#!/usr/bin/perl

use strict;
use warnings;

no warnings ('qw');

use RRDs;

our $rrdpath = '/var/lib/collectd';

our $Canvas	= 'F5F5F5';

# Alpha used to compute these values: 0.25
our $FullRed	= 'FF0000';
our $HalfRed	= 'F8B8B8';
our $FullBlue	= '0000FF';
our $HalfBlue	= 'B8B8F8';
our $FullGreen	= '00E000';
our $HalfGreen	= 'B8F0B8';
our $FullYellow = 'F0F000';
our $HalfYellow = 'F4F4B8';

our $HalfBlueGreen = '8AB4CA';
our $HalfRedBlue   = 'CA8ABA';

our $graphdefs =
{
	load => ['DEF:s_avg={file}:shortterm:AVERAGE',
			'DEF:s_min={file}:shortterm:MIN',
			'DEF:s_max={file}:shortterm:MAX',
			'DEF:m_avg={file}:midterm:AVERAGE',
			'DEF:m_min={file}:midterm:MIN',
			'DEF:m_max={file}:midterm:MAX',
			'DEF:l_avg={file}:longterm:AVERAGE',
			'DEF:l_min={file}:longterm:MIN',
			'DEF:l_max={file}:longterm:MAX',
			'CDEF:m_avg_neg=m_avg,-1,*',
			'CDEF:l_avg_neg=l_avg,-1,*',
			'CDEF:lm_avg_neg=m_avg_neg,l_avg_neg,LT,l_avg_neg,m_avg_neg,IF',
			"AREA:m_avg_neg#$HalfBlue",
			"AREA:l_avg_neg#$HalfRed",
			"AREA:lm_avg_neg#$HalfRedBlue",
			"AREA:s_max#$HalfGreen",
			"AREA:s_min#$Canvas",
			"LINE1:s_avg#$FullGreen: 1m average",
			'GPRINT:s_min:MIN:%4.2lf Min,',
			'GPRINT:s_avg:AVERAGE:%4.2lf Average,',
			'GPRINT:s_max:MAX:%4.2lf Max,',
			'GPRINT:s_avg:LAST:%4.2lf Last\n',
			"LINE1:m_avg_neg#$FullBlue: 5m average",
			'GPRINT:m_min:MIN:%4.2lf Min,',
			'GPRINT:m_avg:AVERAGE:%4.2lf Average,',
			'GPRINT:m_max:MAX:%4.2lf Max,',
			'GPRINT:m_avg:LAST:%4.2lf Last\n',
			"LINE1:l_avg_neg#$FullRed:10m average",
			'GPRINT:l_min:MIN:%4.2lf Min,',
			'GPRINT:l_avg:AVERAGE:%4.2lf Average,',
			'GPRINT:l_max:MAX:%4.2lf Max,',
			'GPRINT:l_avg:LAST:%4.2lf Last'],
	mails => ['DEF:rawgood={file}:good:AVERAGE',
			'DEF:rawspam={file}:spam:AVERAGE',
			'CDEF:good=rawgood,UN,0,rawgood,IF',
			'CDEF:spam=rawspam,UN,0,rawspam,IF',
			'CDEF:negspam=spam,-1,*',
			"AREA:good#$HalfGreen",
			"LINE1:good#$FullGreen:Good mails",
			'GPRINT:good:AVERAGE:%4.1lf Average,',
			'GPRINT:good:MAX:%4.1lf Max,',
			'GPRINT:good:LAST:%4.1lf Last\n',
			"AREA:negspam#$HalfRed",
			"LINE1:negspam#$FullRed:Spam mails",
			'GPRINT:spam:AVERAGE:%4.1lf Average,',
			'GPRINT:spam:MAX:%4.1lf Max,',
			'GPRINT:spam:LAST:%4.1lf Last',
			'HRULE:0#000000'],
	ping => ['DEF:ping_avg={file}:ping:AVERAGE',
			'DEF:ping_min={file}:ping:MIN',
			'DEF:ping_max={file}:ping:MAX',
			"AREA:ping_max#$HalfRed",
			"AREA:ping_avg#$HalfGreen",
			"LINE1:ping_min#$FullGreen",
			"LINE1:ping_max#$FullRed",
			"LINE1:ping_avg#$FullBlue:Ping",
			'GPRINT:ping_min:MIN:%4.1lf ms Min,',
			'GPRINT:ping_avg:AVERAGE:%4.1lf ms Average,',
			'GPRINT:ping_max:MAX:%4.1lf ms Max,',
			'GPRINT:ping_avg:LAST:%4.1lf ms Last'],
	meminfo => ['DEF:used_avg={file}:used:AVERAGE',
			'DEF:used_min={file}:used:MIN',
			'DEF:used_max={file}:used:MAX',
			'DEF:free_avg={file}:free:AVERAGE',
			'DEF:free_min={file}:free:MIN',
			'DEF:free_max={file}:free:MAX',
			'DEF:buff_avg={file}:buffers:AVERAGE',
			'DEF:buff_min={file}:buffers:MIN',
			'DEF:buff_max={file}:buffers:MAX',
			'DEF:cach_avg={file}:cached:AVERAGE',
			'DEF:cach_min={file}:cached:MIN',
			'DEF:cach_max={file}:cached:MAX',
			'CDEF:free_acc=used_avg,buff_avg,cach_avg,free_avg,+,+,+',
			'CDEF:cach_acc=used_avg,buff_avg,cach_avg,+,+',
			'CDEF:buff_acc=used_avg,buff_avg,+',
			'CDEF:used_acc=used_avg',
			"AREA:free_acc#$HalfGreen",
			"AREA:cach_acc#$HalfBlue",
			"AREA:buff_acc#$HalfYellow",
			"AREA:used_acc#$HalfRed",
			"LINE1:free_acc#$FullGreen:Free        ",
			'GPRINT:free_min:MIN:%5.1lf%s Min,',
			'GPRINT:free_avg:AVERAGE:%5.1lf%s Average,',
			'GPRINT:free_max:MAX:%5.1lf%s Max,',
			'GPRINT:free_avg:LAST:%5.1lf%s Last\n',
			"LINE1:cach_acc#$FullBlue:Page cache  ",
			'GPRINT:cach_min:MIN:%5.1lf%s Min,',
			'GPRINT:cach_avg:AVERAGE:%5.1lf%s Average,',
			'GPRINT:cach_max:MAX:%5.1lf%s Max,',
			'GPRINT:cach_avg:LAST:%5.1lf%s Last\n',
			"LINE1:buff_acc#$FullYellow:Buffer cache",
			'GPRINT:buff_min:MIN:%5.1lf%s Min,',
			'GPRINT:buff_avg:AVERAGE:%5.1lf%s Average,',
			'GPRINT:buff_max:MAX:%5.1lf%s Max,',
			'GPRINT:buff_avg:LAST:%5.1lf%s Last\n',
			"LINE1:used_acc#$FullRed:Used        ",
			'GPRINT:used_min:MIN:%5.1lf%s Min,',
			'GPRINT:used_avg:AVERAGE:%5.1lf%s Average,',
			'GPRINT:used_max:MAX:%5.1lf%s Max,',
			'GPRINT:used_avg:LAST:%5.1lf%s Last'],
	cpu0 => ['DEF:user_avg={file}:user:AVERAGE',
			'DEF:user_min={file}:user:MIN',
			'DEF:user_max={file}:user:MAX',
			'DEF:nice_avg={file}:nice:AVERAGE',
			'DEF:nice_min={file}:nice:MIN',
			'DEF:nice_max={file}:nice:MAX',
			'DEF:syst_avg={file}:syst:AVERAGE',
			'DEF:syst_min={file}:syst:MIN',
			'DEF:syst_max={file}:syst:MAX',
			'DEF:idle_avg={file}:idle:AVERAGE',
			'DEF:idle_min={file}:idle:MIN',
			'DEF:idle_max={file}:idle:MAX',
			'CDEF:nice_acc=syst_avg,user_avg,nice_avg,+,+',
			'CDEF:user_acc=syst_avg,user_avg,+',
			'CDEF:syst_acc=syst_avg',
			"AREA:nice_acc#$HalfGreen",
			"AREA:user_acc#$HalfBlue",
			"AREA:syst_acc#$HalfRed",
			"LINE1:nice_acc#$FullGreen:Nice  ",
			'GPRINT:nice_min:MIN:%5.1lf%% Min,',
			'GPRINT:nice_avg:AVERAGE:%5.1lf%% Average,',
			'GPRINT:nice_max:MAX:%5.1lf%% Max,',
			'GPRINT:nice_avg:LAST:%5.1lf%% Last\n',
			"LINE1:user_acc#$FullBlue:User  ",
			'GPRINT:user_min:MIN:%5.1lf%% Min,',
			'GPRINT:user_avg:AVERAGE:%5.1lf%% Average,',
			'GPRINT:user_max:MAX:%5.1lf%% Max,',
			'GPRINT:user_avg:LAST:%5.1lf%% Last\n',
			"LINE1:syst_acc#$FullRed:System",
			'GPRINT:syst_min:MIN:%5.1lf%% Min,',
			'GPRINT:syst_avg:AVERAGE:%5.1lf%% Average,',
			'GPRINT:syst_max:MAX:%5.1lf%% Max,',
			'GPRINT:syst_avg:LAST:%5.1lf%% Last'],
	temperature => ['DEF:temp_avg={file}:value:AVERAGE',
			'DEF:temp_min={file}:value:MIN',
			'DEF:temp_max={file}:value:MAX',
			"AREA:temp_max#$HalfRed",
			"AREA:temp_min#$Canvas",
			"LINE1:temp_avg#$FullRed:Temperature",
			'GPRINT:temp_min:MIN:%4.1lfC Min,',
			'GPRINT:temp_avg:AVERAGE:%4.1lfC Average,',
			'GPRINT:temp_max:MAX:%4.1lfC Max,',
			'GPRINT:temp_avg:LAST:%4.1lfC Last'],
	traffic => ['DEF:out_avg={file}:outgoing:AVERAGE',
			'DEF:out_min={file}:outgoing:MIN',
			'DEF:out_max={file}:outgoing:MAX',
			'DEF:inc_avg={file}:incoming:AVERAGE',
			'DEF:inc_min={file}:incoming:MIN',
			'DEF:inc_max={file}:incoming:MAX',
			'CDEF:out_avg_bit=out_avg,8,*',
			'CDEF:out_min_bit=out_min,8,*',
			'CDEF:out_max_bit=out_max,8,*',
			'CDEF:inc_avg_bit=inc_avg,8,*',
			'CDEF:inc_min_bit=inc_min,8,*',
			'CDEF:inc_max_bit=inc_max,8,*',
			'CDEF:overlap=out_avg_bit,inc_avg_bit,GT,inc_avg_bit,out_avg_bit,IF',
			"AREA:out_avg_bit#$HalfGreen",
			"AREA:inc_avg_bit#$HalfBlue",
			"AREA:overlap#$HalfBlueGreen",
			"LINE1:out_avg_bit#$FullGreen:Outgoing",
			'GPRINT:out_min_bit:MIN:%5.1lf %sb Min,',
			'GPRINT:out_avg_bit:AVERAGE:%5.1lf %sb Average,',
			'GPRINT:out_max_bit:MAX:%5.1lf %sb Max,',
			'GPRINT:out_avg_bit:LAST:%5.1lf %sb Last\n',
			"LINE1:inc_avg_bit#$FullBlue:Incoming",
			'GPRINT:inc_min_bit:MIN:%5.1lf %sb Min,',
			'GPRINT:inc_avg_bit:AVERAGE:%5.1lf %sb Average,',
			'GPRINT:inc_max_bit:MAX:%5.1lf %sb Max,',
			'GPRINT:inc_avg_bit:LAST:%5.1lf %sb Last']
};

$graphdefs->{'traffic_eth1'} = $graphdefs->{'traffic'};
$graphdefs->{'traffic_tap0'} = $graphdefs->{'traffic'};
$graphdefs->{'temperature_cpu'} = $graphdefs->{'temperature'};
$graphdefs->{'temperature_mainboard'} = $graphdefs->{'temperature'};

our $graphargs =
{
	load => ['-t', 'casella.faui2k3.org load average', '-v', 'System load', '-X', '0'],
	mails	=> ['-t', 'verplant.org mail count', '-v', 'Amount', '-X', '0'],
	ping => ['-t', 'casella.faui2k3.org ping', '-v', 'ms'],

	meminfo			=> ['-t', 'casella.faui2k3.org memory usage',		'-v', 'Bytes', '-b', '1024', '-l', '0'],
	cpu0			=> ['-t', 'casella.faui2k3.org CPU usage',		'-v', 'Percent'],
	temperature_cpu		=> ['-t', 'casella.faui2k3.org CPU temperature',		'-v', ' Celsius'],
	temperature_mainboard	=> ['-t', 'casella.faui2k3.org mainboard temperature',	'-v', ' Celsius'],
	traffic_eth1		=> ['-t', 'casella.faui2k3.org eth1 traffic',		'-v', 'Bit/s'],
	traffic_tap0		=> ['-t', 'casella.faui2k3.org tap0 traffic',		'-v', 'Bit/s']
};

our $graphfile =
{
	traffic_eth1	=> "$rrdpath/traffic-eth1.rrd",
	traffic_tap0	=> "$rrdpath/traffic-tap0.rrd",
	temperature_cpu	=> "$rrdpath/sensors-temp1.rrd",
	temperature_mainboard	=> "$rrdpath/sensors-temp2.rrd"
};	

our @info = defined ($ENV{'PATH_INFO'}) ? $ENV{'PATH_INFO'} =~ m#(\w+)#g : die;
our $type = @info ? shift (@info) : die;
our $time = @info ? shift (@info) : 'day';
our $file = defined ($graphfile->{$type}) ? $graphfile->{$type} : "$rrdpath/$type.rrd";

our @cmd = ();

die unless (defined ($graphdefs->{$type}));

if ($time =~ m/(\d+)/)
{
	$time = -1 * int ($1);
}
else
{
	my %t = (day => -86400, week => -604800, month => -2678400, year => -31622400);

	die unless (defined ($t{$time}));

	$time = $t{$time};
}

die ("File not found: $file") unless (-e $file);

push (@cmd, '-', '-a', 'PNG', '-s', $time);
push (@cmd, @{$graphargs->{$type}}) if (defined ($graphargs->{$type}));
#push (@cmd, qw(-c BACK#000000
#	-c SHADEA#000000
#	-c SHADEB#000000
#	-c FONT#dddddd
#	-c CANVAS#202020
#	-c GRID#666666
#	-c MGRID#aaaaaa
#	-c FRAME#202020
#	-c ARROW#ffffff));
push (@cmd, qw(-c BACK#FFFFFF
	-c SHADEA#FFFFFF
	-c SHADEB#FFFFFF
	-c FONT#000000
	-c CANVAS#F5F5F5
	-c GRID#D0D0D0
	-c MGRID#A0A0A0
	-c FRAME#646464
	-c ARROW#FF0000));
push (@cmd, map { s/\{file\}/$file/g; $_; } @{$graphdefs->{$type}});

$| = 1;

print STDOUT <<HEADER;
Content-Type: image/png
Cache-Control: no-cache

HEADER

RRDs::graph (@cmd);

die ('RRDs::error: ' . RRDs::error ()) if (RRDs::error ());

exit (0);
