#!/usr/bin/perl

#use-stuff
use utf8;
use Gtk2 '-init';
use Gtk2::Helper;
use Gtk2::GladeXML;
use locale;
use POSIX qw(locale_h);
setlocale(LC_NUMERIC, "C");
use strict;
use FileHandle;
use Data::Dumper;  # for debugging purposes
my $glade = Gtk2::GladeXML -> new("/home/users/t/theemperor/Projects/project1/project1.glade");

#Definering av ting..

my $version = '0.1.11';
my $logfile = "/var/log/emerge.log";
my @package_list;
my $lastline;
my $status;
my $tag;
my $updatetag;
my $noclickupdate = 0;
my $progresstring = '.';
my @cols = (
	{ title => 'Name',	type => 'Glib::String',	},
	{ title => 'Started',	type => 'Glib::String',	},
	{ title => 'Status',	type => 'Glib::String',	},
);

my @cols_done = (
	{ title => 'Name',	type => 'Glib::String',	},
	{ title => 'Started',	type => 'Glib::String',	},
	{ title => 'Completed in',	type => 'Glib::String',	},
);

#initsialisere ting..
my $store = Gtk2::ListStore->new( map {$_->{type}} @cols );
my $storedone = Gtk2::ListStore->new( map { $_->{type}} @cols_done );
my $window = $glade -> get_widget("window1");
my $swindow = $glade -> get_widget("scrolledwindow1");
my $swindow2 = $glade -> get_widget("scrolledwindow2");
my $vbox = $glade -> get_widget("vbox1");
my $buttonbox = $glade -> get_widget("hbuttonbox1");
my $exitbutton = $glade -> get_widget("button2");
my $updatebutton = $glade -> get_widget("button1");
my $treeview = $glade -> get_widget("treeview1");
$treeview -> set_model($store);
my $treeviewdone = $glade -> get_widget("treeview2");
$treeviewdone -> set_model($storedone);
my $statusbar = $glade -> get_widget("statusbar1");

#sette parametre..
$exitbutton->signal_connect(clicked => sub { Gtk2->main_quit; });
$updatebutton->signal_connect(clicked => sub { &updatesystem; });
$window->signal_connect(destroy => sub { Gtk2->main_quit; });

#Start programmet..
&sett_opp;
Gtk2->main;

sub sett_opp
{
	&sett_opp_kolonner;
	&parselog("emerge");
	my $timer = Glib::Timeout->add(10000, \&test);
}

sub sett_opp_kolonner
{
	my $renderer;
	my $rendererdone;
	my $i = 0;
	foreach (@cols)
	{
		$renderer = Gtk2::CellRendererText->new;
		$renderer->signal_connect (edited => sub {
			my ($cell, $text_path, $new_text, $store) = @_;
			my $path = Gtk2::TreePath->new_from_string ($text_path);
			my $iter = $store->get_iter ($path);
			$store->set ($iter, 2, $text_path);
		}, $store);
		my $column = Gtk2::TreeViewColumn->new_with_attributes(
			$_->{title}, $renderer, text => $i );
		$treeview->append_column($column);
		$i++;
	}

	$i = 0;
	foreach(@cols_done)
	{
		$rendererdone = Gtk2::CellRendererText->new;
		$rendererdone->signal_connect (edited => sub {
			my ($celldone, $text_pathdone, $new_textdone, $storedone) = @_;
			my $pathdone = Gtk2::TreePath->new_from_string ($text_pathdone);
			my $iterdone = $storedone->get_iter ($pathdone);
			$storedone->set ($iterdone, 2, $text_pathdone);
		}, $storedone);
		my $columndone = Gtk2::TreeViewColumn->new_with_attributes(
			$_->{title}, $rendererdone, text => $i );
		$treeviewdone->append_column($columndone);

		$i++;
	}
	return 1;
}

sub updatesystem
{
	unless($noclickupdate eq 1)
	{
		my $updatewindow = Gtk2::Window->new;
		my $vbox = Gtk2::VBox->new;
		my $label = Gtk2::Label->new("Sync should only be done once a day.\nIf sync is selected, emerge world will automagically be run.");
		my $buttonbox = Gtk2::HButtonBox->new;
		my $syncbutton = Gtk2::Button->new('Sync');
		my $emergebutton = Gtk2::Button->new('emerge');
		$syncbutton->signal_connect(clicked => sub { 
								$statusbar->push('1','Running emerge --sync, this will take some time.');
								$noclickupdate = 1;
								&sync;
								$updatewindow->destroy;
							});
		$emergebutton->signal_connect(clicked => sub { 
								$statusbar->push('1','Running emerge world, this will take some time.');
								$noclickupdate = 1;
								&emergeworld;
								$updatewindow->destroy;
							});	
		$updatewindow->add($vbox);
		$vbox->pack_start($label,0,0,0);
		$vbox->pack_start($buttonbox,0,0,0);
		$buttonbox->add($syncbutton);
		$buttonbox->add($emergebutton);
		$updatewindow->show_all;
	}
	return 1;
}

sub sync
{
	my $fh = FileHandle->new;
	open($fh, q^emerge --sync|^);
	$updatetag = Gtk2::Helper->add_watch ( $fh->fileno, 'in', sub { update_callback($fh,$updatetag); });
	return 1;
}

sub update_callback
{
	my ( $fh, $updatetag) = @_;
	
	if ( eof($fh))
	{
		Gtk2::Helper->remove_watch ($updatetag) or &error("Kunne ikke gi slipp på Gtk2::Helper.");
		close($fh);
		$statusbar->push('1','Done running emerge --sync, running emerge world..');
		&emergeworld;
		return 1;
	}
	my $line = <$fh>;
	if($progresstring eq '.............') { $progresstring = '.'; }
	$statusbar->push('1','Running emerge sync'."$progresstring");
	$progresstring = "$progresstring".'.';
	return 1;	
}

sub emergeworld
{
	$statusbar->push('1','Running emerge world, this WILL take some time..');
	my $fh = FileHandle->new;
	open($fh, q^emerge -q world|^);
	$updatetag = Gtk2::Helper->add_watch ( $fh->fileno, 'in', sub { emergeworld_callback($fh,$updatetag); });
	return 1;
}

sub emergeworld_callback
{
	my ( $fh, $updatetag) = @_;
	
	if ( eof($fh))
	{
		Gtk2::Helper->remove_watch ($updatetag) or &error("Kunne ikke gi slipp på Gtk2::Helper.");
		close($fh);
		$statusbar->push('1','Done running emerge world.. You should open a terminal, and as root type "etc-update" to update your config files.');
		$noclickupdate = 0;
		return 1;
	}
	my $line = <$fh>;
	if($progresstring eq '.............') { $progresstring = '.'; }
	$statusbar->push('1','Running emerge world'."$progresstring");
	$progresstring = "$progresstring".'.';
	return 1;	
}

sub parselog
{
	my $fh = FileHandle->new;
	$lastline = `tail -n1 $logfile`;
	chomp($lastline) or &error("Kunne ikke lese /var/log/emerge.log,\nEr du i portage-gruppen?");
	if($_[0] eq 'emerge')
	{
#		open($fh, q^tail -n100 "/var/log/emerge.log" | grep ">>> emerge"| sort -k7 -u| tail -n10|^);
		open($fh, q^tail -n100 "/var/log/emerge.log" | grep ">>> emerge" | tail -n10|^);
	}
	$tag = Gtk2::Helper->add_watch ( $fh->fileno, 'in', sub
	{
		watcher_callback( $fh, $tag );
	});
	return 1;
}

sub watcher_callback
{
	my ( $fh, $tag) = @_;
	
	if ( eof($fh))
	{
		Gtk2::Helper->remove_watch ($tag) or &error("Kunne ikke gi slipp på Gtk2::Helper.");
		close($fh);
		return 1;
	}
	
	my $line = <$fh>;
	my $time = (split /:/, $line)[0];
	my $package = (split /\//, $line)[1];
	$package = (split /\ /, $package)[0];
	my $package_group = (split/\//, $line)[0];
	$package_group = (split /\ /, $package_group)[7];
	my $status = &status_package($package);
	my $completed = 0;
	if(defined($status))
	{
		if((split / /,$status)[0] eq 'completed')
		{
			my $tidting = (split / /,$status)[1];
			$status = &gettime($tidting - $time);
			$completed = 1;
		}
	}
	my $tid = sprintf("%d",$time);
	$tid = gmtime($tid);

	my @data=(
			{ Name => "$package", Time => "$tid", Status => "$status" }
	);

	foreach(@data)
	{
		if($completed)
		{
			my $iterdone = $storedone->append;
			$storedone->set($iterdone,
				0, $_->{'Name'},
				1, $_->{'Time'},
				2, $_->{'Status'}
			);
		}
		else
		{
			my $iter = $store->append;
			$store->set($iter,
				0, $_->{'Name'},
				1, $_->{'Time'},
				2, $_->{'Status'}
			);
			push(@package_list, int($time));
			push(@package_list, "$package_group");
			push(@package_list, "$package");
		}
	}
	return 1;
}

sub test
{
	my $testline = `tail -n1 $logfile`;
	chomp($testline);
	if($testline eq $lastline)
	{
		my $testi = 0;
		my $pathi = 0;
		while($testi < scalar(@package_list))
		{
			my $path;
			my $iter;
			$status = &status_package($package_list[$testi + 2]);
			my $eta = &eta($package_list[$testi],$status);
			if($eta) { $status = "$status ETA: $eta"; }
			if(defined($testi))
			{
				my $path = Gtk2::TreePath->new_from_string($pathi);
				if(defined($path))
				{
					my $iter = $store->get_iter($path);
					if(defined($iter))
					{
						$store->set($iter, 2, $status);
					}
				}
			}
			$testi++;
			$testi++;
			$testi++;
			$pathi++;
		}
		return 1;
	}
	else
	{
		@package_list = ();
		$store->clear;
		$storedone->clear;
		&parselog("emerge");
	}
}

sub status_package
{
	return 0 unless($_[0]);
	my $test = `tail -n100 $logfile | grep "$_[0]"| tail -n1`;
#	my $isdone = `tail -n100 $logfile | grep "$_[0]" | grep "completed" | tail -n1`;
	my $isdone = (split /:::/, $test)[1];
	unless(defined($isdone))
#	if($isdone eq '')
	{
		my $antatt_status = (split / /, $test)[6];
		my $alternativ_status = (split / /, $test)[3];
		if($antatt_status eq "Compiling/Merging")
		{
			my $prosent = &prosent($_[0]);
			if($prosent eq "Ukjent status..")
			{
				return($antatt_status);
			}
			else
			{
				return($prosent);
			}
		}
		else
		{
			return($antatt_status);	
		}
	}
	else
	{
		my $whendone = (split /:::/, $test)[0];
		$whendone = (split /:/, $whendone)[0];
		return("completed $whendone");
	}
}

sub eta
{
	my $start_time = $_[0];
	my $p = $_[1];
	my $t = time();
	my $tt;
	if(defined($p))
	{
		$p = (split /%/, $p)[0];
		my $ss = ($t - $start_time); # time since start
		my $per_sec = ($p / $ss); # percent per second
		if($per_sec > 0) { $tt = ((100 - $p) / ($per_sec)); } # estimated time until 100%
		else { return 0; }
		return &gettime($tt);
	}
}

sub prosent
{
	return 0 unless $_[0];
	my $progress;
	my $total = `find /var/tmp/portage/$_[0] -iname "*.c" -or -iname "*.cpp" -or -iname "*.cc" | wc -l`;
	chomp($total);
	unless($total eq "0")
	{
		$progress = `find /var/tmp/portage/$_[0] -iname "*.o" | wc -l`;
		chomp($progress);
	}
	if(defined($progress))
	{
		if(defined($total))
		{
			unless($progress eq "0" || $total eq "0")
			{	
				my $prosent = ($progress / $total * 100);
				$prosent = sprintf("%.2f", $prosent);
				return("$prosent%");
			}
			else
			{
				return("Ukjent status..");
			}
		}
	}
}

sub gettime # gettime(tid i sekunder)
{
        my $gettime = $_[0];
        if($gettime > 0)
        {
		my $returnstring;
                my $days = int($gettime/24/60/60);
                my $hours = int($gettime/60/60)%24;
                my $minutes = int($gettime/60)%60;
                my $seconds = int$gettime%60;
		if($seconds > 0) { $returnstring = "$seconds sec"; }
		if($minutes > 0) { $returnstring = "$minutes min, $seconds sec"; }
		if($hours > 0) { $returnstring = "$hours hours, $minutes min, $seconds sec"; }
		if($days > 0) { $returnstring = "$days days, $hours hours, $minutes min, $seconds sec"; }
                return $returnstring;
        } # if
	else { return 0; }
} # sub time

sub error
{
	my $message = shift;
	my $dialog = Gtk2::Dialog->new ('Feil!!', $window,
								'destroy-with-parent',
								'gtk-ok' => 'none');
	my $label = Gtk2::Label->new ($message);
	$dialog->vbox->add ($label);
	$dialog->set('modal' => 1);
	
	$dialog->signal_connect (response => sub { $_[0]->destroy; Gtk2->main_quit; });
	$dialog->show_all;
}
