#!/usr/bin/perl

#use-stuff
use utf8;
use Gtk2 '-init';
use Gtk2::Helper;
use strict;
use FileHandle;
use Data::Dumper;  # for debugging purposes

#Definering av ting..

my $version = '0.1.9';
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 => 'Date',	type => 'Glib::String',	},
	{ title => 'Status',	type => 'Glib::String',	},
);

#initsialisere ting..
my $store = Gtk2::ListStore->new( map {$_->{type}} @cols );
my $storedone = Gtk2::ListStore->new( map { $_->{type}} @cols );
my $window = Gtk2::Window->new;
my $swindow = Gtk2::ScrolledWindow->new;
my $vbox = Gtk2::VBox->new;
my $buttonbox = Gtk2::HButtonBox->new;
my $exitbutton = Gtk2::Button->new('Lukk');
my $updatebutton = Gtk2::Button->new('Update system');
my $treeview = Gtk2::TreeView->new_with_model($store);
my $treeviewdone = Gtk2::TreeView->new_with_model($storedone);
my $statusbar = Gtk2::Statusbar->new;

#sette parametre..
$window->set_default_size(600,400);
$window->set_title("Emerge Progress $version");
$buttonbox->set_layout_default("end");
$buttonbox->set_spacing_default(12);
$treeview->set_headers_visible(0);
$treeviewdone->set_headers_visible(0);
$exitbutton->signal_connect(clicked => sub { Gtk2->main_quit; });
$updatebutton->signal_connect(clicked => sub { &updatesystem; });
$window->signal_connect(destroy => sub { Gtk2->main_quit; });
$statusbar->set_has_resize_grip('0');
$swindow->set_policy (qw/automatic automatic/);

#vis ting..
$buttonbox->pack_start($updatebutton,0,0,0);
$buttonbox->pack_start($exitbutton,0,0,0);
$swindow->add($vbox);
$window->add($swindow);
$window->show_all();
#Start programmet..
&sett_opp;
Gtk2->main;

sub sett_opp
{
	my $label_ongoing = Gtk2::Label->new("Ongoing Emerges");
	my $label_done = Gtk2::Label->new("Done Emerges");
	$label_ongoing->set_justify('left');
	$label_done->set_justify('left');
	$vbox->pack_start($label_ongoing,0,0,0);
	$vbox->pack_start($treeview,1,1,0);
	$vbox->pack_start($label_done,0,0,0);
	$vbox->pack_start($treeviewdone,1,1,0);
	my $hbox = Gtk2::HBox->new;
	$hbox->pack_start($statusbar,1,1,0);
	$hbox->pack_start($buttonbox,0,0,0);
	$vbox->pack_start($hbox,0,0,0);
	$window->show_all;
	&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);

		$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|^);
	}
	$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 $tid = sprintf("%d",$time);
	$tid = gmtime($tid);

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

	foreach(@data)
	{
	
		if((split / /,$status)[0] eq "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 $i = 0;
		my $idone = 0;
		my $i2 = 0;
		while($i < scalar(@package_list))
		{
			$status = &status_package($package_list[$i + 2]);
			if((split / /,$status)[0] eq 'completed')
			{
				my $pathdone = Gtk2::TreePath->new_from_string($idone);
				my $iterdone = $storedone->get_iter($pathdone);
				$storedone->set($iterdone, 2, $status);
				$idone++;
			}
			else
			{
				my $path = Gtk2::TreePath->new_from_string($i2);
				my $iter = $store->get_iter($path);
				$store->set($iter, 2, $status);
				$i2++;
			}
			$i++;
			$i++;
			$i++;
		}
		return 1;
	}
	else
	{
		@package_list = ();
		$store->clear;
		$storedone->clear;
		&parselog("emerge");
	}
}

sub status_package
{
	my $test = `tail -n100 $logfile | grep "$_[0]"| tail -n1`;
	my $isdone = (split /:::/, $test)[1];
	if(defined($isdone))
	{
		if((split / /, $isdone)[1] eq "completed")
		{
			my $whendone = (split /:::/, $test)[0];
			$whendone = (split /:/, $whendone)[0];
			return("completed at ".gmtime($whendone));
		}
	}
	else
	{
		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);	
		}
	}
}

sub prosent
{
	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);
	}
	unless($progress eq "0" || $total eq "0")
	{	
		my $prosent = ($progress / $total * 100);
		$prosent = sprintf("%.2f", $prosent);
		return("$prosent%");
	}
	else
	{
		return("Ukjent status..");
	}
}

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;
}
