#!/usr/bin/perl -w
#--------------------------------------------------------------------------------------------------------------
#
# Convert LANL data to the tabbed format.
#
# usage: 
# ./lanl2tab.pl -input ~/research/fta/data/lanl_data -output ~/research/fta/data/lanl_tab
#
# Contact: Derrick Kondo derrick.kondo :: inria fr
#
# Copyright 2009 by Failure Trace Archive site (http://fta.inria.fr)
#
#--------------------------------------------------------------------------------------------------------------



# TESTS:

# total number of hosts is correct


# limit scope of variables
use strict;

use Date::Calc qw (Date_to_Time);
use Switch;
use FTA_Format;

# Module to help handle command line switches
use Getopt::Long;

# method headers
sub main();
sub extract_parameters();

sub create_platform ($);
sub create_node ($);
sub create_node_perf ($);
sub create_component ($);
sub create_event_trace ($$);
sub create_event_state ($);

# platform globals
my ($PLATFORM_ID, $PLATFORM_NAME, $PLATFORM_LOCATION, $PLATFORM_TYPE);
 
$PLATFORM_ID = 3;
$PLATFORM_NAME = "LANL";
$PLATFORM_LOCATION = "Los Alamos National Lab,USA";
$PLATFORM_TYPE = "HPC Clusters"; 

# node globals

# DATA STRUCTURES

# %NODE is a hash table that points to a array reference,
# %which points to an array of events.

# node_name -> events arr (node_id, reference to event_traces array of
# (event_id, event_type, start time, stop time))

my (%NODE, $NODE_ID_COUNTER);

$NODE_ID_COUNTER = 0;

# component globals
my ($COMPONENT_ID, $COMPONENT_CITE, $RESOLUTION);
$COMPONENT_ID = 0;
$RESOLUTION = 1*60; # 1 min


# creator globals
my ($CREATOR_ID, $CREATOR, $CITE, $COPYRIGHT);
$CREATOR_ID = 0;
# assume no spaces here
$CREATOR = "LANL_team";
# bibtex entry difficult to parse in tabbed format. Thus put
# bibtex citation instead.
$CITE = "Gibson_dsn06";
$COPYRIGHT = "LANL_team";

# event_trace globals
my($START_TIME_MEAS, $END_TIME_MEAS);

#$START_TIME_MEAS = "12/1/1996"; # DEC. 1996
#$END_TIME_MEAS = "11/1/2005"; # NOV. 2005

# for overlapped events (1: inter-section, 0:union)
my($OVERLAPPED) = 1;

my(@END_REASON) = ("Facilities", "Hardware", "Human Error", "Network", "Undetermined", "Software");

main;

sub main (){
    my (@args, $start, $stop, $cwd);

    my ($inputdir, $outputdir, $a, $b);

    ($inputdir, $outputdir) = extract_parameters();
    
    createDir ($outputdir);
    create_platform ($outputdir);
    create_node_perf ($outputdir);
    create_event_trace ($inputdir, $outputdir);
    create_event_state ($outputdir);
# must be called after create_event_trace
    create_node ($outputdir);
    create_component ($outputdir);
    create_creator ($outputdir);

}

sub create_platform ($){
    my ($outputdir) = @_;

    open (OUT, ">$outputdir/platform.tab") or die "could not open $outputdir/platform.tab";

    print_header (*OUT, "platform");

    print_ln (*OUT, "platform", [$PLATFORM_ID, $PLATFORM_NAME,
		     $PLATFORM_LOCATION, $PLATFORM_TYPE, "NULL"]);

    close (OUT);
}
 

sub create_creator ($){
  my ($outputdir) = @_;
  
  open (OUT, ">$outputdir/creator.tab") or die "could not open $outputdir/creator.tab";
  
  print_header (*OUT, "creator");
  
  my (@node_names) = keys (%NODE);
  @node_names = sort @node_names;
  
  @node_names > 0 or die "no nodes\n";
  
  my ($node_name);
  foreach $node_name (@node_names){
    my ($events, $node_id, $event_traces, $event_info);
    
    
  print_ln (*OUT, "creator", [$CREATOR_ID, $COMPONENT_ID,
		$NODE{$node_name}->[0], $PLATFORM_ID, $CREATOR, $CITE, $COPYRIGHT]);
    
  }
  
  close (OUT);
}


# create_event_trace must be called before
sub create_node ($){
    my ($outputdir) = @_;


    my ($node_name,$node_info,$node_ch);

    open (NODE, ">$outputdir/node.tab") or die "could not open $outputdir/node.tab";

     print_header (*NODE, "node");

    my (@node_names) = keys (%NODE);
    @node_names = sort @node_names;

    @node_names > 0 or die "no nodes\n";
    
    my($location) = "NM,USA";
    my($timezone) = "-25200";

    foreach $node_name (@node_names){
	my ($events, $node_id, $event_traces, $event_info);
	
	$node_info = $NODE{$node_name}->[2];
	
	$node_ch = $node_info->[-1];
	
	print_ln (*NODE, "node",
		    [$NODE{$node_name}->[0], $PLATFORM_ID,
		     $node_name, "NULL", $location, $timezone, $node_ch->[1], "NULL",
		     "NULL", $node_ch->[0], $node_ch->[2], "NULL", "NULL",
		     "NULL", "NULL", "NULL"]);

=pob	printf NODE ("%10s\t%5d\t%30s\t%30s\t%6s\t%6s\t%6s\t%6s\t%6s\t%6s\t%6s\t%6s\t%6s\t%6s\t%6s\t%6s\n", 
		    $NODE{$node_name}->[0], $PLATFORM_ID,
	$node_name, "NULL", "NULL", "NULL", $node_ch->[1], "NULL",
	"NULL", "NULL", $node_ch->[0], $node_ch->[2], "NULL", "NULL",
	"NULL", "NULL", "NULL");
=cut
	
    }

    close (NODE);
}

# create_node_perf
sub create_node_perf($){
    my ($outputdir) = @_;

    open (NODE_PERF, ">$outputdir/node_perf.tab") or die "could not open $outputdir/node_perf.tab";

    print_header (*NODE_PERF, "node_perf");

    close (NODE_PERF);

}

# create_event_state
sub create_event_state($){
    my ($outputdir) = @_;

    open (EVENT_STATE, ">$outputdir/event_state.tab") or die "could not open $outputdir/event_state.tab";

    print_header (*EVENT_STATE, "event_state");

    close (EVENT_STATE);

}

# create_event_trace must be called before

sub create_component ($){
    my ($outputdir) = @_;
    
    my ($component_type) = "0"; # 0 -> host availability
# should have crawler availability
#     my ($component_type2_crawler) = "crawler host availability ";

    open (COMPONENT, ">$outputdir/component.tab") or die "could not open $outputdir/component.tab";
    
    print_header (*COMPONENT, "component");

    my (@node_names) = keys (%NODE);
    @node_names = sort @node_names;

    @node_names > 0 or die "no nodes\n";
    
    my ($node_name);
    foreach $node_name (@node_names){
	my ($events, $node_id, $event_traces, $event_info);
	
	$events = $NODE{$node_name};

	$node_id = $events->[0];
	$event_traces = $events->[1];

	my ($trace_start, $trace_end);
=pob
# get start time of first event
#	$trace_start = $event_traces->[0]->[2];

	my($year, $month, $day);
	my(@st_date) = split /\//, $START_TIME_MEAS;
		
	$year = $st_date[2];
	$month = $st_date[0];
	$day = $st_date[1];

	$trace_start = Date_to_Time ($year, $month, $day, 0, 0, 0);
 
# get stop time of last event
#	$trace_end = $event_traces->[-1]->[3];
	my(@end_date) = split /\//, $END_TIME_MEAS;
		
	$year = $end_date[2];
	$month = $end_date[0];
	$day = $end_date[1];

	$trace_end = Date_to_Time ($year, $month, $day, 0, 0, 0);
=cut

# get start time of first event
	$trace_start = $event_traces->[0]->[2];
# get stop time of last event
	$trace_end = $event_traces->[-1]->[3];
	print_ln (*COMPONENT, "component", [$COMPONENT_ID,
					    $node_id,
					    $PLATFORM_ID,
					    $CREATOR_ID,
					    $node_name,
					    $component_type,
					    $trace_start,
					    $trace_end,
					    $RESOLUTION]);

    }

    close (COMPONENT);
    
}



sub create_event_trace ($$){
    my ($inputdir, $outputdir) = @_;
    
    my ($event_id, $component_id, $node_id,
	$event_type, $event_state, $event_start_time,
	$event_end_time, $event_end_reason);
    my($semi_counter,$counter , $full_time, $semi_time);

    $semi_counter = 0;
    $counter = 0;
    $full_time = 0;
    $semi_time = 0;

    my (@files, $f);

    $event_id = 0;
 
# open input directory   
    opendir (INPUTDIR, $inputdir);
    
# read in inputs
    @files = grep { /.*\.csv$/ } readdir (INPUTDIR);
    
    print "Number of trace files: " . @files . "\n";
    
    @files = sort @files;

    my ($node_name);
    foreach $f (@files){
	
	print "\tProcessing file $f\n";
	
	open (IN, "$inputdir/$f") or die "$inputdir/$f could not be opened";
	
	my (@info, $line); 
   
	while ($line = <IN>){
#	    print "\t$line\n";
	    
	    chomp ($line);

# start reading from the first line

	    if ($line =~ /^\d/){

		my ($location, @line_info);
		$location="NULL";

		(@line_info) = split /,/, $line;

# ****************************************************
# node_name: system + node number starting from zero

		$node_name = $line_info[0] . "." . $line_info[6];

#start time
		my (@start_date,@start_date_1,@start_date_2);
		@start_date = split /\s+/, $line_info[16];
		
		@start_date_1 = split /\//, $start_date[0];
		@start_date_2 = split /:/, $start_date[1];
		
		my ($year) = $start_date_1[2];
		my ($month) = $start_date_1[0];
		my ($day) = $start_date_1[1];

		my ($hour) = $start_date_2[0];
		my ($min) = $start_date_2[1];
		my($sec) = 0;

		$event_start_time = Date_to_Time ($year, $month, $day, $hour, $min, $sec);

#end time
		my (@end_date,@end_date_1,@end_date_2);
		@end_date = split /\s+/, $line_info[17];
		
		@end_date_1 = split /\//, $end_date[0];
		@end_date_2 = split /:/, $end_date[1];
		
		$year = $end_date_1[2];
		$month = $end_date_1[0];
		$day = $end_date_1[1];

		$hour = $end_date_2[0];
		$min = $end_date_2[1];
		$sec = 0;

		$event_end_time = Date_to_Time ($year, $month, $day, $hour, $min, $sec);


		my (@end_reason_ary,$reason,$i,$j,$event_end_class,$rx,$nrx);

                @end_reason_ary = @line_info[19..24];

                $i = 0;
                $j = 25;
                my($flag) = 1;
                $event_end_class = "";
                $reason = "";
                foreach $rx (@end_reason_ary){
                   if ($rx =~ /\w+/){
		      if ($rx =~ /^"/){			  
			  while ($flag==1){
			      $nrx = $line_info[$j];
			      $rx = $rx.",".$nrx;
			      if ($nrx =~/"$/){
				  $flag=0;}
			      else{
				  $j++;}
			  $rx =~ s/"//;
			  $rx =~ s/"//;
			  }

		      }
#		     $event_end_reason = $END_REASON[$i].": ".$rx;
		     $event_end_class = $END_REASON[$i];
		     $reason = $rx;
		     last;
                   }
                $i = $i+1; 
                }
	# when no reason reported
	if ($i==6){
	     $event_end_reason = "NULL";
	}
	else{
#	print "rr: $event_end_class, tt: $reason \n";
	$event_end_reason = -1;
	        switch ($event_end_class){
		    case "Undetermined" {$event_end_reason = 0;}
		}
		    switch($reason){
			case "Power Outage" {$event_end_reason = 2;}
			case "Power Spike" {$event_end_reason = 3;}
			case "Chillers" {$event_end_reason = 4;}
			case "Environment" {$event_end_reason = 5;}
			case "UPS" {$event_end_reason = 6;}

			case "Other" {$event_end_reason = 1000;}
			case "40MM Cooling Fan" {$event_end_reason = 1001;}
			case "Bach Plane Assembly" {$event_end_reason = 1002;}
			case "CD ROM" {$event_end_reason = 1003;}
			case "Console Interface Module" {$event_end_reason = 1004;}
			case "CPU" {$event_end_reason = 1005;}
			case "DG Board" {$event_end_reason = 1006;}
			case "Fan" {$event_end_reason = 1007;}
			case "Fan Assembly" {$event_end_reason = 1008;}
			case "GFX Power Supply" {$event_end_reason = 1009;}
			case "Graphics Accel Hdwr" {$event_end_reason = 1010;}
			case "Graphics Video Card" {$event_end_reason = 1011;}
			case "Heatsink bracket" {$event_end_reason = 1012;}
			case "IO6" {$event_end_reason = 1013;}
			case "IOS Buffer Memory" {$event_end_reason = 1014;}
			case "IOS CPU" {$event_end_reason = 1015;}
			case "KGPSA" {$event_end_reason = 10016;}
			case "Ktown Board" {$event_end_reason = 1017;}
			case "Maintenance" {$event_end_reason = 1018;}
			case "Memory Dimm" {$event_end_reason = 1019;}
			case "Memory Dimm/CPU" {$event_end_reason = 1020;}
			case "Memory Module" {$event_end_reason = 1021;}
			case "MIA" {$event_end_reason = 1022;}
			case "Mid-plane" {$event_end_reason = 1023;}
			case "MMB" {$event_end_reason = 1024;}
			case "Module Assembly" {$event_end_reason = 1025;}
			case "MSC Board" {$event_end_reason = 1026;}
			case "OCP" {$event_end_reason = 1027;}
			case "PCI Back Plane" {$event_end_reason = 1028;}
			case "PCI Backplane" {$event_end_reason = 1028;}
			case "Power cord" {$event_end_reason = 1029;}
			case "Power Supply" {$event_end_reason = 1030;}
			case "Rack Power Distribution Unit" {$event_end_reason = 1031;}
			case "Riser Card" {$event_end_reason = 1032;}
			case "RM Board" {$event_end_reason = 1033;}
			case "SSD Logic" {$event_end_reason = 1034;}
			case "SSD Memory Module" {$event_end_reason = 1035;}
			case "System Board" {$event_end_reason = 1036;}
			case "System Controller" {$event_end_reason = 1037;}
			case "Temp Probe" {$event_end_reason = 1038;}
			case "Term Server" {$event_end_reason = 1039;}
			case "Vhisp" {$event_end_reason = 1040;}
			case "WACS Logic" {$event_end_reason = 1041;}
			case "Wire Harness" {$event_end_reason = 1042;}
			case "Xtown Board" {$event_end_reason = 1043;}
			case "Node Board" {$event_end_reason = 1043;}
			    
			case "Disk Cabinet" {$event_end_reason = 2001;}
			case "Disk Drive" {$event_end_reason = 2002;}
			case "Drive Cage" {$event_end_reason = 2003;}
			case "Fddi" {$event_end_reason = 2004;}
			case "Fibre Cable" {$event_end_reason = 2005;}
			case "Fibre Channel Port Adapter" {$event_end_reason = 2006;}
			case "Fibre Drive" {$event_end_reason = 2007;}
			case "Fibre HBA" {$event_end_reason = 2008;}
			case "Fibre Raid Controller" {$event_end_reason = 2009;}
			case "Fibre Raid LCC card" {$event_end_reason = 2010;}
			case "Fibre Raid Midplane" {$event_end_reason = 2011;}
			case "Fibre Raid Power Supply" {$event_end_reason = 2012;}
			case "IDE Cable" {$event_end_reason = 2013;}
			case "IOS Disk Logic" {$event_end_reason = 2014;}
			case "PCI Fibre Channel Adapter" {$event_end_reason = 2015;}
			case "PCI Fibre Channel Adaptor" {$event_end_reason = 2015;}
			case "PCI IO Module" {$event_end_reason = 2016;}
			case "PCI SCSI Controller" {$event_end_reason = 2017;}
			case "PCI Shoebox" {$event_end_reason = 2018;}
			case "SAN Appliance" {$event_end_reason = 2019;}
			case "SAN Controller" {$event_end_reason = 2020;}
			case "SAN controller" {$event_end_reason = 2020;}
			case "SAN Disk Drive" {$event_end_reason = 2021;}
			case "SAN Fiber Cable" {$event_end_reason = 2022;}
			case "SAN GBIC" {$event_end_reason = 2023;}
			case "SAN Shelf" {$event_end_reason = 2024;}
			case "SAN Switch" {$event_end_reason = 2025;}
			case "SCSI Adapter Card" {$event_end_reason = 2026;}
			case "SCSI Card" {$event_end_reason = 2026;}
			case "SCSI Controller" {$event_end_reason = 2027;}
			case "SCSI Drive" {$event_end_reason = 2028;}

			case "Network" {$event_end_reason = 3000;}
			case "1 GBit Ethernet Card" {$event_end_reason = 3001;}
			case "100 MBit Ethernet Card" {$event_end_reason = 3002;}
			case "Ethernet Cable" {$event_end_reason = 3003;}
			case "Ethernet Copper Cable" {$event_end_reason = 3004;}
			case "Ethernet Fiber Cable" {$event_end_reason = 3005;}
			case "Ethernet Fibre Cable" {$event_end_reason = 3005;}
			case "Ethernet Switch" {$event_end_reason = 3006;}
			case "GE Board" {$event_end_reason = 3007;}
			case "Gig E Connection" {$event_end_reason = 3008;}
			case "Gig E Switch" {$event_end_reason = 3009;}
			case "Interconnect" {$event_end_reason = 3010;}
			case "Interconnect Cable" {$event_end_reason = 3011;}
			case "Interconnect Interface" {$event_end_reason = 3012;}
			case "Interconnect Misc" {$event_end_reason = 3013;}
			case "Interconnect Soft Error" {$event_end_reason = 3014;}
			case "Interconnect Switch" {$event_end_reason = 3015;}
			case "PCI Ethernet Board" {$event_end_reason = 3016;}
			case "PCI GBIT Ethernet Board" {$event_end_reason = 3017;}
			case "Router Board" {$event_end_reason = 3018;}
			case "Site Ethernet Switch" {$event_end_reason = 3019;}
			case "Site Network Interface" {$event_end_reason = 3020;}
			case "Console Network Device" {$event_end_reason = 3021;}

			case "Other Software" {$event_end_reason = 4000;}
			case "Disk IO, firmware and storage" {$event_end_reason = 4001;}
			case "MPI, PVM, Array services" {$event_end_reason = 4002;}
			case "Cluster File System" {$event_end_reason = 4003;}
			case "Cluster Software" {$event_end_reason = 4004;}
			case "Compilers and libraries" {$event_end_reason = 4005;}
			case "DST" {$event_end_reason = 4006;}
			case "DST-Scan for errors /scratch" {$event_end_reason = 4007;}
			case "DST-Upgrd/Install OS sftw" {$event_end_reason = 4008;}
			case "DST-Upgrd/Instl 3rdParty Sftw" {$event_end_reason = 4009;}
			case "DST-Upgrd/Instl OS Sftw" {$event_end_reason = 4010;}
			case "Interconnect" {$event_end_reason = 4011;}
			case "IOS Software" {$event_end_reason = 4012;}
			case "Kernel software" {$event_end_reason = 4013;}
			case "Modify kernel parameters" {$event_end_reason = 4014;}
			case "Modify system config files" {$event_end_reason = 4015;}
			case "Network" {$event_end_reason = 4016;}
			case "NFS" {$event_end_reason = 4017;}
			case "OS" {$event_end_reason = 4018;}
			case "Parallel File System" {$event_end_reason = 4019;}
			case "Patch Install" {$event_end_reason = 4020;}
			case "Resource Mgmt System" {$event_end_reason = 4021;}
			case "Scheduler Software" {$event_end_reason = 4022;}
			case "Scratch Drive" {$event_end_reason = 4023;}
			case "Scratch FS" {$event_end_reason = 4024;}
			case "Security Software" {$event_end_reason = 4025;}
			case "Upgrade/Install 3rd Party Sftw" {$event_end_reason = 4026;}
			case "Upgrade/Install OS sftw" {$event_end_reason = 4027;}
			case "User code" {$event_end_reason = 4028;}
			case "Vizscratch FS" {$event_end_reason = 4029;}

			case "Human Error" {$event_end_reason = 5000;}

		}
	}
                my( $event_id, $events);
		$event_id = 0;
		$event_type = 1;

		defined ($node_name) or die "node_name undef";
		defined ($location) or die "location undef";
		defined ($event_id) or die "event_id undef";


		my ($event_info,$event_info_pre);
		  
# Process node information
                    if (!exists($NODE{$node_name})){
		    $events = [];

		    my($infos, $node_info, $proc_type, $num_proc, $mem_size);
		    if ($line_info[4] =~ /^\d/){
		      $num_proc = $line_info[4];
		    }
		    else{
			$num_proc = -1;
		    }

		    if ($line_info[11] =~ /^\d/){
		        $mem_size = $line_info[11]*1024**3;
} # memory size in Byte
		    else{
			$mem_size = -1;
		    }
		    if ($line_info[12] =~ /^\d/){
		      $proc_type = $line_info[12];
		    }
		    else{
			$proc_type = -1;
		    }

		    $infos =[$num_proc, $proc_type, $mem_size]; 
				    
		    #unavailability interval
		    $event_type = 0;
		    $event_end_reason = "NULL";
		    $event_info = [$event_id, $event_type, $event_start_time, $event_end_time, $event_end_reason];
		    push (@$node_info, $infos);
		    push (@$events, $event_info);
		    $NODE{$node_name} = [$NODE_ID_COUNTER, $events, $node_info];
		  
		    $NODE_ID_COUNTER++;
		  }
		  else{

                     # Process later event
		    $events = $NODE{$node_name}->[1];

		    # get most recent event type
		    $event_info = $events->[-1];
		    my($size) = scalar @$events;
		    $event_info_pre = $events->[$size-2];
		    #print "$event_info->[3], $size, $event_info_pre->[3]\n";
		    my($last_end_time) = $event_info->[3];

		    if ($last_end_time < $event_start_time){

			# add new event (availability interval)
			$event_info = [$event_info->[0]+1, $event_type,$event_info->[3], $event_start_time, $event_end_reason];
			push (@$events, $event_info);

			# add new event (unavailability interval)
			$event_type = 0;
			$event_end_reason = "NULL";
			$event_info = [$event_info->[0]+1, $event_type,$event_start_time, $event_end_time, $event_end_reason];
			push (@$events, $event_info);
		    }
		    else{
			if ($OVERLAPPED){
			    # intersection of two overlapped events

			    #update start time
			    $event_info->[2] = $event_start_time;

			    #update end time of previous event
			    $event_info_pre->[3] = $event_start_time;
			    
			    if ($event_info->[3] > $event_end_time){

				$event_info->[3] = $event_end_time;
			    }
			}
			else{
			    # union of two overlapped events
			    if ($event_info->[3] <= $event_end_time){

				$event_info->[3] = $event_end_time;
			    }
			 }# if overlapped
		    }# if else

		    } # if exists
		} # if line

	} # while line
	
	close (IN);

    } # foreach files
    close INPUTDIR;

# at end of parsing last probe file, insert stop time for
# last interval of each node

    my (@node_names) ;
    @node_names = keys (%NODE);
    
     print "No. node names: " . @node_names . "\n";
#print "semi-overlapped, total: $semi_counter, $semi_time \n";
#print "overlapped, total :$counter, $full_time \n";

=pob
    my ($nn);
    foreach $nn (@node_names) {
	my ($events, $event_info);

	$events = $NODE{$nn}->[1];
	
# get most recent event type
#	!defined($events->[-1]->[3]) or die "last intv shouldn't be defined";
	$event_info = $events->[-1];

#	defined ($event_info->[1]) or die "event_type undef";

	# ASSUMES LAST TIME STAMP FOR ALL HOSTS IS THE SAME, WHICH IS THE END OF MEASURMENT
	# add stop time to last event: stop = timestamp
	my($year, $month, $day);
	my(@st_date) = split /\//, $END_TIME_MEAS;
		
	$year = $st_date[2];
	$month = $st_date[0];
	$day = $st_date[1];
        
        my($trace_end_time);

	$trace_end_time = Date_to_Time ($year, $month, $day, 0, 0, 0);


        $event_type = 1;

        # end of measurement
	$event_end_reason = 7000;
	$event_info = [$event_info->[0]+1, $event_type,$event_info->[3], $trace_end_time, $event_end_reason];
	push (@$events, $event_info);

    }
=cut    
    print_event_trace($outputdir);

}

sub print_event_trace($){
    my ($outputdir)=@_;
 
    my (@node_names) = keys (%NODE);
    @node_names = sort @node_names;

    my ($node_name);
    my($total_avai) = 0;

    open (EVENT_TRACE, ">$outputdir/event_trace.tab") or die
	"file $outputdir/event_trace.tab could not be used for output";

    print_header (*EVENT_TRACE, "event_trace");

    foreach $node_name (@node_names){
	my ($events, $node_id, $event_traces, $event_info);
	
	$events = $NODE{$node_name};
	defined ($events) or die "events undef";
	$node_id = $events->[0];

	$event_traces = $events->[1];
	
# 	print "node_name: $node_name\n";

	foreach $event_info (@$event_traces){
	    my ($event_id, $event_type, $start_time,
		$stop_time, $stop_reason);

	    defined ($event_info) or die "event_info undef";
# 	    print "event_info: " . @$event_info . "\n";
# 	    print "event_id: " . $event_info->[1] . "\n";

	    $event_id = $event_info->[0];
	    $event_type = $event_info->[1];
	    $start_time = $event_info->[2];
	    $stop_time = $event_info->[3];
	    $stop_reason = $event_info->[4];

	    if ($event_type){$total_avai = $total_avai + ( $stop_time - $start_time)};

	    defined ($event_id) or die "event id undef";
	    defined ($COMPONENT_ID) or die "COMPONENT_ID undef";
	    defined ($node_id) or die "node_id undef";
	    defined ($PLATFORM_ID) or die "platform_id undef";
	    defined ($event_type) or die "event_type undef";
	    defined ($start_time) or die "start_time undef";
	    defined ($stop_time) or die "stop_time undef";

	    print_ln (*EVENT_TRACE, "event_trace", 
		 [$event_id, $COMPONENT_ID,
		 $node_id, $PLATFORM_ID, $node_name, $event_type, 
		 $start_time, $stop_time,
		 $stop_reason]);

	}
    }
    close (EVENT_TRACE);
print "total avail: $total_avai \n";

}




# If the dir doesn't exist, create it                                                                                         
                                                                                                                              
sub createDir ($){
    my ($dir) = @_;                                                                                                           
                                                                                                                              
    if (! -e $dir){                                                                                                           
        print "Creating directory $dir\n";                                                                                    
        my $retval = mkdir($dir, 0777);                                                                                       
        if ($retval == 0)                                                                                                     
        {                                                                                                                     
            die "Fatal Error: $dir could not be created\n Message is: $!\n. Program Terminating....\n";                       
        }                                                                                                                     
    }                                                                                                                         
                                                                                                                              
}                                                                                                                             


# sort by probe number
sub by_pb_num {                                                                                                                                  
    my ($text_a, $pb_num_a) = split /\_+/, $a;
    my ($text_b, $pb_num_b) = split /\_+/, $b;
    
   if ($pb_num_a  > $pb_num_b){                                                                                                                              
        return 1;                                                                                                                                        
    } elsif ($pb_num_a == $pb_num_b){                                                                                                                        
        return 0;                                                                                                                                        
    } else {                                                                                                                      
        return -1;                                                                                                                                       
    }                                                                                                                                                    
}

sub extract_parameters()
{
	my %params = (
		inputdir => \(my $inputdir = undef),
		outputdir => \(my $outputdir = undef),

	);

	# Call Library function which will extract and remove all switches and
	# their corresponding values.
	# These parameters will be removed from @ARGV

	my $errorval = &GetOptions(\%params, "inputdir=s", "outputdir=s");
                        # the exclaimation point allows for the negation
                        # of the switch (i.e. -nobackup/-nobody is a switch)

	# Error value should have returned 1 if nothing went wrong
	# Otherwise, an unlisted parameter was specified.
	if($errorval !=1)
	{
		# Expecting GetOptions to state error.

		print "Exiting Program...\n";
		exit 0;
	}

	defined ($inputdir) or die "inputdir not defined\n";
	defined ($outputdir) or die "outputdir not defined\n";

	return ($inputdir, $outputdir);
	
}
