#!/usr/bin/env perl

use File::Basename;
use strict;
die "[Error (createGraphs): Incorrect number of arguments]\n" unless ($#ARGV >= 1);

my $format_file = $ARGV[0]; 
my $outputdir = $ARGV[1]; 
my $start_date = $ARGV[2];

my $graph_file_name; 
my $graph_title; 
my $graph_ylabel; 
my @graph_keys; 
my @data_files; 
my @graph_key_labels;

my $format_file_name = fileparse($format_file, ("\.graph"));

my $default_key_file = "$format_file_name.perfkeys";
my $default_data_filename = "$format_file_name.dat";
my $data_file = "$outputdir/$default_data_filename";
my $errors_file = "$outputdir/$format_file_name.errors";
my $fatal_errors = 0;
my $custom = 0;
my $custom_start_date = 0;
my $src_file = "$format_file_name.chpl";

# change name of processGraphFile and w/e it calls~~~~~
# set defaults for making the .gif
# continue on to process the format file and make the graphs
&setDefaults;
&processGraphFile;


# auxilliary functions

# remove white space surrounding a string
sub trim($) {
    my $string = shift;
    $string =~ s/^\s+//;
    $string =~ s/\s+$//;
    return $string;
}

# get start date (date of first performance run)
sub getStartDate {
    my $data_file_temp = $_[0];
    open STATS, "$data_file_temp" or die "[Error (createGraphs): can't open .dat file '$data_file_temp' $!]";
    # Assume the first line is a comment with the key names
    my $header_line = <STATS>;
    my $first_test = <STATS>;
    ### my @headers = parse_line('\t', 0, $first_date);
    my @fields = split(/\t/, $first_test);
    # If the date of the first test timed out, it will be in a comment, but
    #  we still want to use that date
    if (index(@fields[0], "#") == 0) {
        return &trim(substr(@fields[0],1));
    } else {
        return @fields[0];
    }
}

sub getMinDate {
    my ($date1, $date2) = @_;
    my ($mon1, $mday1, $year1) = split(/\//, $date1);
    my ($mon2, $mday2, $year2) = split(/\//, $date2);
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,@rest) = localtime time;
    $mon += 1;
    $year -= 100;

    if ($year1 > $year) {
	$year1 += 1900;
    } else {
	$year1 += 2000;
    }

    if ($year2 > $year) {
	$year2 += 1900;
    } else {
	$year2 += 2000;
    }

    my $result;

    if ($year1 < $year2) {
	$result = $date1;
    } elsif ($year1 > $year2) {
	$result = $date2;
    } else {
	if ($mon1 < $mon2) {
	    $result = $date1;
        } elsif ($mon1 > $mon2) {
	    $result = $date2;
   	} else {  
	    if ($mday1 < $mday2) {
		$result = $date1;
	    } else {
		$result = $date2;
	    }
        }
    }

    return $result;

}


# setting default arguments to makeGraph 
sub setDefaults {
    if (-e $src_file) {
        $default_key_file = "$format_file_name.perfkeys";
        open KEYS, "$default_key_file" or die "[Error (createGraphs): can't open .perfkeys file '$default_key_file' $!]";
        my @keys = <KEYS>;
        close(KEYS);
        foreach  my $key (@keys) {
            my $real_key = &trim($key);
            # chomp($key);
            if (substr($real_key,0,1) ne "#") {
                push(@graph_keys, $real_key);
            } else {
                # ignore comments unless they specify a .dat file
                my $comment = &trim(substr($real_key,1));
                if (index($comment,"file:") == 0) {
                    my @crap = split(/\s+/, $comment);
                    $default_data_filename = @crap[1];
                    $data_file = "$outputdir/$default_data_filename";
                }
            }
        }
    }
    $graph_file_name = $format_file_name;	
    $graph_title = "$graph_file_name Performance";
    $graph_ylabel = "";
}


sub processGraphFile {
    open FORMAT, "$format_file" or die "[Error (createGraphs): can't open .graph file '$format_file' $!]";

    my $use_default = 1;

    while (my $line = <FORMAT>) {
        chomp($line);
        my @words = (split / /, $line);
        # each 'perfkeys:' line starts a new graph
        if (@words[0] eq "perfkeys:") {
	    my $graph_keys_line = join(" ", @words[1..$#words]);
	    @graph_keys = split(/, /, $graph_keys_line);

    	    $line = <FORMAT>;
	    chomp($line);
	    @words = (split / /, $line);
	    while (@words[0] && (@words[0] ne "perfkeys:")) {
	        if (@words[0] eq "files:") {
		    $use_default = 0;
	            my $data_files_line = join(" ", @words[1..$#words]);
		    @data_files = split(/, /, $data_files_line);
	        } elsif (@words[0] eq "graphname:") {
	            $graph_file_name = @words[1];
	        } elsif (@words[0] eq "graphtitle:") {
		    $graph_title = join(" ", @words[1..$#words]);
	        } elsif (@words[0] eq "ylabel:")  {
		    $graph_ylabel = join(" ", @words[1..$#words]);
	        } elsif (@words[0] eq "graphkeys:") {
		    my $graph_key_labels_line = join(" ", @words[1..$#words]);
		    @graph_key_labels = split(/, /, $graph_key_labels_line);
		} elsif (@words[0] eq "startdate:") {
		    $custom_start_date = 1;
		    $start_date = @words[1];
                } elsif (@words[0] eq "#") {
                } else {
		    print "[Error (createGraphs): improper format of $format_file (@words)]\n";
		    exit 1;
	        } 
	        $line = <FORMAT>;
                chomp($line);
	        @words = (split / /, $line);
	    }
            if (($use_default == 0) && ($#graph_keys != $#data_files)) {
                print "[Error (createGraphs): files do not match up with keys, $#graph_keys keys and $#data_files files]\n";
                exit 1;
            }
            $custom = 1;
            &makeGraph($start_date, $use_default, $graph_file_name, $graph_title, $graph_ylabel, @graph_keys);
        } elsif (!@words[0] || (@words[0] eq "#"))  {
            # ignore comments and blank lines
        } else {
            print "[Warning (createGraphs): Ignoring stray format line: $line]\n";
        }
    }
    if (!$custom) {
        # empty graph file
        &makeGraph($start_date, $use_default, $graph_file_name, $graph_title, $graph_ylabel, @graph_keys);
    }
}

# makeGraph outputs a .gif in perfdir (by default ./perfdat/<machine>) via gnuplot
sub makeGraph {
    if ($#graph_keys < 0) {
        return;
    }
    my ($start_date, $use_default, $graph_file_name, $graph_title, $graph_ylabel, @graph_keys) = @_;
    my @real_data_files;
    my $default_data_file;
    if ($use_default == 0) {
        foreach my $data_file (@data_files) {
            my $real_data_file;
            my $ri = rindex($data_file, "/");
            if ($ri > -1) {
                if (substr($outputdir,0,1) eq "/") {
                    # absolute path (prepend path and strip relative path))
                    $real_data_file = $outputdir."/".substr($data_file,$ri);
                } else {
                    # relative path (find .dat file in the subdir)
                    $real_data_file = substr($data_file,0,$ri)."/".$outputdir."/".substr($data_file,$ri);
                }
            } else {
                $real_data_file = $outputdir."/".$data_file;
            }
            push(@real_data_files, $real_data_file);
        }
    } else {
        my $ri = rindex($graph_file_name, ".graph");
        if ($ri > -1) {
            $default_data_file = $outputdir."/".substr($graph_file_name,$ri,length(".graph")).".dat";
        } else {
            $default_data_file = $outputdir."/".$graph_file_name.".dat";
        }
    }

    if (($custom_start_date == 0) && ($start_date eq "")) {
        if ($use_default) {
            $start_date = &getStartDate($default_data_file);
        } else {
            my ($sec,$min,$hour,$mday,$mon,$year,@rest) = localtime time;
            $mon += 1;
            $mday += 1;
            $year -= 100;
            $start_date = "$mon/$mday/$year";
            foreach my $f (@real_data_files) {
                $start_date = &getMinDate(&getStartDate($f), $start_date);
            }
        }
    }

    if (! -d $outputdir) {
        # This output directory may not exist if the .dat files are from
        #  different directories
        # NOTE: mkpath() is deprecated in newer versions of File::Path
        #  and replaced by make_path()
        use File::Path qw(mkpath);
        mkpath("$outputdir");
    }
    my $gpl_file = "$outputdir/$format_file_name.gpl";

    open GNUPLOT_COMMANDS, ">$gpl_file" or die "[Error (createGraphs): can't open .gpl file '$gpl_file' for creating $!]";

    print GNUPLOT_COMMANDS "set terminal gif size 1200\n"; 
    print GNUPLOT_COMMANDS "set size ratio 0.33\n"; # figure out how to adjust this setting to x-axis range?
    print GNUPLOT_COMMANDS "set xdata time\n";
    print GNUPLOT_COMMANDS "set timefmt \"%m/%d/%y\"\n";
    print GNUPLOT_COMMANDS "set format x \"%m/%d/%y\"\n";
    print GNUPLOT_COMMANDS "set xlabel \"date (MM/DD/YY)\"\n";
    print GNUPLOT_COMMANDS "set key left\n";
    print GNUPLOT_COMMANDS "set ylabel \"$graph_ylabel\"\n";
    print GNUPLOT_COMMANDS "set xrange [\"$start_date\":*]\n";
    print GNUPLOT_COMMANDS "set yrange [0:*]\n";  
    print GNUPLOT_COMMANDS "set title \"$graph_title\"\n";
    print GNUPLOT_COMMANDS "set output \"$outputdir/$graph_file_name.gif\"\n";
    print GNUPLOT_COMMANDS "plot \\\n";

    my $graph_key_index = 0; 
    my $line_type;
    foreach my $graph_key (@graph_keys[0..$#graph_keys]) {
        my $real_data_file, $data_file;
	my $key_file = $default_key_file;
	if ($use_default == 0) {
	    # need to re-assign $data_file, $key_file
	    $data_file = "@data_files[$graph_key_index]";
            $real_data_file = "@real_data_files[$graph_key_index]";
            $key_file = $data_file;
            my $ri = rindex($key_file, ".dat");
            substr($key_file,$ri,length(".dat")) = '.perfkeys' if $ri > -1;
        } else {
            $real_data_file = $default_data_file;
        }

	# if the derived $key_file does not exist, then use the default
        unless (-e $key_file) {
            print "[Warning (createGraphs): '$key_file' does not exist, using default perfkeys file '$default_key_file']\n";
            $key_file = $default_key_file;
        }
	open KEYS, "$key_file" or die "[Error (createGraphs): can't open .perfkeys file '$key_file' $!]";
        my @keys;
	my @tmp_keys = <KEYS>;
	close (KEYS);
	foreach my $key (@tmp_keys) {
            my $real_key = &trim($key);
            # chomp($key);
            if (substr($real_key,0,1) ne "#") {
                push(@keys, $real_key);
            } else {
                # ignore comments unless they specify a .dat file
                my $comment = &trim(substr($real_key,1));
                if (index($comment,"file:") == 0) {
                    if ($use_default == 1) {
                        my @crap = split(/\s+/, $comment);
                        $real_data_file = @crap[1];
                    }
                }
            }
	}

        $line_type = ($graph_key_index % 8) + 1;
        my $key_index = 0;
 	while (($key_index <= $#keys) && ($graph_key ne @keys[$key_index])) {
	    if ($key_index == $#keys) {
                print "[Error (createGraphs): number of keys does not match .perfkeys file]\n";
		exit 1;
	    }
            $key_index++;
	}
 	my $column_index = $key_index + 2;
	
	if ($#graph_keys == $#graph_key_labels) {
	    $graph_key = @graph_key_labels[$graph_key_index];
	}

	if ($graph_key_index ne $#graph_keys) {
	    print GNUPLOT_COMMANDS "\t\"$real_data_file\" using 1:$column_index title '$graph_key' with linespoints lt $line_type pt 4, \\\n";
	} else {
	    print GNUPLOT_COMMANDS "\t\"$real_data_file\" using 1:$column_index title '$graph_key' with linespoints lt $line_type pt 4\n";
	}
        $graph_key_index++;
    }

    close(GNUPLOT_COMMANDS);
    my $succeed_gnuplot = system("gnuplot $gpl_file");
    if ($succeed_gnuplot != 0) {
	print "[Error (createGraphs): 'gnuplot' command failed for $format_file]\n";
        exit 1;
    }

    # unlink $gpl_file or warn "[Warning (createGraphs): Could not remove $gpl_file: $!]";
    # unlink $errors_file or warn "[Warning (createGraphs): Could not remove $errors_file: $!]";

}
