package mod_sys;

#
# $Id$
#

use strict;

use GD;
use USBLCD;



### Globals
###

use constant M_TITLE		=> "System Info";

use constant CHART_WIDTH	=> 61;
use constant CHART_HEIGHT	=> 32;
use constant CHART_X_STEP	=> 20;

my %M_INFO = (
    'graph'	=> 1,
    'alarm'	=> undef,
    'event'	=> undef,
);

my $M_SCREEN_WIDTH;
my $M_SCREEN_HEIGHT;

my $M_FOCUS;

my @M_CHART_DATA;
my $M_CHART_XI;

my $M_VALUE_CPU;
my $M_VALUE_MEM;

my $l_user;
my $l_nice;
my $l_sys;
my $l_idle;



### Module subs
###

# get CPU usage info
sub get_cpu_usage() {
    open FILE, "</proc/stat" || die "Can't open /proc/stat\n";
    while(<FILE>) {
	chomp;
	if(/cpu*\s+(.*)/) {
	    my @field = split /\s/, $1;

	    my $c_user = $l_user;
	    my $c_nice = $l_nice;
	    my $c_sys = $l_sys;
	    my $c_idle = $l_idle;

	    $l_user = $field[0];
	    $l_nice = $field[1];
	    $l_sys = $field[2];
	    $l_idle = $field[3];

	    return undef unless(defined $l_user and defined $l_nice and defined $l_sys and defined $l_idle);
	    return undef unless(defined $c_user and defined $c_nice and defined $c_sys and defined $c_idle);

	    $c_user = $l_user - $c_user;
	    $c_nice = $l_nice - $c_nice;
	    $c_sys = $l_sys - $c_sys;
	    $c_idle = $l_idle - $c_idle;
	    my $total = $c_user + $c_nice + $c_sys + $c_idle;
	    return undef unless $total;

	    return {
		'user' => sprintf("%.0f", $c_user / $total * 100),
		'nice' => sprintf("%.0f", $c_nice / $total * 100),
		'sys' => sprintf("%.0f", $c_sys / $total * 100),
		'idle' => sprintf("%.0f", $c_idle / $total * 100),
		'usage' => sprintf("%.0f", (1 - $c_idle / $total) * 100),
	    }
	}
    }
    close FILE;
}


# get memory usage info
sub get_memory_usage() {
    my $total = undef;
    my $free = undef;

    open FILE, "</proc/meminfo" || die "Can't open /proc/meminfo\n";
    while(<FILE>) {
	if(/MemTotal:\s*(\d+)/) {
	    $total = $1;
	}
	elsif(/MemFree:\s*(\d+)/) {
	    $free = $1;
	}

	last if defined $total and  defined $free;
    }
    close FILE;

    my $usage = sprintf("%.2f", (($total - $free) / $total * 100)) if
	$total and  defined $free;

    return { 'total' => $total, 'free' => $free, 'usage' => $usage };
}


# draw module header
sub draw_header($$) {
    my $w = shift;
    my $h = shift;

    my $im =  new GD::Image($w, $h);
    my $white = $im->colorAllocate(255, 255, 255);
    my $black = $im->colorAllocate(0, 0, 0);

     my $x = ($w - (gdTinyFont->width * length(&M_TITLE))) / 2;

    if ($M_FOCUS) {
        $im->filledRectangle(0, 0, $im->width, $im->height, $black);
	$im->string(gdTinyFont, $x, 0, &M_TITLE, $white);
    } else {
	$im->string(gdTinyFont, $x, 0, &M_TITLE, $black);
    }

    return $im;
}


# draw CPU and memory usage
sub cpu_mem_info($$;$$) {
    my $w = shift;
    my $h = shift;
    my $value_cpu = shift;
    my $value_mem = shift;

    my $im =  new GD::Image($w, $h);
    my $white = $im->colorAllocate(255, 255, 255);
    my $black = $im->colorAllocate(0, 0, 0);

    $im->string(gdTinyFont, 2, 4, "CPU: ".(defined $value_cpu ? $value_cpu."%" : "-"), $black);
    $im->string(gdTinyFont, 2, 12, "Mem: ".(defined $value_mem ? $value_mem."%" : "-"), $black);

    return $im;
}


sub draw_screen($) {
    my $usblcd = shift;

    # FixMe: get size from modes
    my $im =  new GD::Image($M_SCREEN_WIDTH, $M_SCREEN_HEIGHT);
    my $white = $im->colorAllocate(255, 255, 255);
    my $black = $im->colorAllocate(0, 0, 0);

    my $im_header = draw_header($im->width - &CHART_WIDTH, 8);
    my $im_text = cpu_mem_info($im->width - &CHART_WIDTH, 24,
	$M_VALUE_CPU, $M_VALUE_MEM);
    my $im_chart = main::chart(&CHART_WIDTH, &CHART_HEIGHT,
	\@M_CHART_DATA, $M_CHART_XI, &CHART_X_STEP, 100);

    $im->copy($im_header, 0, 0, 0, 0, $im_header->width, $im_header->height);
    $im->copy($im_text, 0, 8, 0, 0, $im_text->width, $im_text->height);
    $im->copy($im_chart, $M_SCREEN_WIDTH - &CHART_WIDTH, 0, 0, 0, &CHART_WIDTH, &CHART_HEIGHT);

    $usblcd->bitbltgd(0, 0, $im);
}



### Module interface
###

sub init(%) {
    my %init_params = @_;

    $M_SCREEN_WIDTH = $init_params{'width'};
    $M_SCREEN_HEIGHT = $init_params{'height'};

    @M_CHART_DATA = ();

    return %M_INFO;
}


sub enter($) {
    my $usblcd = shift;

    $M_FOCUS = undef;
    $M_CHART_XI = 0;
    $M_VALUE_CPU = undef;
    $M_VALUE_MEM = undef;

    draw_screen($usblcd);
}


sub leave($) {
    my $usblcd = shift;

    @M_CHART_DATA = ();
}


sub focus($) {
    my $usblcd = shift;

    #$M_FOCUS = 1;
    #draw_screen($usblcd);
    #return &main::M_FOCUS_ACCEPT;
    return &main::M_FOCUS_REJECT;
}


sub event($$) {
    my $usblcd = shift;
    my $event_ref = shift;

    if ($event_ref->{'type'} == USBLCD_POLLEVENT_KEYDOWN) {
	if ($event_ref->{'value'} == USBLCD_KEY_CANCEL) {
	    $M_FOCUS = undef;
	    draw_screen($usblcd);
	    return &main::M_EVENT_UNFOCUS;
	}
    }

    return &main::M_EVENT_DISCARD;
}


sub update($) {
    my $usblcd = shift;

    my $cpuinfo_ref = get_cpu_usage();
    my $meminfo_ref = get_memory_usage();

    $M_VALUE_CPU = defined $cpuinfo_ref ? $cpuinfo_ref->{'usage'} : undef;
    $M_VALUE_MEM = defined $meminfo_ref ? $meminfo_ref->{'usage'} : undef;

    main::chart_add(defined $cpuinfo_ref ? $cpuinfo_ref->{'usage'} : undef,
        \@M_CHART_DATA, &CHART_WIDTH - 2);
    $M_CHART_XI = ($M_CHART_XI + 1) % &CHART_X_STEP;

    draw_screen($usblcd);

}


1;
