#! /usr/bin/perl
# 
# Convert the schedule file to a spreadsheet
# Microsoft Project can read in files with the form
#ID\tUnique_ID\tTask_Name\tDuration\tType\tOutline_Level\tBaseline_Duration\tPredecessors\tStart_Date\tFinish_Date\tEarly_Start\tEarly_Finish\tLate_Start\tLate_Finish\tFree_Slack\tTotal_Slack\tLeveling_Delay\tPercent_Complete\tActual_Start\tActual_Finish\tBaseline_Start\tBaseline_Finish\tConstraint_Type\tConstraint_Date\tStop\tResume\tCreated
# We might get away with a subset of these

# and all fields tab separated.  Powerpoint appears to ignore durations
# and takes only dates.  This is called the "Task export map"

$do_html = 0;
$mpi1_only = 0;
$table_cols = 4;
$firstdate = "3/2/02";

while ($_ = shift(@ARGV)) {
    if (/-html/) { 
	$do_html = 1; 
	if (/=(\d*)/) {
	    $table_cols = $1;
	}
    }
    elsif (/-mpi1/) { $mpi1_only = 1; }
    elsif (/^-/) {
	print STDERR "Unexpected option $_\n";
	exit 1;
    }
    else { unshift (@ARGV,$_); last; }
}

# If requested, get MPI 1 only
if ($mpi1_only) {
    open( MPI1, "<maint/mpi1.lst" ) || die "Cannot open mpi1.lst\n";
    while (<MPI1>) {
	s/#.*//g;
	s/\s*[\r\n]*//g;
	if (/^MPI_/) {
	    $mpi1_names{$_} = 1;
	}
    }
}
#
# Skip header
while (<>) {
    if (/-------------------------/) { last; }
}

#
# Phase 1:  Read the file and assign id's to each function.  We need the
# Ids to compute the dependencies.
# Store the information by routine:
#   nametoid{routine} = id
#   nametotime{routine} = avg
#   nametodepend{routine} = dependstring
# This phase does no output
%nametoid = ();
%nametotime = ();
%nametodepend = ();
%nametoowner = ();
@idtoname = ();
$id = 1;
while (<>) {
    s/[\r\n]*$//;
    if (/^\s*BEGIN\s*(\w*)/) {
	$prefix = "$1:";
    }
    elsif (/^\s*END\s*(\w*)/) {
	if ($prefix != "$1:") { 
	    print STDERR "Warning: Found END $1 while processing $prefix\n";
	}
	$prefix = ""
    }
    elsif (/^.*,.*,.*,.*,.*,.*/) { 
	($routine,$min,$max,$avg,$priority,$name,$depend,$actual,$finished,$limits) = split(/,/);
	if ($mpi1_only) {
	    # Skip if not an MPI function
	    $ucroutine = $routine;
	    $ucroutine =~ tr/a-z/A-Z/;
	    if (!defined($mpi1_names{$ucroutine})) { next; }
	}
	# Validate data (check for typos)
	if ($min ne "" && $min =~ /([\.0-9]*)/ && $1 ne $min) {
	    print STDERR "$routine: min value ($min) not valid\n";
	}
	if ($max ne "" && $max =~ /([\.0-9]*)/ && $1 ne $max) {
	    print STDERR "$routine: max value ($max) not valid\n";
	}
	if ($avg ne "" && $avg =~ /([\.0-9]*)/ && $1 ne $avg) {
	    print STDERR "$routine: avg value ($avg) not valid\n";
	}
	if ($priority ne "" && $priority =~ /([\.0-9]*)/ && $1 ne $priority) {
	    print STDERR "$routine: priority value ($priority) not valid\n";
	}
	#print "$routine:$min:$max:$avg:$priority:$name:$depend:$actual\n";
	# Add any prefix to the routine
	$routine = "$prefix$routine";
	#print "$routine\t$min\t$max\t$avg\t$priority\t$name\t$depend\n";
	# eventually convert depend into id's for each routine.
	$nametoid{$routine} = $id;
	if ($actual eq "") { 
	    if ($avg eq "") { $avg = 1; }
	    $nametotime{$routine} = $avg;
	}
	else {
	    if ($actual eq "done") { $actual = 1; }
	    $nametotime{$routine} = $actual;
	    if ($finished eq "") { $finished = $firstdate; }
	    $nametofinished{$routine} = $finished;
	}	    
	$nametodepend{$routine} = $depend;
	$nametoowner{$routine} = $name;
	$idtoname[$id] = $routine;
	$nametolimits{$routine} = $limits;
	$id ++;
    }
    elsif (/^([^,]*),/) {	
	#print "$1\n";
	#print "$id\t$id\t$1\t\r\n";
	$routine = $1;
	print "Saw :$routine:\n" if $debug;
	if ($mpi1_only) {
	    # Skip if not an MPI function
	    $ucroutine = $routine;
	    $ucroutine =~ tr/a-z/A-Z/;
	    if (!defined($mpi1_names{$ucroutine})) { 
		print "Skipping $routine\n" if $debug;
		next; }
	}
	# Add any prefix to the routine
	$routine = "$prefix$routine";
        $nametotime{$routine} = 1;
	$nametoid{$routine} = $id;
	$idtoname[$id] = $routine;
	$id ++;
    }
}

sub convert_depend {
    $depend = $_[0];
    $dependlist= "";
    # Look in depend for strings
    @names = split(/\s\s*/,$depend);
    foreach $name (@names) {
	if (defined($nametoid{$name})) {
	    $dependlist .= "$nametoid{$name},";
	}
    }
    chop $dependlist;
    return $dependlist;
}

sub Earlier {
    $date1 = $_[0];
    $date2 = $_[1];
    # Return 1 if $date1 is before $date2
    ($month1,$day1,$year1) = split(/\//,$date1);
    ($month2,$day2,$year2) = split(/\//,$date2);
    if ($year1 < $year2) { return 1; }
    if ($year1 > $year2) { return 0; }
    if ($month1 < $month2) { return 1; }
    if ($month1 > $month2) { return 0; }
    if ($day1 < $day2) { return 1; }
    return 0;
}

sub PrintAsSpreadsheet {
print "ID\tUnique_ID\tTask_name\tDuration\tPredecessors\tResource_Names\tActual_Finish\r\n";
for ($i = 1; $i <$id; $i++) {
    $routine = $idtoname[$i];
    $avg     = $nametotime{$routine};
    $depend  = $nametodepend{$routine};
    $dependlist = convert_depend( $depend );
    $owner   = $nametoowner{$routine};
    $finished = $nametofinished{$routine};
    # For Microsoft project, we set the earliest date to be near the 
    # beginning of the time that we starting keeping the schedule.
    if ($finished ne "" && Earlier( $finished, $firstdate )) {
	$finished = $firstdate;
    }
    $nl = "\r\n";
    $nl = "\n";
    print "$i\t$i\t$routine\t$avg\t\"$dependlist\"\t\"$owner\"\t\"$finished\"$nl";
}
}

#
# HTMLTable( numcols, setchar, rowstart, rowend, colstart, colend )
# Acts on @table.  Everything after numcols is optional
sub HTMLTable {
    my $nc     = $_[0];
    my $colsep = $_[1];
    my $rowstart = $_[2];
    my $rowend   = $_[3];
    my $colstart = $_[4];
    my $colend   = $_[5];

    if ($colsep eq "") { $colsep = ":"; }
    if ($rowstart eq "") { $rowstart = "<TR>"; }
    if ($rowend eq "") { $rowend = "</TR>\n"; }
    if ($colstart eq "") { $colstart = "<TD>"; }
    if ($colend eq "") { $colend = "</TD>"; }

    my $nrows = $#table;
    # Number of table rows within each column
    my $nrows_per_col = int (($nrows + $nc - 1) / $nc);
    
    for (my $i=0; $i<$nrows_per_col; $i++) {
	print $rowstart;
	for (my $j=0; $j<$nc; $j++) {
	    # Extract table row
	    my @cols = split( /$colsep/, $table[$i+$j*$nrows_per_col] );
	    for (my $k=0; $k<=$#cols; $k++) {
		print "$colstart$cols[$k]$colend";
	    }
	}
	print $rowend;
    }
}

sub PrintAsHtml {
    $done_count = 0;
    $tot_count = 0;
    print "<TABLE>\n";
    foreach $key (sort(keys(%nametotime))) {
	if ($key =~ /^MPI_/) { 
	    $tot_count ++;
	    $routine = $key;
	    $avg     = $nametotime{$routine};
	    $depend  = $nametodepend{$routine};
	    $dependlist = convert_depend( $depend );
	    $owner   = $nametoowner{$routine};
	    $finished = $nametofinished{$routine};
	    $limits = $nametolimits{$routine};
	    $color = "FF0000";
	    if ($finished ne "") { 
		$done_count++;
		$finished = "done";
		if ($limits ne "") {
		    $color = "D0D000";
		}
		else {
		    $color = "00D010";
		}
	    }
#	    print "<TR><TD><FONT COLOR=\"$color\">$routine</FONT><TD>$finished<TD>$owner</TR>\n";
	    @table[$#table+1] = "<FONT COLOR=\"$color\">$routine</FONT>";
	}
    }
    &HTMLTable( $table_cols );
    print "</TABLE>\n";
    print "<TABLE><TR><TH>Routines Finished<TH>Routines Left</TR>\n";
    $left_count = $tot_count - $done_count;
    print "<TR><TD>$done_count<TD>$left_count</TR></TABLE>\n";
}

if ($do_html) {
    &PrintAsHtml;
}
else {
    &PrintAsSpreadsheet;
}
