#!/usr/bin/perl -w
# 

# TemperatureProbeMakeGraph
# Version 1.0
# This programme:
# Makes graphs from RRDTOOL database created from GetInputFromTemperatureKit145

# Author Stephen Kingham, Stephen.Kingham<AT>kingtech.com.au
#
# http://www.kingtech.com.au
#
# License and distributed under the GNU General Public License (GPL)
#
# Copyright (C) 2009 Stephen Kingham
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.


use strict;
# strict checks the perl programme is correctly formated
#
use CGI;
# CGI.pm a mature solution to handle HTTP requests and responses.
#
use File::Find;
# Find helps find the filenames used for the RRDTOOL databases
#
use File::Basename;
# Basename is needed for fileparse which we use to find the RRDTOOL database filenames
#
use RRDs;
# RRDs is a PERL module to accesses RRDtool functionality directly from within Perl
#
use English qw( -no_match_vars ) ;
# The English PERL Module allows us to write a PERL script that is more readable.
# According to Perldoc the "qw( -no_match_vars )" makes this module work a little more efficiently.

my $GraphDuration = "1w";
# GraphDuration indicates the duration of the graph, can be changed by CGI variable
#
my $Debug = "DEBUG";
# Debug="DEBUG" will output debug information.  It is only set here by a programmer to find issues.
#
my @Args=();
# Args is used to pass shell commands
#
my $RootDataDir="/var/data/percyTemp";
# RootDataDir is the directory where the RRDTOOL database files containing the temperature data
# Apache will need to read the directory and read the files (but not write)
#
my $RootGraphDir="/var/www/tempForCGI-BIN";
# RootGraphDir is where the graphs are stored.  This directory will also need to be defined in Apache.
# This is a special directory that is read by Apache, and can be written to from apache, 
# so it is quite vulnerable and so is only used to write graphs to.
#
my $srcFileAbs = "";
# srcFileAbs is created at the start of the the loops that go through and process files in a directory
# Is the Absolute filename of each file found in $RootDataDir
#
my $srcFilePathAbs = "";
# srcFilePathAbs is the absolute directory derived from $srcFileAbs
my $srcFilename = "";
# srcFilePathAbs is the filename (without the filename extension derived from $srcFileAbs
my $srcFileExtension = "";
# srcFilePathAbs is the file extension derived from $srcFileAbs
my $dstGraphFilenameAbs = "";
# the dstGraphFilenameAbs from srcFileAbs by removing .rrd and adding .png
#
my $SafeCharactersFromHtmlPost = "a-zA-Z0-9_.-";
# These are the only characters allowed to be passed from CGI as the $GraphDuration
#
$CGI::POST_MAX = 10;
# Tels CGI to limit the post to 10 Bytes.  This is used to stop hacking.
#
my $line="";
# Line is a variable to read a line from a file that contains the present temperature
#
my $FILE;
# Is set by the perl module and $FILE::Find::name returns the each filename one at a time
#
my $srcFileDatePart = "";
# This temporary variable is used to get the date stamp from the filename of a graphic file in $RootGraphDir
# and is used to delete old graphs
#
my $Minutes;
my $Hours;
my $Day;
my $Month;
my $MonthMM;
my $Year;
my $MonthMMM;
my $DayDD;
my $HoursHH;
my $MinutesMM;


#### Header for Web page
print "Content-type: text/html\r\n\r\n";
print "<Center><H2>Temperature Probes at Percy Crescent Chapman Canberra Australia</H2></Center><br />\n";


# Get the information sent from the HTTP POST
my $query = new CGI;

# Look in the HTTP POST for a variable called "Dur" and check it is valid data
$GraphDuration =$query->param("Dur");
if ( !$GraphDuration )
{
  $GraphDuration = "1w";
}
else
{
  $GraphDuration =~ tr/ /_/;
  $GraphDuration =~ s/[^$SafeCharactersFromHtmlPost]//g;
  if ( $GraphDuration =~ /^([$SafeCharactersFromHtmlPost]+)$/ )
  {
   $GraphDuration = $1;
  }
  else
  {
   die "Duration contains invalid characters";
  }
}


if ( $Debug eq "DEBUG" )
{
  print "RootDataDir  = $RootDataDir\n";
  print "RootGraphDir  = $RootGraphDir\n";
  print "GraphDuration= $GraphDuration\n";
  print "debug        = $Debug\n";
};
#


($Minutes, $Hours, $Day, $Month, $Year) = (localtime(time))[1,2,3,4,5];
#
# what is the year
$Year=$Year+1900;
#
# what is the month
$MonthMMM=("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")[$Month];
$DayDD     = substr("0$Day",     -2, 2);
#
$MonthMM   = substr("0$Month",   -2, 2);
# what is the hour
$HoursHH   = substr("0$Hours",   -2, 2);
#
# what is the minutes
$MinutesMM = substr("0$Minutes", -2, 2);





# Delete any old graphs 
find sub {
  # see the closing bracket which defines the starting directory
  # the srcFileAbs will equal the filenames found, one at a time
  $srcFileAbs = $File::Find::name;
  if ($Debug eq "DEBUG") { print "DEBUG: Start of a new possible Graph src file Abs=$srcFileAbs\n" };

  ($srcFilename, $srcFilePathAbs, $srcFileExtension) = fileparse( $srcFileAbs, qr/\.[^.]*/);
  if ($Debug eq "DEBUG") { print "srcPath=$srcFilePathAbs , Filename=$srcFilename, extension=$srcFileExtension\n" };

  if ( $srcFileExtension eq ".png" )
  {
    # We have found a grphic file, now we want to find out how old it is

    (undef, undef, $srcFileDatePart) = split ( "-", $srcFilename );
    if ($Debug eq "DEBUG") { print "Date Part = $srcFileDatePart\n" };

    if ( $srcFileDatePart lt $Year . $MonthMM . $DayDD . "0000" )
    {
      # We know know that this a graph created in a previous day.
      if ($Debug eq "DEBUG") { print "Goint to delete $srcFileAbs\n" };
      #
      # Delete the file
      @Args = ( "rm -f $srcFileAbs >/dev/null" );
      if ($Debug eq "DEBUG") {print LOG "Going to @Args\n"};

      system(@Args) == 0 or die "ERROR: system @Args failed: $? $!\n";
      if ($? == -1)
      {
        print LOG "ERROR: failed to execute @Args\n $!\n";
      }
      elsif ($? & 127)
      {
        printf LOG "ERROR: @Args\n child died with signal %d, %s\n", ($? & 127),  ($? & 128) ? 'with' : 'without';
        sleep 2;
        exit 0;
      }
      else
      {
        if ($Debug eq "DEBUG2") { printf LOG "@Args\n child exited with value %d\n", $? >> 8 };
      }
    }
  }

}, $RootGraphDir;


# Create the first part of the HTTP page.
#
print "<Center>$HoursHH:$MinutesMM $DayDD$MonthMMM$Year</Center><br />\n";
#
print "<FORM method=\"GET\" action=\"http://www.kingtech.com.au/cgi-bin/TemperatureProbeMakeGraph\">\n";
#
print "<Center>Graph duration ";
print "<select name=\"Dur\">";
print " <option ";
if ( $GraphDuration eq "1h" ) { print "selected=\"selected\" " };
print "value=\"1h\">hour</option>";
print " <option ";
if ( $GraphDuration eq "1d" ) { print "selected=\"selected\" " };
print "value=\"1d\">day</option>";
print " <option ";
if ( $GraphDuration eq "1w" ) { print "selected=\"selected\" " };
print "value=\"1w\">week</option>";
print " <option ";
if ( $GraphDuration eq "1m" ) { print "selected=\"selected\" " };
print "value=\"1m\">month</option>";
print " <option ";
if ( $GraphDuration eq "1y" ) { print "selected=\"selected\" " };
print "value=\"1y\">year</option>";
#
print "<input type=\"submit\" value=\"show me\">";
#
print "</FORM></Center><HR>";


#
# We are now going to go through the directory where the data is
# and create a graph for each one we find
#
find sub { 
  # see the closing bracket which defines the starting directory
  # the srcFileAbs will equal the filenames found, one at a time
  $srcFileAbs = $File::Find::name;
  if ($Debug eq "DEBUG") { print "DEBUG: Start of a new file<BR>\n<BR>\nsrc file Abs=$srcFileAbs<BR>\n" };

  # Look for srcFileAbs that ends in .rrd
  # Find the file's extension
  ($srcFilename, $srcFilePathAbs, $srcFileExtension) = fileparse( $srcFileAbs, qr/\.[^.]*/);
  if ($Debug eq "DEBUG") { print "srcPath=$srcFilePathAbs , Filename=$srcFilename, extension=$srcFileExtension\n" };
  #
  if ( $srcFileExtension eq ".rrd" || $srcFileExtension eq ".RRD")
  {
    # Calculate the dstGraphFilenameAbs from srcFileAbs by removing .rrd and adding .png
    $dstGraphFilenameAbs = $RootGraphDir . "/" . $srcFilename . "-" . $GraphDuration . "-" . $Year . $MonthMM . $DayDD . $HoursHH . $MinutesMM . ".png";
    #
    # Create the graph
    #
    @Args = ( "rrdtool graph $dstGraphFilenameAbs --start end-$GraphDuration --width 700 --end now --rigid --vertical-label Celcius --title  \"$srcFilename up to $HoursHH:$MinutesMM $DayDD$MonthMMM$Year\" DEF:Temperature=$srcFileAbs:Temperature:AVERAGE LINE2:Temperature#0000F0 >/dev/null" );
    if ($Debug eq "DEBUG") {print LOG "Going to @Args\n"};
    system(@Args) == 0 or die "ERROR: system @Args failed: $? $!\n";
    if ($? == -1)
    {
      print LOG "ERROR: failed to execute @Args\n $!\n";
    }
    elsif ($? & 127)
    {
      printf LOG "ERROR: @Args\n child died with signal %d, %s\n", ($? & 127),  ($? & 128) ? 'with' : 'without';
      sleep 2;
      exit 0;
    }
    else
    {
      if ($Debug eq "DEBUG2") { printf LOG "@Args\n child exited with value %d\n", $? >> 8 };
    }

    print "<Center><img src=\"http://www.kingtech.com.au/tempForCGI-BIN/$srcFilename-$GraphDuration-$Year$MonthMM$DayDD$HoursHH$MinutesMM.png\" alt=\"$srcFilename $GraphDuration $Year$MonthMM$DayDD $HoursHH:$MinutesMM\" border=\"0\"></Center>\n";


    # Now read the file that has the present temperature and print it into the HTTP page
    print "<Center>Temperature now is ";
    open(FILE,"<$srcFilePathAbs/$srcFilename.txt") ||print "can't open file $srcFilePathAbs/$srcFilename.txt $!\n";
    while (defined ($line = <FILE>)) {
      chomp $line;
      printf ("%.1f",$line);
    }
    close (FILE);
    print " degrees Celcius.  \n";

    print "</Center><br /><HR>\n";

  };

}, $RootDataDir;
