use strict;
use warnings;
use application "polytope";

foreach my $dir (glob("*")){
   if(-d $dir){
      join_tests($dir);
   }
}

sub join_tests {
   my($dir) = @_;
   my @tests = glob("$dir/*.test");
   my $n = 4;
   if(scalar @tests >= 10){ $n = 5;}
   if(scalar @tests >= 100){ $n = 10;}
   if(scalar @tests >= 200){ $n = 20;}
   while(scalar @tests > 0){
      my @queue = ();
      for(my $i = 0; $i<$n; $i++){
         if(scalar @tests > 0){
            push @queue, pop @tests;
         }
      }
      my $testname = $queue[0];
      my($inputfile, $outputfile) = join_n_tests($dir, @queue);
      verify_test($testname, $inputfile, $outputfile);
   }
   
}

sub verify_test {
   my($testname, $inputfile, $outputfile) = @_;
   my $entire = `cat $testname`;
   my $cmd = "~/mptopcom/build/Opt/bin/canonicalRepresentative";
   if($entire =~ m/--small-group/){
      $cmd .= " --small-group";
   }
   $cmd .= " < $inputfile 2>/dev/null";
   my $goodoutput = `$cmd`;
   my $expectedoutput = `cat $outputfile`;
   my $check = compare_outputs($goodoutput, $expectedoutput);
   if($check){
      `rm $outputfile`;
      open(my $fh, ">$outputfile");
      print $fh $goodoutput;
      close($fh);
      `git add $outputfile`;
   } else {
      die "Something wrong:\nGOT:\n$goodoutput\nEXPECTED:\n$expectedoutput\n";
   }
}

sub compare_outputs {
   my($out1, $out2) = @_;
   my @lines1 = split("\n", $out1);
   my @lines2 = split("\n", $out2);
   if(scalar @lines1 != scalar @lines2){ die "Arrays have different size.";}
   while(scalar @lines1 > 0){
      if(!compare_line(pop @lines1, pop @lines2)){
         return 0;
      }
   }
   return 1;
}

sub compare_line {
   my($line1, $line2) = @_;
   my ($triang1, $gkz1, $perm1) = $line1 =~ m/({\D*{.*}\D*})\D*gkz: (\[.*\]) - perm: (\[.*\])/;
   my ($triang2, $gkz2, $perm2) = $line2 =~ m/({\D*{.*}\D*})\D*gkz: (\[.*\]) - perm: (\[.*\])/;
   $gkz1 eq $gkz2 or return 0;
   $perm1 eq $perm2 or return 0;
   convert_triang($triang1) == convert_triang($triang2) or return 0;
   return 1;
}

sub convert_triang {
   my($triang) = @_;
   $triang =~ s/\{/\[/g;
   $triang =~ s/\}/\]/g;
   return new Set<Set<Int>>(eval $triang);
}

sub join_n_tests {
   my($dir, @tests) = @_;
   print "---\n";
   my $i = 0;
   my ($points, $group, $triang, $output, $inputfile, $outputfile) = get_input_output($tests[0], $dir);
   my $inputnew = "$points\n$group\n$triang\n";
   my $outputnew = "$output";
   print "$i:   $tests[0]\n";
   shift @tests;
   `rm $dir/$inputfile $dir/$outputfile`;
   my $inputfilename = "$dir/$inputfile";
   my $outputfilename = "$dir/$outputfile";
   open(my $inputfh, ">$dir/$inputfile");
   open(my $outputfh, ">$dir/$outputfile");
   foreach my $test (@tests){
      $i++;
      print "  $i: $test\n";
      ($points, $group, $triang, $output, $inputfile, $outputfile) = get_input_output($test, $dir);
      `git rm $dir/$inputfile $dir/$outputfile $test`;
      $inputnew .= "$triang\n";
      $outputnew .= $output;
   }
   print $inputfh $inputnew;
   print $outputfh $outputnew;
   close($inputfh);
   close($outputfh);
   `git add $inputfilename $outputfilename`;
   return($inputfilename, $outputfilename);
}

sub get_input_output {
   my($test, $dir) = @_;
   my $entire = `cat $test`;
   my($inputfile) = $entire =~ m/"INPUTFILE" : "([^"]*)"/;
   my($outputfile) = $entire =~ m/"RESULT" : "([^"]*)"/;
   defined($inputfile) or die "Input not found for $test";
   defined($outputfile) or die "Output not found for $test";
   my $input = `cat $dir/$inputfile`;
   my($points, $group, $triang) = $input =~ m/(\[\D*\[.*\]\D*\])\D*(\[\D*\[.*\]\D*\])\D*({\D*{.*}\D*})/s;
   defined($triang) or die "Triang not found in $input\n";
   my $output = `cat $dir/$outputfile`;
   return ($points, $group, $triang, $output, $inputfile, $outputfile);
}

