#!/usr/bin/perl -w 
##################################################################################
# triangulateParallel 
# 
# Runs the boundary algorithm and triangulates the resulting partitions in
# parallel.
#
# Output:
#  filename.L.partition - Output of boundary algorithm using left interface,
#                         the triangulations given in this file should 
#                         probably be ignored.
#  filename.R.partition - Output of boundary algorithm using right interface,  
#                         the triangulations given in this file should 
#                         probably be ignored.
#  filename.L.P         - Triangulation of the left interface prologue
#  filename.L.C         - Triangulation of the left interface chunk 
#  filename.L.E         - Triangulation of the left interface epilogue 
#  filename.R.P         - Triangulation of the right interface prologue
#  filename.R.C         - Triangulation of the right interface chunk 
#  filename.R.E         - Triangulation of the right interface epilogue 
#  filename.trifile     - The best left interface P,C,E triangulations merged
#  filename.R.trifile   - The best right interface P,C,E triangulations merged
##################################################################################

# $Header$

use strict;
use Getopt::Long;

my $valid_options; 
my $str_file; 
my $any_time_triangulate, 
my $boundary_any_time; 
my $triangulate_any_time; 
my $other_arguments; 
my $total_seconds;
my $boundary_seconds;
my $triangulate_seconds;
my $pmae_line;
my $boundary_line; 
my $triangulate_line;
my $gmtk_triangulate;
my $gmtk_tfmerge;
my $output;
my $pmae;

##############################################################################
# GMTK tool names
# -Do not add paths to these definitons, alter your path instead
##############################################################################
$gmtk_triangulate = 'gmtkTriangulate'; 
$gmtk_tfmerge     = 'gmtkTFmerge'; 
$pmae             = 'pmae'; 

##############################################################################
# Get command line parameters 
##############################################################################
$valid_options = &GetOptions( 
  "strFile:s"            => \$str_file, 
  "anyTimeTriangulate:s" => \$any_time_triangulate, 
  "boundaryAnyTime:s"    => \$boundary_any_time, 
  "triangulateAnyTime:s" => \$triangulate_any_time,
  "other:s"              => \$other_arguments
 );

##########################################################################
# Process command line parameters
##########################################################################
if (!defined $str_file) { 
  print "***ERROR:  Must supply a structure file name\n";
  $valid_options = 0;
}
else {
  (-e $str_file) or die "***ERROR:  '$str_file' does not exist\n";
}

if ((defined $any_time_triangulate) &&
    (!defined $boundary_any_time)   && 
    (!defined $triangulate_any_time)) 
{
  $total_seconds       = get_seconds($any_time_triangulate);
  $boundary_seconds    = int($total_seconds*0.2 + .5);
  $triangulate_seconds = $total_seconds - $boundary_seconds; 
}
elsif ((!defined $any_time_triangulate) &&
       (defined $boundary_any_time)     && 
       (defined $triangulate_any_time)) 
{ 
  $boundary_seconds    = get_seconds($boundary_any_time);
  $triangulate_seconds = get_seconds($triangulate_any_time);
}
elsif ((!defined $any_time_triangulate) &&
       (!defined $boundary_any_time)    && 
       (!defined $triangulate_any_time)) 
{
  $boundary_seconds    = 20; 
  $triangulate_seconds = 60; 
}
else 
{
  print "***ERROR:  Must give -anyTimeTriangulate or both -boundaryAnyTime and\n"; 
  print "           -triangulateAnyTime\n";
  $valid_options = 0;
}

if (!$valid_options) 
{
  print "Structure file name is required, make sure gmtkTriangulate, gmtkTRmerge, and\n";
  print "  pmae are in the path.\n";
  print "      -strFile             Structure file name\n";
  print "      -anyTimeTriangulate  Total boundary/triangulate time\n";
  print "      -boundaryAnyTime     Boundary search time\n";
  print "      -triangulateAnyTime  Triangulation search time\n";
  print "      -other               Other arguments to gmtkTriangulate\n";
  die "\n";
}

if (!defined $other_arguments)
{
  $other_arguments = ' ';
}

#############################################################################
# Create command line to pipe items to pmae/pmake 
#############################################################################
$pmae_line = "$pmae | pmake -L 0 -J 6 -f- 1>&2";

#############################################################################
# Export process to find best boundary 
#############################################################################
print "Finding best boundary (maximum of $boundary_seconds seconds after export)...\n";

$boundary_line = "$gmtk_triangulate -strFile $str_file -rePartition T -reTriangulate T -findBestBoundary T -triangulationHeuristic completed -findBestBoundary T -boundaryHeuristic W -M 1 -S 1 -seed T -anyTimeTriangulate $boundary_seconds -jtWeight T $other_arguments"; 

`echo \'$boundary_line -forceLeftRight L -outputTriangulatedFile $str_file.L_partition \n$boundary_line -forceLeftRight R -outputTriangulatedFile $str_file.R_partition\' | $pmae_line`; 

#############################################################################
# Export processes to triangulate P, C, and E 
#############################################################################
print "Triangulating (maximum of $triangulate_seconds seconds after export)...\n";

$triangulate_line = "$gmtk_triangulate -strFile $str_file -rePartition F -reTriangulate T -findBestBoundary F -findBestBoundary F -seed T -anyTimeTriangulate $triangulate_seconds -jtWeight T $other_arguments";

open PMAE, "| $pmae_line" or die 
  "Could not open stream to pmae or pmake";

print PMAE "$triangulate_line -inputTriangulatedFile $str_file.L_partition -outputTriangulatedFile $str_file.L.P -noReTriP F -noReTriC T -noReTriE T\n";
print PMAE "$triangulate_line -inputTriangulatedFile $str_file.L_partition -outputTriangulatedFile $str_file.L.C -noReTriP T -noReTriC F -noReTriE T\n";
print PMAE "$triangulate_line -inputTriangulatedFile $str_file.L_partition -outputTriangulatedFile $str_file.L.E -noReTriP T -noReTriC T -noReTriE F\n"; 

print PMAE "$triangulate_line -inputTriangulatedFile $str_file.R_partition -outputTriangulatedFile $str_file.R.P -noReTriP F -noReTriC T -noReTriE T\n";
print PMAE "$triangulate_line -inputTriangulatedFile $str_file.R_partition -outputTriangulatedFile $str_file.R.C -noReTriP T -noReTriC F -noReTriE T\n";
print PMAE "$triangulate_line -inputTriangulatedFile $str_file.R_partition -outputTriangulatedFile $str_file.R.E -noReTriP T -noReTriC T -noReTriE F\n"; 

close PMAE;

#############################################################################
# Merge trifiles (using local processor) 
#############################################################################
print "Merging trifiles...\n";

`$gmtk_tfmerge -strFile $str_file -outputTriangulatedFile $str_file.trifile -Ptrifile $str_file.L.P -Ctrifile $str_file.L.C -Etrifile $str_file.L.E 1>&2`; 

`$gmtk_tfmerge -strFile $str_file -outputTriangulatedFile $str_file.R.trifile -Ptrifile $str_file.R.P -Ctrifile $str_file.R.C -Etrifile $str_file.R.E 1>&2`; 


#############################################################################
# get_seconds(timestring)
#
# The input is a time string specifying:  seconds, minutes, hours, days, 
#    weeks.  Examples: 
#    '3 seconds 4 minutes 1 hour'  
#    '4min 1 hour 2 days'  
#    '1w3s1h'  
#
# Output is the integer number of seconds represented by the string.
#############################################################################
sub get_seconds 
{
  my $time_string;
  my @strings;
  my $total;
  my $string;
  my $numbers;
  my $letters;
  my $scnds;
  
  $time_string = pop;

  (@strings) = split /(\d+\s*\w+)/, $time_string;

  $total = 0;

  foreach $string (@strings)
  {
    ($numbers, $letters) = $string =~ /(\d+)\s*(\w+)/;

    if ((defined $letters) && (defined $numbers) &&  
        ('seconds' =~ /$letters/)) {
      $total = $total + $numbers;
    }
    elsif ((defined $letters) && (defined $numbers) &&  
           ('minutes' =~ /$letters/)) {
      $total = $total + 60*$numbers;
    }
    elsif ((defined $letters) && (defined $numbers) &&  
           ('hours' =~ /$letters/)) {
      $total = $total + 60*60*$numbers;
    }
    elsif ((defined $letters) && (defined $numbers) &&  
           ('days' =~ /$letters/)) {
      $total = $total + 24*60*60*$numbers;
    }
    elsif ((defined $letters) && (defined $numbers) &&  
           ('weeks' =~ /$letters/)) {
      $total = $total + 7*24*60*60*$numbers;
    }
  }

  return $total;
}


