#!/usr/bin/perl -w

###################################################################################################
#	MAGNETOMETER_FIGURE.CGI
#	
#	Denne filen behandler data mottatt fra "MAGNETOMETER_PAGE.CGI" ( som igjen mottar disse dataene fra 
#	brukerprogrammet SENSOR_FORM.CGI ), og genererer en graf over en gitt tid ut fra disse dataene.
#	Mottatte data er YEAR, MONTH, DAY, PERIODE, MIDDLE, MIN OG MAX.
#	
#	YEAR, MONTH og DAY angir starttid for når grafen skal tegnes. 
#	PERIODE er enten 24_HOURS, WEEK, MONTH eller YEAR og angir hvor langt grafen skal tegnes i
#	forhold til starttid.
#	MIDDLE, MIN OG MAX angir hva som skal tegnes i gitt PERIODE ( en eller flere av disse kan være 
#	valgt av bruker). 
#
#	Programmet består av seks subrutiner
#	
#		- day_data($year, $month, $day, $min, $max, $middle )
#		- week_data($year, $month, $day, $min, $max, $middle )
#		- month_data($year, $month )
#		- year_data($year )
#		- error($x, $y, $string, $string2 )
#		- $drawGraph()
#
#	Avhengig av PERIODE og MIDDLE, MIN og MAX ( når og hva som skal plottes ) vil subrutinene 
#	day_data(..) - week_data(..) plukke ut ønsket data fra databasen HESSDALEN.MAGNETOMETER_BEREGNET og
#	legge disse dataene i det globale arrayet @data. Videre vil så subrutinen drawGraph() tegne 
# en graf for disse dataene. Dersom en feil oppstår ( f.eks feil periode - ingen data i db o.l )
#	vil subrutinen error(..) slå til. error(..) genererer et bilde basert på sine fire argumenter, der
#	de to første angir plassering, (x,y), for hvor de siste argumentene ( string og string2 ) skal
#	skrives ut.
#
# month_data() og year_data() henter ut alleredeeksisterende bilder fra katalogen images. 
#
###################################################################################################

use strict;
use CGI ":standard";
use GD::Text;
use GD;
use GD::Graph::lines;
use Pg;
use Time::ParseDate;

my @legends;
my @data;
my $year = url_param('year');
my $day = url_param('day');
my $month = url_param('month');
my $min = url_param('min');
my $middle = url_param('middle');
my $max = url_param('max');
my $x = url_param('x');
my $y = url_param('y');
my $z = url_param('z');
my $title;
my $y_label;
my $x_label;
my $x_label_skip;
my $x_label_vertical;
my $status = 0;
my $correct_width;

if(url_param('periode') eq '24_HOURS'){
	#year, month, day, min, maks, mid
	if(defined(&day_data( $year, $month, $day, $min, $max, $middle, $x, $y, $z ))) {
		&drawGraph();		
	} else {
		&error(10,10, "There are no data registred in the database for this period.", "Try again...");
	}
}elsif(url_param('periode') eq 'WEEK'){
	#year, month, day, min, maks, mid
	if(defined(&week_data( $year, $month, $day, $min, $max, $middle, $x, $y, $z ))) {
		&drawGraph();		
	} else {
		&error(10,10, "There are no data registred in the database for this period.", "Try again...");
	}
}elsif(url_param('periode') eq 'MONTH'){
	#year, month, day, min, maks, mid
	if(defined(&month_data( $year, $month ))) {
		exit;
		#&drawGraph();		
	} else {
		&error(10,10, "There are no data registred in the database for this period.", "Try again...");
	}
}elsif(url_param('periode') eq 'YEAR'){
	#year, month, day, min, maks, mid
	if(defined(&year_data( $year ))) {
		exit;
		#&drawGraph();		
	} else {
		&error(10,10, "There are no data registred in the database for this period.", "Try again...");
	}
	
}else{
	&error(10,10, "There are no data for this length", "Try again");
}


#############################
#
#		SUBRUTINER
#
#############################


#############################
#ERROR-MELDING
#############################
sub error{
		my ($x, $y, $error_message, $error_message2 ) = @_;
		#Dersom det ikke er oppgitt noen ønkset min, maks eller middle 
		#lages et enkelt bilde med feilmelding i.
		my $im = new GD::Image(600,400);
		#Farger
		my $bakgrunn 	= $im->colorAllocate(232,	246,	250);
		my $white		 	= $im->colorAllocate(255,	255,	255);
		my $black 		= $im->colorAllocate(0,		0,		0);
		$im->filledRectangle(1,1,599,399,$bakgrunn);
		
		#Plasserer feilmelding i bildet.
		$im->string(gdMediumBoldFont,$x,$y,$error_message, $black);
		$im->string(gdMediumBoldFont,10,$y+14,$error_message2, $black);
		
		print("Content-type: image/png\n\n");
		print $im->png;
		exit;
}

#############################
#DAG-DATA
#############################
sub day_data {
	#Mottatte data
	my ($from_year, $from_month, $from_day, $usemin, $usemax, $usemid, $usex, $usey, $usez) = @_;

	#Dersom bruker ikke har oppgitt ønsket data - returner
	($usemin == 0) && ($usemax == 0) && ($usemid == 0) && return undef;
	($usex == 0) && ($usey == 0) && ($usez == 0) && return undef;
	
	#Oppkobling til database
	my $dbconn = Pg::connectdb("dbname=hessdalen");
	
	($dbconn->status == PGRES_CONNECTION_BAD) && return undef;

	my $res = $dbconn->exec("
		SELECT time,
		min_x_verdi, middel_x_verdi, max_x_verdi,
		min_y_verdi, middel_y_verdi, max_y_verdi,
		min_z_verdi, middel_z_verdi, max_z_verdi
		FROM magnetometer_beregnet
		WHERE aar=$from_year AND maaned=$from_month AND dag=$from_day
		ORDER BY time"
	);

	($res->resultStatus != PGRES_TUPLES_OK) && return undef;

	($res->ntuples == 0) && return undef;

	#Globale variabler for graf.
	$title		= sprintf ("Magnetometerdata for %02d.%02d.%d", $from_month, $from_day, $from_year );
	$x_label	= "Time - [ hours ]";
	$y_label	= "nanoTesla [ nT ]";
	$x_label_skip = 0;
	$x_label_vertical = 0;
	$correct_width= 1;
	
	#Ønskede intervaller ( fra periode - til periode ) - brukes i sql setning nedenfor.
	my $from_time = parsedate("$from_day.$from_month.$from_year", UK=>1);
	my $to_time = parsedate("+ 1 day", NOW => $from_time);
	
	#Tabeller for dataer som skal vises i graf
	my @xvalues = ();
	my @min_x_data = ();
	my @min_y_data = ();
	my @min_z_data = ();
	my @mid_x_data = ();
	my @mid_y_data = ();
	my @mid_z_data = ();
	my @max_x_data = ();
	my @max_y_data = ();
	my @max_z_data = ();

	for(my $tup=0, my $i=0; $from_time < $to_time; $i++) {
		my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($from_time);
		
		#Push time til @xvalues -> det som vises på x-akse.
		push @xvalues, $hour; 

		#Dersom time i db = ønsket time fra $from_time legges data i @mindata - @maxdata
		#ellers udefinert -> Vises ikke i graf
		if($tup < $res->ntuples && $res->getvalue($tup, 0) == $hour) {	
			push @min_x_data, $res->getvalue($tup, 1);
			push @mid_x_data, $res->getvalue($tup, 2);
			push @max_x_data, $res->getvalue($tup, 3);		
			
			push @min_y_data, $res->getvalue($tup, 4);
			push @mid_y_data, $res->getvalue($tup, 5);
			push @max_y_data, $res->getvalue($tup, 6);
		
			push @min_z_data, $res->getvalue($tup, 7);
			push @mid_z_data, $res->getvalue($tup, 8);
			push @max_z_data, $res->getvalue($tup, 9);
			
			$tup++;
		} else {
			push @min_x_data, undef;
			push @mid_x_data, undef;
			push @max_x_data, undef;		
			
			push @min_y_data, undef;
			push @mid_y_data, undef;
			push @max_y_data, undef;
			
			push @min_z_data, undef;
			push @mid_z_data, undef;
			push @max_z_data, undef;		

		}

		#Øker $fromdata med en time.
		$from_time = parsedate("+ 1 hour", NOW => $from_time);
	}

	#Legger data i den globale tabellen @data. Denne benyttes så for tegning av grafen i drawGraph().
	push @data, [@xvalues];
	if( $usemin == 1 && ( ($usex != 0) || ($usey != 0) || ($usez != 0) ) ){
	 ($usex == 1) && ( push @legends, "x-min" ) && (push @data, [@min_x_data]);
	 ($usey == 1) && ( push @legends, "y-min" ) && (push @data, [@min_y_data]);
	 ($usez == 1) && ( push @legends, "z-min" ) && (push @data, [@min_z_data]);
	}	
	if( $usemid == 1 && ( ($usex != 0) || ($usey != 0) || ($usez != 0) ) ){
	 ($usex == 1) && ( push @legends, "x-avg" ) && (push @data, [@mid_x_data]);
	 ($usey == 1) && ( push @legends, "y-avg" ) && (push @data, [@mid_y_data]);
	 ($usez == 1) && ( push @legends, "z-avg" ) && (push @data, [@mid_z_data]);
	}
	if( $usemax == 1 && ( ($usex != 0) || ($usey != 0) || ($usez != 0) ) ){
	 ($usex == 1) && ( push @legends, "x-max" ) && (push @data, [@max_x_data]);
	 ($usey == 1) && ( push @legends, "y-max" ) && (push @data, [@max_y_data]);
	 ($usez == 1) && ( push @legends, "z-max" ) && (push @data, [@max_z_data]);
	}
	
	#Legends - angir "datas tilhørende fargekombinasjon" i grafen.
	#($usemin == 1) && (push @legends, "x-min") && (push @legends, "y-min") && (push @legends, "z-min");
	#($usemid == 1) && (push @legends, "x-avg") && (push @legends, "y-avg") && (push @legends, "z-avg");
	#($usemax == 1) && (push @legends, "x-max") && (push @legends, "y-max") && (push @legends, "z-max");
	
	#($usemin == 1) && (push @data, [@min_x_data]) && (push @data, [@min_y_data]) && (push @data, [@min_z_data]); 
	#($usemid == 1) && (push @data, [@mid_x_data]) && (push @data, [@mid_y_data]) && (push @data, [@mid_z_data]); 
	#($usemax == 1) && (push @data, [@max_x_data]) && (push @data, [@max_y_data]) && (push @data, [@max_z_data]);
	
	return 1;
}


#############################
#UKES-DATA
#############################
sub week_data {
	#Mottatte data
	my ($from_year, $from_month, $from_day, $usemin, $usemax, $usemid, $usex, $usey, $usez ) = @_;
	
	#Dersom bruker ikke har oppgitt ønskede data - returner
	($usemin == 0) && ($usemax == 0) && ($usemid == 0) && return undef;
	($usex == 0) && ($usey == 0) && ($usez == 0) && return undef;
  
	#Oppkobling til database
	my $dbconn = Pg::connectdb("dbname=hessdalen");

	($dbconn->status == PGRES_CONNECTION_BAD) && return undef;

	my $from_time = parsedate("$from_day.$from_month.$from_year", UK=>1);
	my $to_time = parsedate("+ 1 week", NOW => $from_time);

	my ($to_sec,$to_min,$to_hour,$to_mday,$to_mon,$to_year,$to_wday,$to_yday,$to_isdst) = localtime($to_time);

	my $from = $from_year*10000 + $from_month*100 + $from_day;
	my $to = ($to_year+1900)*10000 + ($to_mon+1)*100 + $to_mday;

	my $res = $dbconn->exec("
		SELECT aar, maaned, dag, time, 
		min_x_verdi, middel_x_verdi, max_x_verdi,
		min_y_verdi, middel_y_verdi, max_y_verdi,
		min_z_verdi, middel_z_verdi, max_z_verdi
		FROM magnetometer_beregnet
		WHERE aar*10000+maaned*100+dag>=$from AND aar*10000+maaned*100+dag < $to
		ORDER BY aar, maaned, dag, time"
	);
	
	($res->resultStatus != PGRES_TUPLES_OK) && return undef;

	($res->ntuples == 0) && return undef;

	$title		= sprintf ( "Magnetometerdata for %02d.%02d.%d - %02d.%02d.%d" , $from_month, $from_day,$from_year, ($to_mon+1), ( $to_mday-1 ), ($to_year+1900) );
	$x_label	= "Time - [ month.day - hour ]";
	$y_label	= "NanoTesla [ nT ]";
	$x_label_skip  = 4;
	$x_label_vertical = 1;	
	$correct_width= 1;	

	my @xvalues = ();
	my @min_x_data = ();
	my @min_y_data = ();
	my @min_z_data = ();
	my @mid_x_data = ();
	my @mid_y_data = ();
	my @mid_z_data = ();
	my @max_x_data = ();
	my @max_y_data = ();
	my @max_z_data = ();

	for(my $tup=0, my $i=0; $from_time < $to_time; $i++) {
		my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($from_time);

		my $date = sprintf("%2d.%02d - %2d", ( $mon + 1 ), $mday ,$hour );
		push @xvalues, $date;


		if($tup < $res->ntuples && $res->getvalue($tup, 0) == ($year+1900) &&
			$res->getvalue($tup, 1) == ($mon+1) && $res->getvalue($tup, 2) == $mday &&
			$res->getvalue($tup, 3) == $hour) {	

			push @min_x_data, $res->getvalue($tup, 4);
			push @mid_x_data, $res->getvalue($tup, 5);
			push @max_x_data, $res->getvalue($tup, 6);		
			
			push @min_y_data, $res->getvalue($tup, 7);
			push @mid_y_data, $res->getvalue($tup, 8);
			push @max_y_data, $res->getvalue($tup, 9);
		
			push @min_z_data, $res->getvalue($tup, '10');
			push @mid_z_data, $res->getvalue($tup, '11');
			push @max_z_data, $res->getvalue($tup, '12');
		
			$tup++;
		} else {
			push @min_x_data, undef;
			push @mid_x_data, undef;
			push @max_x_data, undef;		
			
			push @min_y_data, undef;
			push @mid_y_data, undef;
			push @max_y_data, undef;
			
			push @min_z_data, undef;
			push @mid_z_data, undef;
			push @max_z_data, undef;		
		}
	
		$from_time = parsedate("+ 1 hour", NOW => $from_time);
	}

	push @data, [@xvalues];

	if( $usemin == 1 && ( ($usex != 0) || ($usey != 0) || ($usez != 0) ) ){
	 ($usex == 1) && ( push @legends, "x-min" ) && (push @data, [@min_x_data]);
	 ($usey == 1) && ( push @legends, "y-min" ) && (push @data, [@min_y_data]);
	 ($usez == 1) && ( push @legends, "z-min" ) && (push @data, [@min_z_data]);
	}	
	if( $usemid == 1 && ( ($usex != 0) || ($usey != 0) || ($usez != 0) ) ){
	 ($usex == 1) && ( push @legends, "x-avg" ) && (push @data, [@mid_x_data]);
	 ($usey == 1) && ( push @legends, "y-avg" ) && (push @data, [@mid_y_data]);
	 ($usez == 1) && ( push @legends, "z-avg" ) && (push @data, [@mid_z_data]);
	}
	if( $usemax == 1 && ( ($usex != 0) || ($usey != 0) || ($usez != 0) ) ){
	 ($usex == 1) && ( push @legends, "x-max" ) && (push @data, [@max_x_data]);
	 ($usey == 1) && ( push @legends, "y-max" ) && (push @data, [@max_y_data]);
	 ($usez == 1) && ( push @legends, "z-max" ) && (push @data, [@max_z_data]);
	}

	#($usemin == 1) && (push @legends, "x-min") && (push @legends, "y-min") && (push @legends, "z-min");
	#($usemid == 1) && (push @legends, "x-avg") && (push @legends, "y-avg") && (push @legends, "z-avg");
	#($usemax == 1) && (push @legends, "x-max") && (push @legends, "y-max") && (push @legends, "z-max");
	
	#($usemin == 1) && (push @data, [@min_x_data]) && (push @data, [@min_y_data]) && (push @data, [@min_z_data]); 
	#($usemid == 1) && (push @data, [@mid_x_data]) && (push @data, [@mid_y_data]) && (push @data, [@mid_z_data]); 
	#($usemax == 1) && (push @data, [@max_x_data]) && (push @data, [@max_y_data]) && (push @data, [@max_z_data]);

	return 1;
}

#############################
#MÅNEDS-DATA
#############################
sub month_data {
	#Mottatte data
	my ($from_year, $from_month) = @_;
	my $fileref = sprintf( "images/month_%4d%02d.png", $from_year, $from_month );
	open (PNG, $fileref ) || return undef; 
	my  $monthimg = newFromPng GD::Image(\*PNG) || return undef;
	close PNG;
	print("Content-type: image/png\n\n");
	print $monthimg->png || return undef;		
		}

#############################
#ÅR-DATA
#############################
sub year_data {
	#Mottatte data
	my ($from_year ) = @_;
	my $fileref = sprintf( "images/year_%4d.png", $from_year );
	open (PNG, $fileref ) || return undef; 
	my  $yearimg = newFromPng GD::Image(\*PNG) || return undef;
	close PNG;
	print("Content-type: image/png\n\n");
	print $yearimg->png || return undef;
	
}


#############################
#SELVE FIGURTEGINGEN
#############################
sub drawGraph{
	
	#Oppretter ny figur - graf bestående av linjer.
	my $graph = GD::Graph::lines->new(600,400);
	
	#Farger og font.
	$graph->set_text_clr('#000000');
	$graph->set_title_font('../font/courbd.ttf',14);
	#$graph->set_x_label_font('../font/courbd.ttf',10);
	#$graph->set_y_label_font('../font/courbd.ttf',10);
	$graph->set_legend_font('../font/courbd.ttf',8);
	
	#"Fargesammensetning" for de forskjellige grafene som vises i samme figur - basert på den globale 
	#tabellen @legends.
	$graph->set_legend(@legends);

	#Oppsett av grafen - hvordan den ser ut.
	$graph->set(
		labelclr					=>	'black',
		textclr						=>	'black',
		title							=>	$title,
		transparent				=>	1,
		interlaced				=>	0,
		fgclr							=>	'#4395a5',
		bgclr							=>	'#e8f6fa',
		boxclr						=>	'#e8f6fa',
		borderclrs				=>	'undef',
		t_margin					=>	10,
		r_margin					=>	10,
		l_margin					=>	10,
		b_margin					=>	0,
		tick_length				=>	4,
		long_ticks				=>	1, 
		zero_axis					=>  0, 
		zero_axis_only		=>	0, 
		box_axis					=>	0,
		axis_space				=>	4,
		line_width				=>	2,
		line_types				=>	[1,1,1,1],
	
		x_label_position 	=>	1,
		x_label						=>	$x_label,
		x_label_skip			=>	$x_label_skip,	
		x_all_ticks				=> 	0,
		x_tick_offset			=>  0,
		correct_width			=>	$correct_width,
		x_plot_values			=>	1, 
		x_labels_vertical	=>	$x_label_vertical,
	
		y_label_position	=>	1,
		y_label						=>	$y_label,
		y_tick_number			=>	10,
		y_label_skip			=>	0,
		overwrite					=>	0
	);
	
	#Plotter graf med datasettet @data - inneholder data for enten day_data(), week_data(), month_data()
	#eller year_data() med tilhørende tilhørende verdier i form av min, maks eller middel temperatur. 
	my $gd = $graph->plot(\@data);
	
	print("Content-type: image/png\n\n");
	print $gd->png;

}
