#!/usr/local/bin/perl
#
#  Copyright (c) 2004, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
#  All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are met:
#
#   * Redistributions of source code must retain the above copyright notice,
#     this list of conditions and the following disclaimer.
#   * Redistributions in binary form must reproduce the above copyright notice,
#     this list of conditions and the following disclaimer in the documentation
#     and/or other materials provided with the distribution.
#   * Neither the name of SWITCH nor the names of its contributors may be
#     used to endorse or promote products derived from this software without
#     specific prior written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
#  POSSIBILITY OF SUCH DAMAGE.
#
#  $Author: peter $
#
#  $Id: GenGraph.pl 27 2005-04-20 13:50:06Z peter $
#
#  $LastChangedRevision: 27 $

use strict;
use warnings;
use RRDs;
use Sys::Syslog; 
Sys::Syslog::setlogsock('unix');

######################################
#
# Configuration: 
# The only parameter to set:

use lib "/usr/local/libexec/nfsen";

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

use NfConf;
use Log;

my $VERSION = '$Id: GenGraph.pl 27 2005-04-20 13:50:06Z peter $';

sub SendFile {
	my $file = shift;

	my $buf;
	open(GIFILE,$file) || syslog 'err', "Cannot open gif file: $!", return;;
	while (read(GIFILE, $buf, 8192)) {
		print $buf;
	}

} # End of SendFile


if ( !NfConf::LoadConfig() ) {
	die "$Log::ERROR\n";
}

openlog("GenGraph", 'cons,pid', $NfConf::syslog_facility);

if ( scalar @ARGV != 14 ) {
	syslog 'err', "Argument error";
	syslog 'err', "Expect: profile source[:source] proto type, tstart, tend, tleft, tright, width, heigh, light, logscale, linegraph";
	closelog();
	exit;
}

# Arguments
my $profile 	= shift;	# profile name
my $sources 	= shift;	# ':' separated list of sources
my $proto   	= shift;	# proto type: 'any', 'TCP', 'UDP', 'ICMP', 'other'
my $type    	= shift;	# 'flows', 'packets', 'traffic'
my $pstart		= shift;	# profile start time - UNIX format
my $tstart		= shift;	# start time - UNIX format
my $tend		= shift;	# end time - UNIX format
my $tleft   	= shift;	# left time of marker - UNIX format; 0 is no marker
my $tright  	= shift;	# right time of marker - UNIX format; 0 is no marker
my $width		= shift;	# width of graph
my $heigh		= shift;	# heigh of graph
my $light		= shift;	# light version ( small graphs ) - no title no span window
my $logscale	= shift;	# linear or log y-Axis
my $linegraph	= shift;	# linear or log y-Axis



if ( ! -f "$NfConf::PROFILESTATDIR/$profile/profile.dat" ) {
	syslog 'err', "Profile '$profile' unknown";
	closelog();
	exit;
}

if ( $sources eq '@EMPTY' ) {
	SendFile("$NfConf::HTMLDIR/EmptyGraph.gif");
	return;
}

# generate the title: e.g. flows -> Flows/s
my $title = $type eq 'traffic' ? "bits/s" : "$type/s";
$title =~ s/^(\w)/\u$1/;

my $ds_extension;
if ( $proto eq 'any' ) {
	$title    .= " any protocol";
	$ds_extension = '';
} else {
	$title    .= " proto $proto";
	$ds_extension = "_" . lc $proto;
}

my $datestr;
if ( $tleft ) {
	$datestr = scalar localtime($tleft);
} else {
	$datestr = scalar localtime($tstart) . " - " . scalar localtime($tend);
}

my @DEFS = split ':', $sources;

my @rrdargs = ();
push @rrdargs, "-";	# output graphics to stdout

foreach my $def ( @DEFS ) {
	if ( $type eq 'traffic' ) {
		push @rrdargs, "DEF:tmp${def}=$NfConf::PROFILESTATDIR/$profile/${def}.rrd:${type}${ds_extension}:AVERAGE";
		push @rrdargs, "CDEF:$def=tmp${def},8,*";
	} else {
		push @rrdargs, "DEF:$def=$NfConf::PROFILESTATDIR/$profile/${def}.rrd:${type}${ds_extension}:AVERAGE";
	}
}
push @rrdargs, "--logarithmic" if $logscale;
push @rrdargs, "--title", "$datestr $title" unless $light;
push @rrdargs, "--vertical-label", "$title" unless $light;
push @rrdargs, "--no-minor", if $light;
push @rrdargs, "--no-legend", if $light;
push @rrdargs, "--start",  "$tstart";
push @rrdargs, "--end",  "$tend";
push @rrdargs, "-w";
push @rrdargs, "$width";
push @rrdargs, "-h";
push @rrdargs, "$heigh";

my $def = shift @DEFS;
my $HasLabel = $light ? "" : ":$def";

# graph outside profile boundary? - grayout time before profile start
if ( !$light && ($tstart < $pstart) ) {
	push @rrdargs, "CDEF:outofdata=$def,POP,TIME,$pstart,LE,INF,UNKN,IF";
	push @rrdargs, "AREA:outofdata#DDDDDD";
}

# mark time window if tleft != tright
if ( !$light && ($tright - $tleft) != 0 ) {
	push @rrdargs, "CDEF:background=$def,POP,TIME,$tleft,GT,TIME,$tright,LE,*,INF,UNKN,IF";
	push @rrdargs, "AREA:background#B1FFA1";
}


if ( $linegraph ) {
	# Create a line graph
	push @rrdargs, "LINE1:$def$NfConf::sources{$def}{'col'}${HasLabel}";
	foreach my $def ( @DEFS ) {
		$HasLabel = ":$def" unless $light;
		push @rrdargs, "LINE1:$def$NfConf::sources{$def}{'col'}${HasLabel}";
	}
} else {
	# create a stacked graph
	push @rrdargs, "AREA:$def$NfConf::sources{$def}{'col'}${HasLabel}";
	foreach my $def ( @DEFS ) {
		$HasLabel = ":$def" unless $light;
		push @rrdargs, "STACK:$def$NfConf::sources{$def}{'col'}${HasLabel}";
	}
}

if ( $tleft ) {
	push @rrdargs, "VRULE:$tleft#000000";
}

my ($averages,$xsize,$ysize) = RRDs::graph( @rrdargs );
	
if (my $ERROR = RRDs::error) {
	syslog 'err', "$ERROR";
	syslog 'err', "Arg: '$profile', '$sources', '$proto', '$type', '$pstart', '$tstart', '$tend', '$tleft', '$tright', '$width', '$heigh', '$light', '$logscale', '$linegraph'";
	foreach my $arg ( @rrdargs ) {
		syslog 'err', "RRD '$arg'";
	}
	SendFile("$NfConf::HTMLDIR/ErrorGraph.gif");
} 
closelog();

