#!/usr/bin/perl -w

use strict;
use Tk;
use Tk::Balloon;
use Tk::NumEntry;
use Tk::ROText;
use Tk::Dialog;
use Statistics::Distributions;
use Statistics::Descriptive;

&gui;

sub gui {
    my $mw = MainWindow->new(-title=>'Competition Plotter');

    my $topfr = $mw->Frame->pack;
    my $botfr = $mw->Frame->pack(-fill=>'both',
				 -expand=>1
				 );

    my $inputfr = $topfr->Frame(-relief=>'groove',
			     -borderwidth=>2,
			     )->pack(-side=>'left',
				     -anchor=>'nw',
				     -fill=>'both',
				     );
    
    my $wordfile_label = $inputfr->Label(-text=>'Data File',
		                          )->grid(-row=>0,-column=> 0,-sticky=>'e');
    my $wordfile_lab_bal = $topfr->Balloon(-state=>'balloon',
                                        -background=>'white');
    my $wordfilehelp = "A tab-delimited file of competition values.  First column should be data labels (e.g. mouse number).  Competition pairs should be located in adjacent columns.";
    $wordfile_lab_bal->attach($wordfile_label,
                              -balloonmsg => $wordfilehelp,
                              );

    my $wordfile;
    my $wordfile_e = $inputfr->Entry(-state=>'normal',
				     -textvariable=> \$wordfile,
				     -width=>21,
				     )->grid(-row=>0,
					     -column=> 1,
					     -sticky=>'w',
					     -columnspan=>2,
					     );

    my %data;
    my $ymax;


    my $ymin = 0;
    $inputfr->Label(-text=>'Y-axis min',
		    )->grid(-row=>1,-column=>0,-sticky=>'e');
    $inputfr->NumEntry(-minvalue => 0,
		       -textvariable => \$ymin,
		       -width=>7,
		       )->grid(-row=>1,-column=>1,-sticky=>'w');

    $inputfr->Label(-text=>'Y-axis max',
		    )->grid(-row=>1,-column=>2,-sticky=>'e');
    $inputfr->NumEntry(-minvalue => 0,
		       -textvariable => \$ymax,
		       -width=>7,
		       )->grid(-row=>1,-column=>3,-sticky=>'w');

    my $ytick = 5;
    $inputfr->Label(-text=>'Y-axis ticks',
		    )->grid(-row=>2,-column=>0,-sticky=>'e');
    $inputfr->NumEntry(-minvalue => 0,
		       -textvariable => \$ytick,
		       -width=>7,
		       )->grid(-row=>2,-column=>1,-sticky=>'w');

    my $ptsize = 5;
    $inputfr->Label(-text=>'Point size',
		    )->grid(-row=>2,-column=>2,-sticky=>'e');
    $inputfr->NumEntry(-minvalue => 0,
		       -textvariable => \$ptsize,
		       -width=>7,
		       )->grid(-row=>2,-column=>3,-sticky=>'w');

    my $tickin = 5;
    $inputfr->Label(-text=>'Tick length Inside',
		    )->grid(-row=>3,-column=>0,-sticky=>'e');
    $inputfr->NumEntry(-minvalue => 0,
		       -textvariable => \$tickin,
		       -width=>7,
		       )->grid(-row=>3,-column=>1,-sticky=>'w');

    my $tickout = 0;
    $inputfr->Label(-text=>'Tick Length Outside',
		    )->grid(-row=>3,-column=>2,-sticky=>'e');
    $inputfr->NumEntry(-minvalue => 0,
		       -textvariable => \$tickout,
		       -width=>7,
		       )->grid(-row=>3,-column=>3,-sticky=>'w');

    my $width = 480;
    $inputfr->Label(-text=>'Plot width',
		    )->grid(-row=>4,-column=>0,-sticky=>'e');
    $inputfr->NumEntry(-minvalue => 0,
		       -textvariable => \$width,
		       -width=>7,
		       )->grid(-row=>4,-column=>1,-sticky=>'w');

    my $height = 300;
    $inputfr->Label(-text=>'Plot height',
		    )->grid(-row=>4,-column=>2,-sticky=>'e');
    $inputfr->NumEntry(-minvalue => 0,
		       -textvariable => \$height,
		       -width=>7,
		       )->grid(-row=>4,-column=>3,-sticky=>'w');

    my $pair = 50;
    $inputfr->Label(-text=>'Pair spacing',
		    )->grid(-row=>5,-column=>0,-sticky=>'e');
    $inputfr->NumEntry(-minvalue => 0,
		       -textvariable => \$pair,
		       -width=>7,
		       )->grid(-row=>5,-column=>1,-sticky=>'w');

    my $set = 100;
    $inputfr->Label(-text=>'Set spacing',
		    )->grid(-row=>5,-column=>2,-sticky=>'e');
    $inputfr->NumEntry(-minvalue => 0,
		       -textvariable => \$set,
		       -width=>7,
		       )->grid(-row=>5,-column=>3,-sticky=>'w');

   my $hbuf = 40;
    $inputfr->Label(-text=>'Horiz buffer',
		    )->grid(-row=>6,-column=>0,-sticky=>'e');
    $inputfr->NumEntry(-minvalue => 0,
		       -textvariable => \$hbuf,
		       -width=>7,
		       )->grid(-row=>6,-column=>1,-sticky=>'w');

    my $vbuf = 30;
    $inputfr->Label(-text=>'Vert buffer',
		    )->grid(-row=>6,-column=>2,-sticky=>'e');
    $inputfr->NumEntry(-minvalue => 0,
		       -textvariable => \$vbuf,
		       -width=>7,
		       )->grid(-row=>6,-column=>3,-sticky=>'w');

    my $databuf = 50;
    $inputfr->Label(-text=>'First data set buffer',
		    )->grid(-row=>7,-column=>0,-sticky=>'e');
    $inputfr->NumEntry(-minvalue => 0,
		       -textvariable => \$databuf,
		       -width=>7,
		       )->grid(-row=>7,-column=>1,-sticky=>'w');

    my $labels = 0;
    $inputfr->Label(-text=>'Data labels',
		    )->grid(-row=>7,-column=>2,-sticky=>'e');
    $inputfr->Checkbutton(-variable=>\$labels,
			  )->grid(-row=>7,-column=>3,-sticky=>'w');

    $inputfr->Button(-text=>"Exit",
		     -command=> sub { exit },
		     )->grid(-row=>8,
			     -column=>3,
			     -pady=>5,
			     );
    
    my $plotfr = $topfr->Frame(-relief=>'groove',
			    -borderwidth=>2,
			    )->pack(-side=>'right',
				    -anchor=>'nw',
				    -fill=>'both',
				    );    

    my $plot = $plotfr->Canvas(-background=>'white',
			       -height=>300,
			       -width=>480,
			       )->pack();

    $inputfr->Button(-text=>"Reset",
		     -command=> [\&reset, \$plotfr, \$plot, \%data, \$ymin, \$ymax, \$ytick, \$ptsize, \$width, \$height, \$pair, \$set, \$hbuf, \$vbuf, \$databuf, \$labels, \$tickin, \$tickout ],
		     )->grid(-row=>8,
			     -column=>0,
			     -pady=>5,
			     );

    $inputfr->Button(-text=>"Save Plot",
		     -command=> [\&saveplot, \$mw, \$plot],
		     )->grid(-row=>8,
			     -column=>2,
			     -pady=>5,
			     );
    
    $inputfr->Button(-text=>"Update plot",
		     -command=> [\&main, \$plotfr, \$plot, \%data, \$ymin, \$ymax, \$ytick, \$ptsize, \$width, \$height, \$pair, \$set, \$hbuf, \$vbuf, \$databuf, \$labels, \$tickin, \$tickout ],
		     )->grid(-row=>8,
			     -column=>1,
			     -pady=>5,
			     );

    my $textfr = $botfr->Frame(
			       )->pack(-fill=>'both',
				       -expand=>1,
				       );
    my $textwin = $textfr->Scrolled('ROText',
				    -height=>14,
				    -scrollbars=>'osoe',
				    -wrap=>'word',
				    )->pack(-fill=>'both',
					    -expand=>1,
					    );


    $inputfr->Button(-text=>'Load',
		     -command=> [ \&load, \$wordfile_e , \$mw, \%data, \$ymax, \$plotfr, \$plot, \$width, \$height, \$textwin ],
		     -borderwidth=>1,
		     -padx=> 0,
		     -pady=> 0,
		     )->grid(-row=>0
			     ,-column=>3
			     ,-sticky=>'w',
			     -padx=>3,
			     -pady=>5,
			     );

    $inputfr->Button(text=>"Calculate Stats",
		     -command=> [ \&stats, \$mw, \%data, \$textwin ],
		     )->grid(-row=>9,
			     -column=>0,
			     -pady=>5,
			     );
    $inputfr->Button(text=>"Save Stats",
		     -command=> [ \&savestat, \$mw, \$textwin ],
		     )->grid(-row=>9,
			     -column=>1,
			     -pady=>5,
			     );

    MainLoop;

}

sub stats {
    my ($mwref, $dataref, $textwinref) = @_;

    $$textwinref->delete('1.0','end');
    $$mwref->update;

    my %data = %{$dataref};
    my @xcat;
    my %pairdiff;
    my %pairname;
    foreach my $col (keys %data) {
	next if ($col % 2 == 1);
	my %temphash = %{$data{$col}};
	my $count = 1;
	foreach my $row (keys %temphash) {
	    if ($row == 0) {
		$xcat[$col] = $temphash{$row};
		next;
	    }

	    my $diff = $data{$col-1}{$row} - $data{$col}{$row};
	    my $colpair = $col-1 . "_" . $col;
	    $pairname{$colpair} = $data{$col-1}{0} . ' vs ' . $data{$col}{0};
	    $pairdiff{$colpair}{$count} = $diff;
	    $count++;
	}
    }
    foreach my $colpair (keys %pairdiff) {
	my %temphash = %{$pairdiff{$colpair}};
	my $stat = Statistics::Descriptive::Sparse->new();
	foreach my $count (sort keys %temphash) {
	    $stat->add_data($temphash{$count});
	}
	my $mean = $stat->mean;
	my $stdev = $stat->standard_deviation;
	my $count = $stat->count;

	my $dof = $count - 1;
	my $t = ($mean / ($stdev/sqrt($count)) );
	my $tprob1 = Statistics::Distributions::tprob($dof,$t);
	my $tprob2 = $tprob1 * 2;

	my $results = "$pairname{$colpair} Paired t-test (2-tailed)\n\tMean Difference\t$mean\n\tDF\t$dof\n\tt-value\t$t\n\tp-value\t$tprob2\n\n";
	&printlog($results,$textwinref);

    }

}

sub savestat {
    my $mwref = shift;
    my $mw = $$mwref;
    my $logwinref = shift;
# fix portability
    my $outfile = $mw->getSaveFile(-title=>'Save Results As');
    $outfile .= '.txt' if $outfile !~ /\.txt$/i;
    open(OUTFILE,">$outfile") or die "Can't open output file $outfile\n";
    print OUTFILE $$logwinref->get("1.0","end");
    close OUTFILE;
    $mw->messageBox(-title => 'Finished',
		    -message => 'Results Saved',
		    -type => 'OK');
}

sub printlog {
    my $line = shift;
    my $logwinref = shift;
    my $logwin = $$logwinref;
    $logwin->insert('end',$line);
    $logwin->update();
}

sub main {
    my ($plotfrref, $plotref, $dataref, $yminref, $ymaxref, $ytickref, $ptsizeref, $widthref, $heightref, $pairref, $setref, $hbufref, $vbufref, $databufref, $labelsref, $tickinref, $tickoutref) = @_;
    my %data = %{$dataref};
    my $ymin = $$yminref;
    my $ymax = $$ymaxref;
    my $ytick = $$ytickref;
    my $ptsize = $$ptsizeref;
    my $width = $$widthref;
    my $height = $$heightref;
    my $pair = $$pairref;
    my $set = $$setref;
    my $hbuf = $$hbufref;
    my $vbuf = $$vbufref;
    my $databuf = $$databufref;
    my $labels = $$labelsref;
    my $tickin = $$tickinref;
    my $tickout = $$tickoutref;
    
# clear canvas
    $$plotref->destroy if Tk::Exists($$plotref);
    $$plotref = $$plotfrref->Canvas(-width=>$width,
				-height=>$height,
				-background=>'white',
				)->pack();
    
# draw axes
    $$plotref->createLine( $hbuf,$vbuf, $hbuf,$height-$vbuf, $width-$hbuf,$height-$vbuf);


# draw y ticks
    for (my $c = 0; $c <= $ytick; $c++) {
	my $xstart = $hbuf - $tickout;
	my $xstop = $hbuf + $tickin;
	my $y = ((($height - ($vbuf*2)) / $ytick) * $c) + $vbuf;
	$$plotref->createLine($xstart,$y, $xstop,$y);
	my $yval = $ymax - ((($ymax - $ymin)/($ytick))*$c);
	if ($ymax / $ytick >= 1) {
	    $yval = int($yval+0.5);
	}
	else {
	    $yval = sprintf("%.1f",$yval);
	}
	my $offset = length($yval) * 3 + 5;
	$$plotref->createText($xstart-$offset,$y, -text=>"$yval");
    }

# plot data
    my @xcat;
    foreach my $col (sort keys %data) {
	my %temphash = %{$data{$col}};
	my $xval = ((($col) / 2 ) * ($pair + $set)) -$set + $hbuf + $databuf;
	my $lastx = ((($col - 2) / 2 ) * ($pair + $set)) + $hbuf + $databuf;
	foreach my $row (sort keys %temphash) {
#	    print "$row\t$col\t$temphash{$row}\n";
	    if ($row == 0) {
		$xcat[$col] = $temphash{$row};
		next;
	    }

	    next if ($col % 2 == 1);

	    my $datapoint = $temphash{$row};
	    my $yval = $vbuf + ($ymax-$datapoint) / ($ymax-$ymin) * ($height - (2*$vbuf) );
	    
	    $$plotref->createOval($xval-$ptsize/2,$yval-$ptsize/2, $xval+$ptsize/2, $yval+$ptsize/2, -fill=>'black');
	    $$plotref->createText($xval + ($ptsize/2) + 12,$yval, -text=>"$datapoint") if $labels;
	    
            # connect with line
	    my $lasty = $vbuf + ($ymax-$data{$col-1}{$row}) / ($ymax-$ymin) * ($height - (2*$vbuf) );
	    
	    $$plotref->createLine($xval,$yval, $lastx,$lasty);
	    
	    $$plotref->createOval($lastx-$ptsize/2,$lasty-$ptsize/2, $lastx+$ptsize/2,$lasty+$ptsize/2, -fill=>'white');
	    my $textoffset = length($data{$col-1}{$row}) * 5;
	    $$plotref->createText($lastx - ($ptsize/2) - $textoffset,$lasty, -text=>"$data{$col-1}{$row}") if $labels;
	}

	if ($col % 2 == 0) {
	    $$plotref->createText($xval,$height-$vbuf/2, -text=>"$xcat[$col]");
	}
	else {
	    my $labelx = ((($col - 1) / 2 ) * ($pair + $set)) + $hbuf + $databuf;
	    $$plotref->createText($labelx,$height-$vbuf/2, -text=>"$xcat[$col]");
	}
    }

}

sub load {
    my $entryblankref = shift;
    my $entryblank = $$entryblankref;
    my $mwref = shift;
    my $mw = $$mwref;
    my $dataref = shift;
    my %data = %{$dataref};
    my $ymaxref = shift;

    my $plotfrref = shift;
    my $plotref = shift;
    my $widthref = shift;
    my $heightref = shift;
    my $width = $$widthref;
    my $height = $$heightref;
    my $textwinref = shift;

# cleanup
    $$plotref->destroy if Tk::Exists($$plotref);
    $$plotref = $$plotfrref->Canvas(-width=>$width,
				-height=>$height,
				-background=>'white',
				)->pack();

    $$textwinref->delete('1.0','end');
    $$mwref->update;

    undef(%data);

# main
    my $file;
    if ($^O =~ /mswin/i) {
	my $opentypes = [
			 "{All files}     *           ",
			 "{PCL files}     {.pcl}      ",
			 "{Text files}    {.txt}      ",
			 ];
	$file = $mw->getOpenFile(-filetypes=>$opentypes);
    }
    else {
	$file = $mw->getOpenFile(-title=>'Load File');
    }
    if (defined $file and $file ne '') {
	$entryblank->delete(0, 'end');
	$entryblank->insert(0, $file);
	$entryblank->xview('end');
    }

    open(INFILE,$file) or die "Couldn't open input file $file\n";
    my $linecount = 0;
    while(<INFILE>) {
	chomp;
	my @line = split(/\t/);
	for (my $c = 1; $c <= $#line; $c++) {
	    $data{$c}{$linecount} = $line[$c];
	}
	$linecount++;
    }
    %{$dataref} = %data;
    
    my $max = 0;
    foreach my $col (keys %data) {
	my %temphash = %{$data{$col}};
	foreach my $row (keys %temphash) {
#	    print "$row\t$col\t$temphash{$row}\n";
	    next if $row == 0;
	    $max = $temphash{$row} if $max < $temphash{$row};
	}
    }
    $$ymaxref = $max + (0.05 * $max);
    
    if ($$ymaxref >= 15) {
	my $dialog = $mw->Dialog(-title => "Warning",
				 -text => 'Data contains high values, indicating it may not be transformed to log scale.  OK to proceed?',
				 -buttons => [qw/Yes No/],
				 -default_button => 'No',
				 );
	my $answer = $dialog->Show();
	if ($answer eq 'No') {
	    undef $file;
	    undef %data;
	    $entryblank->delete(0, 'end');
	    $$ymaxref = undef;
	    return;
	}
    }
}

sub reset {
    my ($plotfrref, $plotref, $dataref, $yminref, $ymaxref, $ytickref, $ptsizeref, $widthref, $heightref, $pairref, $setref, $hbufref, $vbufref, $databufref, $labelsref, $tickinref, $tickoutref) = @_;
    my %data = %{$dataref};
    $$yminref = 0;
#    my $ymax = $$ymaxref;
    $$ytickref = 5;
    $$ptsizeref = 5;
    $$widthref = 480;
    $$heightref = 300;
    $$pairref = 50;
    $$setref = 100;
    $$hbufref = 40;
    $$vbufref = 30;
    $$databufref = 50;
    $$labelsref = 0;
    $$tickinref = 5;
    $$tickoutref = 0;

    my $max = 0;
    foreach my $col (keys %data) {
	my %temphash = %{$data{$col}};
	foreach my $row (keys %temphash) {
#	    print "$row\t$col\t$temphash{$row}\n";
	    next if $row == 0;
	    $max = $temphash{$row} if $max < $temphash{$row};
	}
    }
    $$ymaxref = $max + (0.05 * $max);
}

sub saveplot {
    my $mwref = shift;
    my $mw = $$mwref;
    my $plotref = shift;
    my $plot = $$plotref;
    
    my $file = $mw->getSaveFile();

    $file .= '.ps' if $file !~ /\.ps$/i;

    print $file;

    return if $file eq '.ps';

    $plot->postscript(-file=>"$file");

    $mw->messageBox(-title => 'Finished',
		    -message => 'Plot Saved',
		    -type => 'OK');

}
