#!/usr/bin/perl -w
#
#
use strict;
use Image::Magick;
my $usage = "Usage: $0 <infile.txt> <out.png>\n";
my $infile = shift or die $usage;
my $outfile = shift or die $usage;
my $font;
#my %matrix = &readData($infile);
my @dataArray = &readData($infile);
my $matrixSize = 1000;
#
# Determine the data size.
#
my $dataSize = 0;
foreach my $rec (@dataArray) {
   $dataSize = $rec->{X} if ($rec->{X} > $dataSize);
   $dataSize = $rec->{Y} if ($rec->{Y} > $dataSize);
   }
my $scale = int($matrixSize / $dataSize);
$matrixSize = $dataSize * $scale;
$matrixSize = $dataSize if ($dataSize > $matrixSize);
my $xOrig = int($matrixSize/5.5);
my $yOrig = $xOrig;
my $cmapAllowance = $xOrig + int(2.2*$scale);
#print("Data size: $dataSize\n");
#print("Image size: $matrixSize\n");
#print("Scale: $scale\n");
#print("Drawing...\n");
my $image = &initGraphics($matrixSize+$xOrig+$cmapAllowance,$matrixSize+$yOrig);
#
# Draw the matrix.
#
foreach my $rec (@dataArray) {
   my $hexColor = &selectColor($rec->{VALUE});
   print("$rec->{X}-1, $rec->{Y}-1\n") if ($rec->{Y} == 858);
   &drawSquare($image, $xOrig, $yOrig, $rec->{X}-1, $rec->{Y}-1, $hexColor);
   &drawSquare($image, $xOrig, $yOrig, $rec->{Y}-1, $rec->{X}-1, $hexColor);
   }
#
# Draw the leading diagonal.
#
for (my $i=0; $i<=$dataSize; $i++) {
   &drawSquare($image, $xOrig, $yOrig, $i, $i, '#ff0000');
   }
#
# Draw the axis labels.
#
my $i = 0.5;
foreach my $label (&getNames($dataSize, @dataArray)) {
   my $x = $xOrig + $scale*$i;
   my $y = $yOrig + $scale*$i++;
   &drawLabel($image, $label, $x, 'X');
   &drawLabel($image, $label, $y, 'Y');
   }
#
# Symbolic names
#
#&drawLines($image, $matrixSize, 11);
#&drawLines($image, $matrixSize, 21);
#&drawLines($image, $matrixSize, 25);
#&drawLines($image, $matrixSize, 29);

#
# Draw the colormap key.
#
&drawColormapKey($image, $xOrig+$matrixSize+$scale, $yOrig);
#
# Save the file.
#
$image->Crop('0x0');
if ($outfile =~ /\.png$/) {
   #my $r = $image->Write(filename=>"png8:$outfile");
   my $r = $image->Write(filename=>$outfile);
   warn $r if $r;
   }
else {
   $image->Write(filename=>$outfile);
   }
undef $image;

sub readData {
   my ($infile) = @_;
   #print("Reading...\n");
   open(IN, $infile) or die "Cannot open $infile\n";
   my @dataArray = ();
   while (<IN>) {
      chomp;
      my ($xname, $x, $yname, $y, $value1) = split(/\s+/);
      my $rec = {
         XNAME => $xname,
         YNAME => $yname,
         X => $x,
         Y => $y,
         VALUE => $value1,
         };
      push(@dataArray, $rec);
      }
   close(IN);
   return @dataArray;
   }

sub getNames {
   my ($dataSize, @dataArray) = @_;
   my @names = ();
   foreach my $rec (@dataArray) {
      $names[0] = $rec->{XNAME} if ($rec->{X} == 1);
      $names[$rec->{Y}-1] = $rec->{YNAME};
      last if ($rec->{X} != 1);	# bail out
      }
   return @names;
   }

sub initGraphics {
   my ($width, $height) = @_;
   my $image = Image::Magick->new();
   $image->Set(size=>"${width}x${height}");
   $image->ReadImage('xc:#ffffff');
   if (-r 'C:\Winnt\Fonts\Arial.ttf') {
      $font = 'C:\Winnt\Fonts\Arial.ttf';
      }
   elsif (-r '/home/wes/proj/perl/arial.ttf') {
      $font = '/home/wes/proj/perl/arial.ttf';
      }
   else {
      die "Cannot find a font file.\n";
      }
   return $image;
   }

sub drawSquare {
   my ($image, $x0, $y0, $x, $y, $hexColor) = @_;
   my $x1 = $x0 + $x * $scale;
   my $y1 = $y0 + $y * $scale;
   my $x2 = $x1 + $scale - 1;
   my $y2 = $y1 + $scale - 1;
   $image->Draw(primitive=>'rectangle', fill=>$hexColor, stroke=>'#111111', points=>"$x1,$y1 $x2,$y2");
   #$image->Draw(primitive=>'rectangle', fill=>$hexColor, stroke=>$hexColor, points=>"$x1,$y1 $x2,$y2");
   }

sub drawLabel {
   my ($image, $text, $pos, $xory) = @_;
   my $pointsize = int(0.7*$scale);
   if ($xory eq 'Y') {
      my $x = $matrixSize + $cmapAllowance;	# from right side of image
      $pos += 0.5*$pointsize;
      $image->Annotate(text=>$text, font=>$font, pointsize=>$pointsize, fill=>'#000000', x=>$x, y=>$pos, gravity=>'NorthEast');
      }
   else {	# X
      $pos += 0.5*$pointsize;
      $image->Annotate(text=>$text, font=>$font, pointsize=>$pointsize, fill=>'#000000', x=>$pos, y=>$yOrig, rotate=>270);
      }
   return;
   }

sub selectColor {
   my ($value) = @_;
   my $maxVal = 255;
   my $gray = 0;
   my $hexColor;
   if ($gray) {
      my $gray = int(0.5*($value + 1)*$maxVal);
      my $hex = sprintf("%x", $gray); # lower case a-f
      $hexColor = "#$hex$hex$hex";
      }
   else {
#     if    ($value <= -0.85)  { $hexColor = '#0000ff'; }
#     elsif ($value <= -0.80)  { $hexColor = '#3399ff'; }
#     elsif ($value <= -0.70)  { $hexColor = '#66ccff'; }
#     elsif ($value <= -0.08) { $hexColor = '#ffffff'; }
#     elsif ($value <= -0.03) { $hexColor = '#ffffff'; }
#     elsif ($value <=  0.03) { $hexColor = '#ffffff'; }
#     elsif ($value <=  0.08) { $hexColor = '#ffffff'; }
#     elsif ($value <=  0.70)  { $hexColor = '#ffffff'; }
#     elsif ($value <=  0.80)  { $hexColor = '#ff66cc'; }
#     elsif ($value <=  0.85)  { $hexColor = '#ff6666'; }
      if    ($value <= -0.8)  { $hexColor = '#0000ff'; }
      elsif ($value <= -0.6)  { $hexColor = '#3399ff'; }
      elsif ($value <= -0.4)  { $hexColor = '#66ccff'; }
      elsif ($value <= -0.2)  { $hexColor = '#99ccff'; }
      elsif ($value <= -0.05) { $hexColor = '#ccccff'; }
      elsif ($value <=  0.05) { $hexColor = '#ffffff'; }
      elsif ($value <=  0.2)  { $hexColor = '#ffccff'; }
      elsif ($value <=  0.4)  { $hexColor = '#ff99ff'; }
      elsif ($value <=  0.6)  { $hexColor = '#ff66cc'; }
      elsif ($value <=  0.8)  { $hexColor = '#ff6666'; }
      else                     { $hexColor = '#ff0000'; }
      }
   return $hexColor;
   }

sub drawColormapKey {
   my ($image, $x0, $y0) = @_;
   my $pointsize = int(0.4*$scale);
   my $x = $x0 + $scale + 5;
   my $i = 0;
   for my $value qw(1.00 0.80 0.60 0.40 0.20 0.05 -0.05 -0.20 -0.40 -0.60 -0.80) {
      my $hexColor = &selectColor($value-0.01);
      &drawSquare($image, $x0, $y0, 0, $i, $hexColor);
      my $y = $y0 + $scale*$i++ + int(0.5*$pointsize);
      $image->Annotate(text=>$value, font=>$font, pointsize=>$pointsize, fill=>'#000000', x=>$x, y=>$y);
      }
   my $y = $y0 + $scale*$i++ + int(0.5*$pointsize);
   $image->Annotate(text=>'1.0', font=>$font, pointsize=>$pointsize, fill=>'#000000', x=>$x, y=>$y);
   return;
   }

sub drawLines {
   my ($image, $size, $cellNum) = @_;
   my $xmax = $xOrig + $size - 1;
   my $ymax = $yOrig + $size - 1;
   my $x = $xOrig + $scale*$cellNum;
   my $y = $yOrig + $scale*$cellNum;
   $image->Draw(primitive=>'line', stroke=>'#000000', points=>"$xOrig,$y $xmax,$y", linewidth=>5);
   $image->Draw(primitive=>'line', stroke=>'#000000', points=>"$x,$yOrig $x,$ymax", linewidth=>5);
   return;
   }
