#!/usr/bin/perl

#
# RRDtool stripgraph maker - version 0.3
# Copyright 2006 by Howard Jones, howie@thingy.com
# http://wotsit.thingy.com/haj/
# 
# All rights reserved.  This program is free software; you may 
# redistribute it and/or modify it under the same terms as Perl itself.
#
# See the website for documentation. This is rough and ready at the moment
#

use Imager;
use XML::Simple;
use Data::Dumper;
use Number::Format qw(:subs);
use Getopt::Long;

$twidth = 128;
$theight = 48;

$tfont = "./ArialN.TTF";
$tfontsize = 11;

$tfilename = "strip.png";

$theight = 48;
$twidth = 128;
$nonzero = 0;
$unformatted=0;
$tlinethickness=1;

$linecolour = "8080ff";
$bgcolour = "dedeff";

$blacktext = "System Name";
$redtext = "1000M";

$scalefactor = 3;
$verbose = 0;

GetOptions (
	"wanted=i" => \$wanted,
	"font=s" => \$font,
	"fontsize=i" => \$tfontsize,
	"label=s" => \$blacktext,
	"width=i" => \$twidth,
	"height=i" => \$theight,
	"nonzero" => \$nonzero,
	"unformatted" => \$unformatted,
	"verbose" => \$verbose,
	"rescaling=i" => \$scalefactor,
	"linethickness=i" => \$tlinethickness,
	"backgroundcolour=s" => \$bgcolour,
	"linecolour=s" => \$linecolour,
	"outputfilename=s" => \$tfilename
);

if($verbose)
{
  print STDERR "Supported Image formats: ", join(", ", sort keys %Imager::formats),"\n";
  print STDERR "Supported Font formats: ";

  print STDERR "Has truetype. "      if $Imager::formats{tt};
  print STDERR "Has t1 postscript. " if $Imager::formats{t1};
  print STDERR "Has Win32 fonts. "   if $Imager::formats{w32};
  print STDERR "Has Freetype2. "     if $Imager::formats{ft2};
  print STDERR "\n";
}

#####################
# scale up here, so we can scale down later
#

$width = $twidth * $scalefactor;
$height = $theight * $scalefactor;
$fontsize = $tfontsize * $scalefactor;
$linethickness= $tlinethickness * $scalefactor/2;

###########

my $img = Imager->new(xsize=>$width, ysize=>$height, channels=>3);

$black = Imager::Color->new(0,0,0);
$white = Imager::Color->new(255,255,255);

$paleblue = Imager::Color->new("#${bgcolour}");
$linecolour = Imager::Color->new("#${linecolour}");
$red = Imager::Color->new("#ff0000");


# background fill
$img->box(filled=>1, color=>$white);


# figure out how big the chart part needs to be...

$font = Imager::Font->new(file => $tfont, size => $fontsize) || die($!);

# here's a string with the tallest letters...
($neg_width, $global_descent, $pos_width,$global_ascent,
   $descent, $ascent, $advance_width, $right_bearing) = $font->bounding_box(string=>"yyAAIIjygzwjjjww");

$chartheight = $height - ($global_ascent - $global_descent + 2 * $scalefactor);
$chartwidth = $width;

# print "Chart height is $chartheight, width is $chartwidth\n";

# graph background fill
$img->box(filled=>1, color=>$paleblue, 
			xmin => 0, xmax => $width, 
			ymin => 0, ymax => $chartheight
		);



# read in the XML data from stdin

read_xml();

##########

($neg_width, $global_descent, $pos_width,$global_ascent,
   $descent, $ascent, $advance_width, $right_bearing) = $font->bounding_box(string=>$blacktext);


$img->string(font  => $font,
             text  => $blacktext,
			 color => $black,
			 align => 1,
             x     => 1*$scalefactor,
             y     =>  $height + $global_descent,
             aa    => 1);

####

($neg_width, $global_descent, $pos_width,$global_ascent,
   $descent, $ascent, $advance_width, $right_bearing) = $font->bounding_box(string=>$redtext);

$img->string(font  => $font, text  => $redtext, color => $red,
			align => 1, 
			  x => $width - 1*$scalefactor - $advance_width,
             y     =>  $height + $global_descent,
             aa    => 1);





##########
# now all the drawing is done, we should scale back down again...
$newimg = $img->scale(xpixels=>$twidth, ypixels=>$theight);
$newimg->write(file=>$tfilename) or die $newimg->errstr;



#######################################################################

sub read_xml
{
	$ref = XMLin('-',ForceArray=>['v','entry']);

	$rowcount = $ref->{meta}->{rows};
	# take one off for the NaN at the end, and another to make the index 0-based
	$rowcount--;
	$rowcount--;

	# This is a bodge. Have a look for the perl equiv of limits.h....
	$valmin = 99e80;
	$valmax = -99e80; 

	$label = $ref->{meta}->{legend}->{entry}->[$wanted];
	$blacktext = $label;

	foreach $i (1..$rowcount)
	{
		$timet = $ref->{data}->{row}->[$i-1]->{t},"\t";
		$val = $ref->{data}->{row}->[$i-1]->{v}->[$wanted],"\t";

		if($val ne "NaN")
		{
			$valmin = min($valmin,$val);
			$valmax = max($valmax,$val);
		}
	}

	# just so the graph isn't 1-dimensional
	if($valmax==$valmin) 
	{
		$valmax++;
	}

	$chartheight = $chartheight-$linethickness*2;

	for $i (0..$rowcount)
	{
		$x = (($i/$rowcount)*$chartwidth)+1;	
		$v = $ref->{data}->{row}->[$i-1]->{v}->[$wanted];
		if($nonzero)
		{
			$y = $chartheight - (($v-$valmin)/($valmax-$valmin))*$chartheight + $linethickness*2;
		}
		else
		{
			$y = $chartheight - ($v/$valmax)*$chartheight + $linethickness*2;
		}
	
		$xpts[$i] = $x;
		$ypts[$i] = $y;
		$lastval = $v;
	}
	
	for $i (2..$rowcount)
	{
		$colour = $linecolour;
		if($i==$rowcount) { $colour=$red; }

		# now set that as the anti-alias colour
		# $colour = $im->setAntiAliased($colour);
		# $colour = gdAntiAliased;

		# $img->line($xpts[$i-1],$chartheight-$ypts[$i-1],$xpts[$i],$chartheight-$ypts[$i],$colour);
#		$img->line(color=>$colour, 
	#				x1=>$xpts[$i-1], y1=>$ypts[$i-1],
		#			x2=>$xpts[$i], y2=>$ypts[$i],
			#		aa=>1, endp=>1
				#	);

		thickline(image => $img, color=>$colour, 
					x1=>$xpts[$i-1], y1=>$ypts[$i-1],
					x2=>$xpts[$i], y2=>$ypts[$i],
					aa=>1, endp=>1, thickness => $linethickness
					);



#		print "LINE: x1=>$xpts[$i-1], y1=>$ypts[$i-1],	x2=>$xpts[$i], y2=>$ypts[$i]\n";

	}
	
	$redtext = format_bytes($lastval);
	if($unformatted)
	{
			$redtext = sprintf("%d",$lastval);
	}
}


sub thickline
{
	my %params = @_;

	my $dx = $params{'x2'} - $params{'x1'};
	my $dy = $params{'y2'} - $params{'y1'};

	my $len = sqrt($dx*$dx + $dy*$dy);
	my $ndx = $dx/$len;
	my $ndy = $dy/$len;

	# find the normal.
	my $nx = $ndy;
	my $ny = -$ndx;

	my $img = $params{'image'};

	my $x1a = $params{'x1'} + $params{'thickness'}*$nx;
	my $x1b = $params{'x1'} - $params{'thickness'}*$nx;
	my $x2a = $params{'x2'} + $params{'thickness'}*$nx;
	my $x2b = $params{'x2'} - $params{'thickness'}*$nx;

	my $y1a = $params{'y1'} + $params{'thickness'}*$ny;
	my $y1b = $params{'y1'} - $params{'thickness'}*$ny;
	my $y2a = $params{'y2'} + $params{'thickness'}*$ny;
	my $y2b = $params{'y2'} - $params{'thickness'}*$ny;



	if(1==0)
	{
		$img->line( 	aa => $params{'aa'},
			endp => $params{'endp'},
			x1 => $params{'x1'} + $params{'thickness'}*$nx,
			y1 => $params{'y1'} + $params{'thickness'}*$ny,

			x2 => $params{'x2'} + $params{'thickness'}*$nx,		
			y2 => $params{'y2'} + $params{'thickness'}*$ny,	
			color=>$params{'color'}
			 );
		$img->line( 	aa => $params{'aa'},
			endp => $params{'endp'},
			x1 => $params{'x1'} - $params{'thickness'}*$nx,
			y1 => $params{'y1'} - $params{'thickness'}*$ny,

			x2 => $params{'x2'} - $params{'thickness'}*$nx,		
			y2 => $params{'y2'} - $params{'thickness'}*$ny,	
			color=>$params{'color'}
			 );
	}
	else
	{
		$img->polygon(
			points => [
				[$x1a,$y1a], [$x2a,$y2a],
				[$x2b,$y2b], [$x1b,$y1b]
			],
			color=>$params{'color'}
			);
	}
}

sub min
{
        if($_[0] < $_[1]) { return $_[0]; } else { return $_[1]; }
}

sub max
{
       if($_[0] > $_[1]) { return $_[0]; } else { return $_[1]; }
}



