#!/usr/bin/perl -w

use strict;
use CGI;
use CGI::Carp qw(carpout);
use GD::Graph::lines;
use FileHandle;

# Configuration

my $run_dir_base = '/home/swarren/cron_scripts/monitor';

# Globals

my $host;
my %valid_hosts = ();
my %conf = ();
my $run_dir;
my $sensor_log;
my $localhost;

# Subroutines

sub open_config_file
{
    my $fn         = $_[0];
    my $allow_host = $_[1];

    my @fps = ($run_dir_base . '/' . $fn);
    if ($allow_host) {
        push(@fps, $run_dir. '/' . $fn);
    }

    foreach my $fp (@fps) {
        if (!-f $fp) {
            next;
        }
        my $fh = new FileHandle;
        if (!$fh->open($fp)) {
            die "Can't open '${fp}' to read: $!";
        }
        return $fh;
    }

    die "Can't find config file '${fn}'";
}

sub process_cgi_hosts_line
{
    my $line = $_[0];

    if ($line eq 'localhost') {
        $line = $localhost;
    }
    $valid_hosts{$line} = 1;
}

sub process_cgi_vars_line
{
    my $line  = $_[0];

    $line =~ s:#.*$::;
    $line =~ s:^\s+::;
    $line =~ s:\s+$::;
    if ($line eq '') {
        return;
    }

    my @line = split('\s+', $line);
    if ($#line < 8) {
        die "Wrong field count in var line: ${line}\n";
    }

    my ($var_type, $params, $var_name, $low_set, $low_clear, $high_clear, $high_set, $graph_max, @description) = @line;
    my $description = join(' ', @description);

    $conf{$var_name} = {
        'name'   => $description,
        'y_min'  => 0,
        'y_max'  => $graph_max
    };
}

sub parse_config_files
{
    my $fh_cgi_hosts = open_config_file('conf.cgi.hosts.txt', 0);
    while (<$fh_cgi_hosts>) {
        chomp;
        process_cgi_hosts_line($_, '\s+');
    }
    $fh_cgi_hosts->close();

    if (!exists $valid_hosts{$host}) {
        die "Bad host: '${host}'";
    }

    my $fh_cgi_vars = open_config_file('conf.vars.txt', 1);
    while (<$fh_cgi_vars>) {
        chomp;
        process_cgi_vars_line($_, '\s+');
    }
    $fh_cgi_vars->close();
}

# Main Program

my $cgi = new CGI;

print $cgi->header(-type=>'image/png');
#print $cgi->header(-type=>'text/plain');

#carpout(\*STDOUT);

my @cgi_parms = $cgi->param;
my %cgi_parms = map {$_ => 1} @cgi_parms;

if (!exists $cgi_parms{'value'}) {
    die "No value param";
}
if (!exists $cgi_parms{'host'}) {
    die "No host param";
}

my $value = $cgi->param('value');
$host = $cgi->param('host');
$run_dir = $run_dir_base . '/' . $host;
$sensor_log = $run_dir . '/sensor_log.txt';
$localhost = `hostname`;
chomp $localhost;

parse_config_files();

if (!exists $conf{$value}) {
    die "Bad value: '${value}'";
}

my $conf = $conf{$value};
my $name = $conf->{'name'};
my $y_min = $conf->{'y_min'};
my $y_max = $conf->{'y_max'};

my $width = 1024;
my $height = 1024;
my $max_samples = 10080 * 2; # 2 Weeks
if (exists $cgi_parms{'width'}) {
    $width = $cgi->param('width');
    if ($width !~ m:^\d+$:) {
        die "Bad width: '${width}'";
    }
    if ($width > 4096) {
        die "Bad width: '${width}'";
    }
}
if (exists $cgi_parms{'height'}) {
    $height = $cgi->param('height');
    if ($height !~ m:^\d+$:) {
        die "Bad height: '${height}'";
    }
    if ($height > 4096) {
        die "Bad height: '${height}'";
    }
}
if (exists $cgi_parms{'max_samples'}) {
    $max_samples = $cgi->param('max_samples');
    if ($max_samples !~ m:^\d+$:) {
        die "Bad max_samples: '${max_samples}'";
    }
}

my @x_axis = ();
my @samples = ();
my $last_date = '';

open(FH, $sensor_log) || die "Can't open '${sensor_log}' to read: $!";
while (<FH>) {
    #2009_10_11_22_56_01,fan_cpu,4115,ok,temp_sys,24.0,ok,temp_cpu,36.0,ok,temp_sda,34,ok,temp_sdb,36,ok,raid,0,ok,load_1,0.20,ok,load_5,0.13,ok,load_15,0.15,ok,fan_chassis,3245,ok,
    chomp;
    my @fields = split(",", $_);

    my $field = undef;
    for (my $fidx = 1; $fidx <= $#fields - 1; $fidx += 3) {
        if ($fields[$fidx] eq $value) {
            $field = $fields[$fidx + 1];
            $field =~ s/!.*$//;
            if ($field eq '') {
                $field = 0;
            }
            last;
        }
    }
    push @samples, $field;

    my $date = '';
    if ($#fields >= 0) {
        my $date_str = $fields[0];
        if ($date_str =~ m:^\d+_(\d+_\d+)_:) {
            my $this_date = $1;
            if ($this_date ne $last_date) {
                $date = $this_date;
                $last_date = $this_date;
            }
        }
    }

    push @x_axis, $date;
}
close(FH);

if ($#samples >= $max_samples) {
    @samples = @samples[-$max_samples..-1];
    @x_axis = @x_axis[-$max_samples..-1];
}
if ($#samples < ($max_samples - 1)) {
    my $missing_count = ($max_samples - 1) - $#samples;
    @samples = ((undef) x $missing_count, @samples);
    @x_axis  = (('') x $missing_count, @x_axis);
}

my @data = (
    \@x_axis,
    \@samples
);

my $graph = GD::Graph::lines->new($width, $height);

$graph->set(
    'x_label'     => 'Sample',
    'y_label'     => $name,
    'title'       => 'Graph of ' . $name,
    'dclrs'       => ['red'],
    'y_min_value' => $y_min,
    'y_max_value' => $y_max,
) or die $graph->error;

print $graph->plot(\@data)->png;

exit(0);
