
use warnings;
use strict;

use Path::Tiny;
use JSON::XS;
use Data::Dumper;

my $REDUCER = './Reducer.hs';
my $RUNHS = '/usr/bin/runhaskell';
my $DOT = '/usr/bin/dot';

my $filename = shift;
my $hs_file = $filename;
$hs_file =~ s/\.\w+$/.hs/;
my $dot_file = $filename;
$dot_file =~ s/\.\w+$/.dot/;
my $parts_file = $filename;
$parts_file =~ s/\.\w+$/.parts/;
my $json_file = $filename;
$json_file =~ s/\.\w+$/.json/;

my $abc = _get_abc($filename);
_build_hs($hs_file, $abc);
my $json = `$RUNHS $hs_file`;
path($json_file)->spew($json);
print STDERR "Building Hs file: $hs_file\n";
my $res = decode_json $json;
_build_dot($dot_file, $res);
_build_svg($dot_file);
_build_png($dot_file);
_build_parts($parts_file, $res);

#print Dumper $res;

sub _get_abc {
  my ($filename) = @_;

  print STDERR "Reading Abc from: $filename\n";
  my $abc = path($filename)->slurp;

  return $abc;
}

sub _build_hs {
  my ($hs_file, $abc) = @_;

  print STDERR "Building Hs file: $hs_file\n";
  my $hs = "import qualified Data.ByteString.Lazy as BS\nimport qualified Data.Aeson as A\n\n";
  $hs .= path($REDUCER)->slurp;
  $hs .= "\ninput = $abc\n\n";
  $hs .= 'main = BS.putStr $ A.encode $ reduce input';

  path($hs_file)->spew($hs);
}

sub _build_dot {
  my ($dot_file, $res) = @_;

  print STDERR "Building dot file: $dot_file\n";
  my $dot = "digraph finite_state_machine {\n  rankdir=LR;\n  size=\"7,5\";\n  node [shape = circle];\n";
  my $counter = 1;
  my @list = @{ $res->[0] };
  my $last;
  foreach (@list) {
    if ($last) {
      $dot .= "  \"$last\" -> \"$_\" [ label = \"$counter\" ];\n";
      $counter++;
    }
    $last = $_;
  }
  $dot .= "}\n";

  path($dot_file)->spew($dot);
}

sub _build_svg {
  my ($dot_file) = @_;

  my $svg_file = $dot_file;
  $svg_file =~ s/\.\w+$/.svg/;

  print STDERR "Building svg file: $svg_file\n";
  `$DOT -Tsvg $dot_file > $svg_file`;
}

sub _build_png {
  my ($dot_file) = @_;

  my $png_file = $dot_file;
  $png_file =~ s/\.\w+$/.png/;

  print STDERR "Building png file: $png_file\n";
  `$DOT -Tpng $dot_file > $png_file`;
}

sub _build_parts {
  my ($parts_file, $res) = @_;

  print STDERR "Building parts file: $parts_file\n";
  my $parts;
  my @list = @{ $res->[1] };
  foreach (@list) {
    $parts .= "$_->[0]: " .  join(',', @{$_->[1]}) . "\n";
  }

  path($parts_file)->spew($parts);
}
