#!/usr/bin/perl -w
require 5.003;
use strict;

# plots traces labeled with label_results
# see also: label_results, report_results

if (`pwd` =~ 'ReportGen') {
	use lib '..';
}

use ReportGen::Opts;
use ReportGen::Globs;
use ReportGen::ObjDbase;

require ReportGen::Plot;
require ReportGen::Line;


# Configuration

my %Opts = (
	out_name => undef(),
	sort_by => undef(),
	plot_title => undef(),
	plotter_terminal => undef(),
	plotter => undef(),
	plotter_opts => undef(),
);
my %SavedOpts = %Opts;


# globals

my $Meas;     # what measurement to plot
my $IFName;

my ($MeasPos, $MeasType);
my ($SortPos);
my (@LineLabels, @LineTypes, @LineNames);
my $LabelWidthMax = -10;
my $Plot;


&init();
exit(&main());

sub main {

	&scanLineLabels();

	$Plot = new ReportGen::Plot(join(' ', $0, @ARGV));

	&setXLabel();
	&setYLabel();
	&setXTics();
	&setTitle();
	&setOther();
	&addLines();

	&setTerminal($Opts{plotter_terminal});
	&setOutput($Opts{out_name});

	&plot();
	return 0;
}

sub scanLineLabels {

	my @lines = ();
	my %vendors = ();
	my $typeCount = 0;

	#system("jove $IFName") if $Opts{plot_title} =~ /Median/;
	my $IF = new FileHandle("<$IFName") or die("$0: cannot open $IFName; $!\n");	
	while (<$IF>) {
		next if /^\#/;
		next if /^\s*$/;
		chomp;

		my ($fields, $name) = ($_ =~ /^\s*(.*)\s*\"([^\"]*)\"$/);
		die("$0: cannot parse line: `$_', stopped") unless defined $fields && defined $name;

		my ($vendor) = ($name =~ /^([^-]+)/);
		die($name) unless defined $vendor;
		$vendors{$vendor} = &VendType($vendor) unless defined $vendors{$vendor};

		my @fields = split /\s+/, $fields;
		push @lines, [ @fields, $vendors{$vendor}, $name ];

		$LabelWidthMax = length($fields[0]) if length($fields[0]) > $LabelWidthMax;
	}

	@lines = sort cmpLines grep { knownLine($_) } @lines if defined $SortPos;
	@LineLabels = map { $_->[0] } @lines;
	@LineTypes = map { $_->[$#{$_}-1] } @lines;
	@LineNames = map { $_->[$#{$_}] } @lines;
}

sub setXLabel {
	$Plot->xlabel_qw('');
}

sub setYLabel {
	$Plot->ylabel_qw($MeasType);
}

sub setXTics {
	$Plot->xtics('rotate') if @LineLabels > 5;
	$Plot->tics('x',
		map { $LineNames[$_], $_ } 0 .. $#LineNames);
}

sub setTitle {
	my $title = $Opts{plot_title};
	$Plot->title($title) if defined $title;
}

sub setOther {
	$Plot->range('x', -1, scalar @LineLabels);
	$Plot->range('y', 0);
	$Plot->set('size 1,0.85');
	$Plot->set("bmargin $LabelWidthMax/2") if @LineLabels > 5;
	$Plot->data('style boxes');
	$Plot->set('boxwidth 0.75');
	$Plot->grid();
	#$Plot->timestamp();
}

sub addLines {
	# plot each line separately so that they appear in different colors
	my $count = 0;
	for (my $li = 0; $li <= $#LineLabels; ++$li) {
		my $llabel = $LineLabels[$li];
		my $lt = $LineTypes[$li];
		my $line = new ReportGen::Line;
		my $filter = "grep '^$llabel\[[:space:]]' $IFName";
		$line->data("<$filter");
		$line->using($count, "\$$MeasPos");
		$line->with("boxes lt $lt");
		$line->title('');
		$Plot->line($line);
		$count++;
	}
}

sub setTerminal {
	my $term = shift;
	$Plot->terminal($term) if $term;
}

sub setOutput {
	my $fname = shift;
	$Plot->output($fname) if defined $fname;
}

sub plot {
	if (my $fname = $Plot->ofile()) {
		warn("$0: plotting: `$fname'\n");
	}
	#warn($Plot->image());
	$Plot->plot();
}

sub cmpLines {
	die('cmpLines') unless defined $SortPos;
	return cmpFields($a->[$SortPos-1], $b->[$SortPos-1]);
}

sub knownLine {
	my $line = shift;
	die('knownLines') unless defined $SortPos;
	return $line->[$SortPos-1] =~ /^\d/;
}

sub cmpFields($$) {
	my ($x, $y) = @_;
	return $x <=> $y if $x =~ /^\d/ && $y =~ /^\d/;
	return $x cmp $y;
}

sub getObjPos {
	my ($fname, $name) = @_;
	
	open(IF, "<$fname") or die("$0: cannot open `$fname': $!\n");
	my $firstLine = <IF>;
	close(IF);

	my @names = split(/\s+/, $firstLine);
	die("$0: `$fname' has unknown file format\n") 
		unless @names && $names[0] =~ s/^#//;

	my $pos = 1;
	foreach my $n (@names) {
		return $pos if $n eq $name;
		$pos++;
	}

	#die("$0: `$fname' has no object named `$name'\n");
	return undef();
}

sub init {
	my @params = ();
	die(&usage()) unless &ParseOpts(\%Opts, \@params, @ARGV) && @params == 2;
	die("plotter must be specified\n" . &usage()) unless $Opts{plotter};
	$ReportGen::Plot::Plotter = $Opts{plotter};
	$ReportGen::Plot::Plotter .= ' ' . $Opts{plotter_opts}
		if $Opts{plotter_opts};
	($Meas, $IFName) = @params;
	$MeasType = &ObjName2Type($Meas);
	die("$0: unknown object `$Meas'\n") unless $MeasType;

	$MeasPos = getObjPos($IFName, $Meas);
	die("$0: `$IFName' has no object named `$Meas'\n") unless defined $MeasPos;

	my $sortField = $Opts{'sort_by'};
	if (defined $sortField) {
		$SortPos = getObjPos($IFName, $sortField);
		die("$0: cannot sort by `$sortField', not in `$IFName'\n") unless defined $SortPos && $SortPos > 0;
	}	
}

sub usage {
	return "usage: $0 [options] <object> <file_name>\n" . &Opts2Str(\%SavedOpts);
}


syntax highlighted by Code2HTML, v. 0.9.1