#!/usr/bin/perl

# Monitor

# Copyright (C) 1999 MandrakeSoft (damien@mandrakesoft.com)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

use Gtk;
use lib qw(/usr/lib/libDrakX);
use interactive;
use standalone;
use my_gtk qw(:helpers :wrappers);
use Data::Dumper;
use common qw(:common :file :functional :system);
use strict;
use netconnect;

my $default_intf;
init Gtk;
$::isEmbedded = ($::XID, $::CCPID) = "@ARGV" =~ /--embedded (\w+) (\w+)/;
($default_intf) = "@ARGV" =~ /--defaultintf (\w+)/;
my $window1 = $::isEmbedded ? new Gtk::Plug ($::XID) : new Gtk::Window -toplevel;
$window1->signal_connect ( delete_event => sub { Gtk->exit(0); });
$window1->set_position(1);
$window1->set_title(_("Network monitoring"));
$window1->set_policy(0, 0, 0);
$window1->set_border_width(5);
#$::isEmbedded or $window1->set_usize(500, 400);

my @anim;
($anim[$_]->[0], $anim[$_]->[1]) = gtkcreate_png("/usr/share/icons/anim_" . ($_ + 1) . ".png") foreach (0..9);
my $isconnected=0;
my @interfaces;
my $monitor = {};
gtkadd($window1,
       gtkpack_(new Gtk::VBox(0,5),
		0, _("Network Monitoring"),
		1, gtkpack_(new Gtk::HBox(0,5),
			    1, my $notebook = new Gtk::Notebook,
			    0, gtkpack_(new Gtk::VBox(0,5),
					1, gtkadd(gtkset_shadow_type(new Gtk::Frame(_("Statistics")), 'etched_out'),
						  gtkpack__(gtkset_border_width(new Gtk::VBox(0,5),5),
				      gtkpack__(new Gtk::HBox(0,0), _("Sending Speed : "), my $label_st = new Gtk::Label("")),
				      gtkpack__(new Gtk::HBox(0,0), _("Receiving Speed : "), my $label_sr = new Gtk::Label("")),
							   )
						 ),
					0, gtksignal_connect(my $button_connect = new Gtk::Button(), clicked => \&connection),
					0, new Gtk::HSeparator,
					0, gtksignal_connect(new Gtk::Button(_("Close")), clicked => sub { Gtk->exit(0) })
				       )
			   ),
		0, my $statusbar = new Gtk::Statusbar
	       )
      );
my ($pix_c_map, $pix_c_mask) = gtkcreate_png("net_c.png");
my ($pix_d_map, $pix_d_mask) = gtkcreate_png("net_d.png");
$button_connect->add(gtkpack__(new Gtk::VBox(0,3),
				   my $pix_c = new Gtk::Pixmap($pix_d_map, $pix_d_mask),
				   my $label_c = new Gtk::Label(_("Connect to internet"))
				  ));
$statusbar->push(1, "Not connected");
$window1->show_all();
$window1->set_policy (1, 1, 1);
update();
my ($labelr, $labelt);
my $time_tag = Gtk->timeout_add(1000, \&rescan);
my $time_tag2 = Gtk->timeout_add(5000, \&update);
rescan();
Gtk->main;
Gtk->exit(0);

sub connection {
    my $dialog = new Gtk::Dialog();
    $dialog->set_position(1);
    $dialog->vbox->set_border_width(10);
    my $darea1= new Gtk::DrawingArea();
    $darea1->size(350,12);
    $darea1->set_usize(350,12);
    gtkpack_($dialog->vbox,
	     0, $isconnected ? _("Deconnecting from internet ...") : _("Connecting to internet ..."),
	     1, my $frame = gtkadd(gtkset_shadow_type(new Gtk::Frame(""), 'etched_out'),
						  $darea1)
	    );
    my $bbox_dialog = new Gtk::HButtonBox;
    $dialog->action_area->add($bbox_dialog);
    $bbox_dialog->set_layout(-spread);
    my $button_ok = gtksignal_connect(new Gtk::Button (_("OK")), clicked => sub {
					  $dialog->set_modal(0);
					  $dialog->destroy;
					  update();
				      });
    $button_ok->set_sensitive(0);
    $bbox_dialog->add($button_ok );
    $dialog->show_all;
    $dialog->set_modal(1);
    $darea1->realize();
    my $anim_nb=0;
    my $tag = Gtk->timeout_add(100, sub {
				   $darea1->window->draw_pixmap
				     ($darea1->style->white_gc,
				      $anim[$anim_nb]->[0], 0, 0,
				      ($darea1->allocation->[2]-340)/2, ($darea1->allocation->[3]-15)/2,
				      350, 13);
				   $anim_nb++;
				   $anim_nb > 9 and $anim_nb=0;
				   1;
			       });
    my $netc = {};
    my $tag2 = Gtk->timeout_add(7000, sub {
				    Gtk->timeout_remove($tag);
				    $frame->destroy;
				    gtkpack_($dialog->vbox,
					     1, $isconnected ? ( netconnect::connected('', $netc) ?
								 _("Deconnection from internet failed.") :
								 _("Deconnection from internet complete.")) :
					     ( netconnect::connected('', $netc) ?
					       _("Connection complete.") :
					       _("Connection failed.\nVerify your configuration in the Mandrake Control Center."))
					    );
				    $dialog->vbox->show_all;
				    $button_ok->set_sensitive(1);
				    0;
				});
    $isconnected ? netconnect::disconnect_backend('') : netconnect::connect_backend('');
}

sub rescan {
    get_val();
    foreach(@interfaces) {
	my $intf = $_;
	my $recv = $monitor->{$intf}{val}->[0];
	my $transmit = $monitor->{$intf}{val}->[8];
	my $refr = $monitor->{$intf}{referencer};
	my $reft = $monitor->{$intf}{referencet};
	$monitor->{sr} += $recv - $refr;
	$monitor->{st} += $transmit - $reft;
	push(@{$monitor->{$intf}{stack_r}}, $recv - $refr);
	shift @{$monitor->{$intf}{stack_r}} if @{$monitor->{$intf}{stack_r}} > 250;
	$labelr->set(formatXiB($recv - $monitor->{$intf}{initialr}));
	$monitor->{$intf}{referencer} = $recv;
	push(@{$monitor->{$intf}{stack_t}}, $transmit - $reft);
	shift @{$monitor->{$intf}{stack_t}} if @{$monitor->{$intf}{stack_t}} > 250;
	$monitor->{$intf}{referencet} = $transmit;
	$labelt->set(formatXiB($transmit - $monitor->{$intf}{initialt}));
	draw_monitor($monitor->{$intf});
    }
    $label_sr->set(formatXiB($monitor->{sr}) . "/s");
    $label_st->set(formatXiB($monitor->{st}) . "/s");
    $monitor->{$_} = 0 foreach ('sr', 'st');
    1;
}

sub get_val {
    my @ret;
    my $a = cat_("/proc/net/dev");
    $a =~ s/^.*?\n.*?\n//;
    $a =~ s/^\s*lo:.*?\n//;
    my @line = split(/\n/, $a);
    foreach(@line) {
	s/\s*(\w*)://;
	my $intf=$1;
	push (@ret,$intf);
	$monitor->{$intf}{val} = [split()];
	$monitor->{$intf}{intf} = $intf;
    }
    @ret;
}

sub update {
    my @intfs = get_val();
    foreach(@intfs) {
	my $intf = $_;
	if(!member($intf,@interfaces)) {
	    push (@interfaces, $intf);
	    $default_intf = $intf;
	    $monitor->{$intf}{initialr} = $monitor->{$intf}{val}->[0];
	    $monitor->{$intf}{initialt} = $monitor->{$intf}{val}->[8];
	    $notebook->append_page(gtkshow(my $page = gtkpack_(new Gtk::VBox(0,0),
					       0, gtkpack__(gtkset_border_width(new Gtk::HBox(0,0), 5),
							    gtksize(my $darea = $monitor->{$intf}{darea} = new Gtk::DrawingArea(),300, 150)),
					       0, gtkpack__(gtkset_border_width(new Gtk::HBox(0,0), 5),
							    _("sent : "), $labelt = new Gtk::Label("0")),
					       0, gtkpack__(gtkset_border_width(new Gtk::HBox(0,0), 5),
							    _("received : "), $labelr = new Gtk::Label(_("0"))),
					   )),
				   new Gtk::Label($intf));
	    $notebook->set_page($notebook->page_num($page));
	    $monitor->{$intf}{page}=($notebook->page_num($page));
	    $monitor->{$intf}{pixmap_db} = new Gtk::Gdk::Pixmap($darea->window, 300, 150);
	    $monitor->{$intf}{referencer} = $monitor->{$intf}{val}->[0];
	    $monitor->{$intf}{referencet} = $monitor->{$intf}{val}->[8];
	    $monitor->{$intf}{pixmap_db}->draw_rectangle ($monitor->{$intf}{darea}->style->black_gc, 1, 0, 0, 300, 150);
	    $darea->signal_connect( expose_event => sub {
					$darea->window->draw_pixmap ($darea->style->bg_gc('normal'),
								     $monitor->{$intf}{pixmap_db}, 0, 0, 0, 0, 300, 150);
				    });
	}
    }
    foreach(@interfaces) {
	my $intf = $_;
	if(!member($intf,@intfs)) {
	    $notebook->remove_page($monitor->{$intf}{page});
	    @interfaces = map { $_ if($_ ne $intf)} @interfaces;
	}
    }
    my $netc={};
    if(netconnect::connected('', $netc) == !$isconnected) {
	$isconnected = $isconnected ? 0 : 1;
	$label_c->set($isconnected ? _("Disconnect") : _("Connect"));
	$isconnected ? $pix_c->set($pix_c_map, $pix_c_mask) : $pix_c->set($pix_d_map, $pix_d_mask);
    }
    1;
}

sub draw_monitor {
    my ($o) = @_;
    $o->{pixmap_db}->draw_rectangle ($o->{darea}->style->black_gc, 1, 0, 0, 300, 150);
#    my @c = map { $step+=2; ($step, $_); } @{$o->{stack_r}};
#    print "\n##\n" . Data::Dumper->Dump([@c],['$c']) . "\n##\n";
#    $o->{pixmap_db}->draw_segments($o->{darea}->style->white_gc, @c);
    my $maxr = 0;
    foreach (@{$o->{stack_r}}) {
	$maxr = $_ if $_>$maxr;
    }
    my $maxt = 0;
    foreach (@{$o->{stack_t}}) {
	$maxt = $_ if $_>$maxt;
    }
    my $ech = $maxr + $maxt;
    $ech == 0 and $ech = 1;
    my $colorr = my_gtk::gtkcolor(50400, 655, 20000);
    my $gcr = new Gtk::Gdk::GC($o->{darea}->window);
    $gcr->set_foreground($colorr);
    my $colort = my_gtk::gtkcolor(55400, 65400, 655);
    my $gct = new Gtk::Gdk::GC($o->{darea}->window);
    $gct->set_foreground($colort);
    my $step=50;
    foreach (@{$o->{stack_t}}) {
	$o->{pixmap_db}->draw_rectangle($gct, 1, $step, 0, 1, $_*150/$ech);
	$step++;
    }
    $step=50;
    foreach (@{$o->{stack_r}}) {
	$o->{pixmap_db}->draw_rectangle($gcr, 1, $step, 151-$_*150/$ech, 1, $_*150/$ech);
	$step++;
    }
    my $gcl = new Gtk::Gdk::GC($o->{darea}->window);
    $gcl->set_foreground($o->{darea}->window->get_colormap->color_white());
    $gcl->set_line_attributes (1, 'on-off-dash', 'not-last', 'round');
    my $style= new Gtk::Style;
    $style->font(Gtk::Gdk::Font->fontset_load("-adobe-times-medium-r-normal-*-12-*-75-75-p-*-iso8859-*,*-r-*"));
    for (my $i = 30;$i<=120;$i+=30) {
	$o->{pixmap_db}->draw_line($gcl, 50, $i, 300, $i);
	my ($gc2, $text);
	my $dif1 = abs(150-@{$o->{stack_r}}[@{$o->{stack_r}}-1]*150/$ech - $i);
	my $dif2 = abs(@{$o->{stack_t}}[@{$o->{stack_t}}-1]*150/$ech - $i);
	if ($dif1 < $dif2) {
	    $text = formatXiB((150-$i)*$ech/150);
	    $gc2=$gcr;
	} else {
	    $text = formatXiB($i*$ech/150);
	    $gc2=$gct;
	}
#	    $text = formatXiB((150-$i)*$ech/150);
#	    $gc2 = $o->{darea}->style->white_gc;

	my $w = $style->font->string_width($text);
	$o->{pixmap_db}->draw_string($style->font, $gc2, 45-$w, $i+5, ($text) );
    }
    $o->{darea}->draw(undef);
}