#!/usr/bin/perl
# vim:nowrap

use strict;
use warnings;

use Pod::Usage;
use Config::IniFiles;
use Statistics::Descriptive;
use Getopt::Long;

my $cfgfile = "boxplot.ini";
my $help = 0;
my $man  = 0;
my $gBlock  = "Global";
Getopt::Long::Configure ("bundling");
my $result = GetOptions( 
	"f|file=s"   => \$cfgfile,
	"b|block=s"  => \$gBlock,
	"h|help"     => \$help,
	"m|man"      => \$man,
) or pod2usage(2);
pod2usage(1)  if $help;
pod2usage({-exitval => 0, -verbose => 2})  if $man;
pod2usage({-message => "File $cfgfile not found", -exitval => 2})  unless -e $cfgfile;

die "need cfg file!" unless defined $cfgfile;

my %cfg;
tie %cfg, 'Config::IniFiles', ( -file => $cfgfile, -allowcontinue => 1 );

my $gTitle    = $cfg{$gBlock}{title}     || ' ';
my $gXlabel   = $cfg{$gBlock}{xlabel}    || ' ';
my $gYlabel   = $cfg{$gBlock}{ylabel}    || ' ';
my $gTerminal = $cfg{$gBlock}{terminal}  || 'pdf enhanced color';
my $gOutfile  = $cfg{$gBlock}{outfile}   || 'out.pdf';
my $gKeyPos   = $cfg{$gBlock}{keypos}    || 'top right';
my @gBlocks   = split(/,\s*/, $cfg{$gBlock}{blocks}) ;
my $gLineTmpl = $cfg{$gBlock}{line_tmpl} || qq('FILENAME' u 1:3:2:6:5 w candlesticks t 'TITLE' whiskerbars 0.5 lt LT, '' u 1:4:4:4:4 w candlesticks lt LT notitle);
my $gVerbose  = $cfg{$gBlock}{verbose}   || 0;

my @gnuplotlines;
my $i = 1;
foreach (@gBlocks){
    push @gnuplotlines, getGnuplotLine($i++,$_);
}

my $lines = join( ", \\\n", @gnuplotlines);

my $s =<<EOT
set key $gKeyPos
set xrange [0:$i]
set xlabel "$gXlabel"
set ylabel "$gYlabel"
set title "$gTitle"
unset xtics
set terminal pdf enhanced color
set output "$gOutfile"
set boxwidth 0.75
plot $lines
pause -1
EOT
;

open GP, '| gnuplot' or die $!;
print GP $s;

sub getGnuplotLine{
    my $xcoor = shift;
    my $block = shift;
    my $file  = $cfg{$block}{filename}  || die "No Filename for $block";
    my $title = $cfg{$block}{title}     || ' ';
    my $ls    = $cfg{$block}{linestyle} || $xcoor; 
    my $col   = $cfg{$block}{column} ;
    $col = 0 unless defined $col;
    
    if($gVerbose){
        print "reading file `$file' col `$col' title `$title'\n";
    }
    
    my @data;
    open F,"<$file" or die $!;
    while(<F>){ chomp; @_ = split /\s+/; push @data, $_[$col] }
    my $csp   = join ' ', getCandleStickParams($xcoor,\@data);
    return fillLineTemplate($gLineTmpl,".dat$xcoor",$title,$csp,$ls);
}

sub fillLineTemplate{
    my $tmpl     = shift;
    my $filename = shift;
    my $title    = shift;
    my $data     = shift;
    my $lt       = shift;

    $_ = $tmpl;
    s/FILENAME/$filename/g;
    s/TITLE/$title/g;
    s/LT/$lt/g;
    `echo '$data' > $filename`;
    return $_;
}

sub getCandleStickParams
{
    my $xcoor = shift;
    my @c = @{shift()};
    my $s = Statistics::Descriptive::Full->new();
    $s->add_data(@c);
    my $median   = $s->median();
    my $quart25  = $s->percentile(25);
    my $quart75  = $s->percentile(75);

    my $iqr      = $quart75 - $quart25;

    # smallest non-outlier/largest non-outlier
    my $sno = undef;
    my $lno = undef;
    my @sc  = sort {$a <=> $b} @c;
    foreach (@sc){
        if($_ >  $quart25 - 1.5 * $iqr){
            $sno = $_;
            last;
        }
    }
    @sc = reverse @sc;
    foreach (@sc){
        if($_ <  $quart75 + 1.5 * $iqr){
            $lno = $_;
            last;
        }
    }
    print "Candlestick Params: ", join ', ',  ($sno, $quart25, $median, $quart75, $lno), "\n" if($gVerbose);
    return ($xcoor, $sno, $quart25, $median, $quart75, $lno)
}

__END__

=head1 NAME

boxplot2.pl - print box plots for data-columns in files

=head1 SYNOPSIS

boxplot2.pl [options]

  Options:
    -f | --file configfile        load this configuration file (required)
    -b | --block block            use this block instead of [Global]
    -h | --help                   this message
    -m | --man                    man page

=head1 DESCRIPTION

This script allows you to generate a plot with several boxplots in it.
The necessary values are derived from columns in data files.
It relies on Gnuplot to plot the files.

The script is controlled via a INI-Style config file.
There is a global section and a section for each boxplot.
Most values have reasonable defaults and can be dropped.

=head1 EXAMPLE INI-File

        [Global]
        title    = Method 1 vs. Method 2
        xlabel   = Method
        ylabel   = Accuracy
        keypos   = top left
        blocks   = b1, b2
        outfile  = out.pdf
        terminal = pdf enhanced color
        verbose  = 1
        line_tmpl = 'FILENAME' u 1:3:2:6:5 w candlesticks t 'TITLE' whiskerbars 0.5 lt LT, '' u 1:4:4:4:4 w candlesticks lt LT notitle

        [b1]
        filename  = data.txt
        column    = 0
        title     = Method 1
        linestyle = 1

        [b2]
        filename  = data.txt
        column    = 2
        title     = Method 2
        linestyle = 3

=cut

