package mod_stor;

#
# $Id$
#

use strict;

use GD;
use USBLCD;



### Globals
###

use constant M_TITLE		=> "Storage";

use constant UNIT_TB		=> 1024 * 1024 * 1024;
use constant UNIT_GB		=> 1024 * 1024;
use constant UNIT_MB		=> 1024;

use constant PART_WIDTH		=> 30;
use constant PART_HEIGHT	=> 7;


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

my $M_SCREEN_WIDTH;
my $M_SCREEN_HEIGHT;
my %M_CONFIG;

my $M_FOCUS;

my $M_VOLUME_INDEX;

my @M_STOR_LIST;
my @M_STOR_STAT;
my %M_STOR_INFO;



### Module subs
###

# convert bytes to human readable
sub get_unit($) {
    my $v = shift;

    if($v >= &UNIT_TB) {
        return ($v / &UNIT_TB, "T");
    }
    elsif($v >= UNIT_GB) {
        return ($v / &UNIT_GB, "G");
    }
    elsif($v >= &UNIT_MB) {
        return ($v / UNIT_MB, "M");
    }
    else {
        return ($v, "");
    }
}


# get volume values
sub get_disk_stat($)
{
    my $dev = shift;

    my $df_result = `df -k $dev 2>/dev/null`;
    my ($total, $used) = ($df_result =~ /$dev\s+(\d+)\s+(\d+)/);
    if (not defined $total) {
	($total, $used) = ($df_result =~ /\s+(\d+)\s+(\d+)\s+\d+\s+\d+%\s+$dev/);
	if (not defined $total) {
	    return ( 'present' => 0 );
	}
    }

    my $hddtemp_result = `/usr/sbin/hddtemp -n $dev 2>/dev/null`;
    my ($temp) = ($hddtemp_result =~ /(.*)$/);
    $temp = undef if not $temp;

    return ( 'present' => 1, 'total' => $total, 'used' => $used, 'temp' => $temp );
}


# update statistics of all volumes
sub update_stat() {
    @M_STOR_STAT = ();

    foreach my $vol (@M_STOR_LIST) {
	my %stat = get_disk_stat($vol);
	if($stat{'present'} == 1) {
	    push @M_STOR_STAT, {
		'title'		=> $M_STOR_INFO{$vol}->{'title'},
		'total'		=> $stat{'total'},
		'used'		=> $stat{'used'},
		'temp'		=> $stat{'temp'},
	    };
	}
    }
}


# 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 single volume info
sub draw_volume_info($$$) {
    my $w = shift;
    my $h = shift;
    my $stat_ref = shift;

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

    my($value, $unit) = get_unit($stat_ref->{'used'});
    my $used_str = sprintf("%.0f%s", $value, $unit);
    ($value, $unit) = get_unit($stat_ref->{'total'});
    my $total_str = sprintf("%.0f%s", $value, $unit);
    my $size_str = sprintf("%s/%s", $used_str, $total_str);
    my $size_width = gdTinyFont->width * length($size_str);

    my $temp_str = $stat_ref->{'temp'} ? sprintf("%3sC", $stat_ref->{'temp'}) : "  - ";
    my $temp_width = gdTinyFont->width * length($temp_str);

    my $part = $stat_ref->{'used'} / $stat_ref->{'total'};
    my $part_str = sprintf("%d%%", int($part * 100));
    my $part_x = (&PART_WIDTH - (gdTinyFont->width * length($part_str))) / 2;
    my $part_width = int(&PART_WIDTH * (1.0 - $part));

    my $pw_im = new GD::Image(&PART_WIDTH, &PART_HEIGHT);
    my $pw_white = $pw_im->colorAllocate(255, 255, 255);
    my $pw_black = $pw_im->colorAllocate(0, 0, 0);
    $pw_im->rectangle(0, 0, &PART_WIDTH - 1, &PART_HEIGHT-1, $black);
    $pw_im->string(gdTinyFont, $part_x, 0, $part_str, $black);

    my $pb_im = new GD::Image(&PART_WIDTH, &PART_HEIGHT);
    my $pb_white = $pb_im->colorAllocate(255, 255, 255);
    my $pb_black = $pb_im->colorAllocate(0, 0, 0);
    $pb_im->filledRectangle(0, 0, &PART_WIDTH - 1, &PART_HEIGHT-1, $black);
    $pb_im->string(gdTinyFont, $part_x, 0, $part_str, $white);

    $im->string(gdTinyFont, 0, 0, $stat_ref->{'title'}, $black);
    $im->string(gdTinyFont, $im->width - $temp_width - &PART_WIDTH - $size_width, 0, $size_str, $black);
    $im->copy($pw_im, $im->width - $temp_width - &PART_WIDTH, 0, 0, 0, $part_width, $pw_im->height);
    $im->copy($pb_im, $im->width - $temp_width - &PART_WIDTH + $part_width, 0, $part_width, 0, $pb_im->width - $part_width, $pb_im->height);
    $im->string(gdTinyFont, $im->width - $temp_width, 0, $temp_str, $black);

    return $im;
}


# draw storage statistics
sub draw_stat($$) {
    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 $select_width = $im->width;
    my $window_size = $h / gdTinyFont->height;
    my $logical_size = scalar @M_STOR_STAT - $window_size;
    if ($M_VOLUME_INDEX > $logical_size) {
	$M_VOLUME_INDEX = $logical_size;
    }
    if ($window_size < scalar @M_STOR_STAT) {
	my $physical_size = $im->height - &main::SELECT_LIST_SCROLL_SIZE;
	my $y = ($logical_size > $M_VOLUME_INDEX) ? $physical_size * $M_VOLUME_INDEX / $logical_size : $physical_size;
	$im->line($im->width - &main::SELECT_LIST_SCROLL_SIZE / 2, 0,
	    $im->width - &main::SELECT_LIST_SCROLL_SIZE / 2, $im->height, $black);
	$im->filledEllipse($im->width - &main::SELECT_LIST_SCROLL_SIZE / 2, $y + &main::SELECT_LIST_SCROLL_SIZE / 2,
	    &main::SELECT_LIST_SCROLL_SIZE - 1, &main::SELECT_LIST_SCROLL_SIZE - 1, $black);
	$select_width -= &main::SELECT_LIST_SCROLL_SIZE;
    }
    else {
	$M_VOLUME_INDEX = 0;
    }

    my $y = 0;
    for (my $i = $M_VOLUME_INDEX; $i < scalar @M_STOR_STAT; $i++) {
	my $im_volume_info = draw_volume_info($select_width, 8, $M_STOR_STAT[$i]);
	$im->copy($im_volume_info, 0, $y, 0, 0, $im_volume_info->width, $im_volume_info->height);
	$y += gdTinyFont->height;
	last if $y >= $h;
    }

    return $im;
}


# update screen
sub draw_screen($) {
    my $usblcd = shift;

    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_title = draw_header($im->width, 8);
    $im->copy($im_title, 0, 0, 0, 0, $im_title->width, $im_title->height);

    my $im_stat = draw_stat($im->width, $im->height - 8);
    $im->copy($im_stat, 0, 8, 0, 0, $im_stat->width, $im_stat->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_CONFIG = %init_params;

    @M_STOR_LIST = map { $_->{'name'} } @{$M_CONFIG{'volume'}};
    foreach my $vol_ref (@{$M_CONFIG{'volume'}}) {
	my $vol = $vol_ref->{'name'};
	my ($vol_name) = ($vol =~ /([^\/]*)$/);
	$M_STOR_INFO{$vol} = {
	    'title'	=> $vol_ref->{'title'} ? $vol_ref->{'title'} : $vol_name
	};
    }

    $M_VOLUME_INDEX = 0;

    return %M_INFO;
}


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

    $M_FOCUS = 1;

    draw_screen($usblcd);

    return &main::M_FOCUS_ACCEPT;
}


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;
	}
	elsif ($event_ref->{'value'} == USBLCD_KEY_UP) {
	    if ($M_VOLUME_INDEX > 0) {
		$M_VOLUME_INDEX -= 1;
	    }
	    draw_screen($usblcd);
	    return &main::M_EVENT_PROCESS;
	}
	elsif ($event_ref->{'value'} == USBLCD_KEY_DOWN) {
	    if ($M_VOLUME_INDEX < (scalar @M_STOR_STAT - 1)) {
		$M_VOLUME_INDEX += 1;
	    }
	    draw_screen($usblcd);
	    return &main::M_EVENT_PROCESS;
	}
    }

    return &main::M_EVENT_DISCARD;
}


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

    $M_FOCUS = undef;

    update_stat();
    draw_screen($usblcd);
}


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

    @M_STOR_STAT = ();
}


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

    update_stat();
    draw_screen($usblcd);
}


1;
