#!/usr/bin/perl
#
# vim: ts=4:noet
#
# sbocheck
# script to update the local sbo tree and check for updates
#
# authors: Jacob Pipkin <j@dawnrazor.net>
#          Luke Williams <xocel@iquidus.org>
#          Andreas Guldstrand <andreas.guldstrand@gmail.com>
# license: WTFPL <http://sam.zoy.org/wtfpl/COPYING>

use 5.16.0;
use strict;
use warnings FATAL => 'all';
use SBO::Lib qw/ update_tree get_available_updates script_error open_fh is_local show_version get_local_outdated_versions /;
use Getopt::Long;
use File::Basename;
use List::Util 'max';
use Data::Dumper;

my $self = basename($0);

sub show_usage {
	print <<"EOF";
Usage: $self

Options:
  -h|--help:
    this screen.
  -v|--version:
    version information.

EOF
	return 1;
}

my ($help, $vers);

GetOptions('help|h' => \$help, 'version|v' => \$vers);

if ($help) { show_usage(); exit 0 }
if ($vers) { show_version(); exit 0 }

update_tree();

# retrieve and format list of available updates
sub get_update_list {
	print "Checking for updated SlackBuilds...\n";
	my @updates = @{ get_available_updates() };
	my @outdated = get_local_outdated_versions();
	return() unless @outdated + @updates;

	my %updates;
	for my $update (@updates) {
		$updates{$update->{name}} = {
			installed => $update->{installed},
			available => $update->{update},
			local => is_local($update->{name})
		};
	}
	for my $update (@outdated) {
		my $name = $update->{name};
		$updates{$name}{installed} = $update->{version};
		$updates{$name}{sbo} = $update->{orig};
		$updates{$name}{local} = 1;
	}

# Output should look like this where the < is aligned to the longest sboname 1.0 string (excepting ones that would then wrap):
# sboname 1.0  <  needs updating (1.1 from overrides)
# sboname 1.0  <  needs updating (1.1 from SBo)
# sboname 1.0  <  needs updating (1.1 from overrides, 1.2 from SBo)
# sboname 1.0  <  override outdated (1.1 from SBo)

	my $max = 0;
	foreach my $sbo (keys %updates) {
		my $info = $updates{$sbo};
		my $current = sprintf "%s %s", $sbo, $info->{installed};

		my $available = '';
		if (defined $info->{available} and defined $info->{sbo}) {
			$available = sprintf "needs updating (%s from overrides, %s from SBo)", $info->{available}, $info->{sbo};
		}
		elsif ($info->{available}) {
			$available = sprintf "needs updating (%s from %s)", $info->{available}, $info->{local} ? "overrides" : "SBo";
		}
		else {
			$available = sprintf "override outdated (%s from SBo)", $info->{sbo};
		}
		$info->{name_str} = $current;
		$info->{upd_str} = $available;

		my $str = sprintf "%s  <  %s", $current, $available;
		if (length($str) <= 80) {
			$max = length($current) if length($current) > $max;
		}
	}

	my @listing;
	foreach my $sbo (sort keys %updates) {
		my $info = $updates{$sbo};

		my $str = sprintf "%s  <  %s", $info->{name_str}, $info->{upd_str};
		if (length($str) <= 80) {
			$str = sprintf "%-*s  <  %s", $max, $info->{name_str}, $info->{upd_str};
			my $adjust = 1;
			while (length($str) > 80) {
				$str = sprintf "%-*s  <  %s", $max-$adjust++, $info->{name_str}, $info->{upd_str};
			}
		}
		push @listing, $str;
	}
	return @listing;
}

# print list of updates
sub print_output {
	my @listing = @_;
	if (@listing) {
		print "\n";
		say $_ for @listing;
		print "\n";
		# save a log of available updates
		my $logfile = '/var/log/sbocheck.log';
		unlink $logfile if -f $logfile;
		my ($log_fh, $exit) = open_fh($logfile, '>');
		# non-fatal
		if ($exit) {
			warn $log_fh;
		} else {
			say {$log_fh} $_ for @listing;
			close $log_fh;
			say "A copy of the above result is kept in $logfile\n";
		}
	} else {
		say "\nNo updates available.";
	}
	return 1;
}

my @listing = get_update_list();
print_output(@listing);

exit 0;
