#!@DASPERL

# bacon is a utility for performing tasks on a list of files

use FindBin;                     # find location of the this script 
use lib "$FindBin::Bin";         # make perl libraries available 
use Env;                         # make env vars readily available 
use File::Basename;              # for basename(), dirname() 
use File::Find;                  # for using Find command
use Getopt::Long;                # command line options
#use File::Copy;                  # for copy() 
#use Time::Local;                 # time functions 
#use CPAN::Shell qw(rcp rsh scp ssh);   # make C-shell commands available 
@line_list = ();

print "---------------------------------------------------------------------------------\n" if ($v) ;
initialize();
@ttl_lines_constructed = read_rc();

print "--- ttl_lines_constructed = @ttl_lines_constructed \n" if ($v);
run_lines(@ttl_lines_constructed);

exit (0);

sub initialize() {

$increment = 0;
$time_steps = 0;
# set default options
# -------------------
	$opt_1 = 0;
	$opt_d = "./";
	$opt_h = 0;
	$opt_rc = "bacon.rc";
	$opt_v = 0;
	$remote_shell = 'rsh';
	$exit_code = 0;

# command line options
# --------------------
	my $rc= GetOptions( "1", "d=s",  "h", "rc=s", "v"); 
	print "rc = $rc \n";

	manpage() if ( $opt_h || $#ARGV <0 || $ARGV[0] eq 'help' || !$rc ); 
	$nofork = $opt_1;
	$work_dir = $opt_d;
	$rc_file_use = $opt_rc;
	$v = $opt_v;

# check for conflicting option settings
	##
	##

	if (dirname($0) ne "" ) {
		if ($opt_rc eq "bacon.rc" ) { 
			$rc_file_use = dirname ($0) . "/" .  $rc_file_use; 
		}	
	}

	$work_dir = "$work_dir\/";

	print "THE FOLLOWING OPTIONS HAS BEEN SET \n";
	print "================================== \n";
	print "nofork      = $nofork 		\n";
	print "verbose     = $v 		\n";
	print "work_dir    = $work_dir 		\n";
	print "rc_file_use = $rc_file_use 	\n";
	print "================================== \n";

	#if ($work_dir ne './' ) {chdir $work_dir; print "Directory changed to $work_dir\n";}

	$pwd = `pwd`;
	print "current directory  = $pwd \n";


}

sub read_rc {
# get list of files from rc file
     print "Read Resource File..." if ($v);

     my @ttl_lines_constructed 	= ();
     my @line_list_temp  	= ();
     my $temp            	= "";
     unless ( open( RCFILE, $rc_file_use ) ) { 
         print  "(acquire) ERROR: Configuration file '", $rc_file_use, "' can not be opened.\n"; 
         exit (1); 
      } 
      while ( <RCFILE> ) { 
		 chop; 
		 if ((! /^#/ )&&(/.{1,}/))  { 
			#chomp( $line = $_ ); 
			push (@line_list_temp, "$_\n");
			my @lines_constructed     = "";
			my $first_string          = "";
			my $expanded_first_string = "";
			$line = $_;
			#$line1 = quotemeta($line);
		print "\n" if ($v);
		print "\n" if ($v);
		print "\n" if ($v);

		print "---------------B E G I N---------------\n" if ($v);
		print " line = $line \n" if ($v);
			@temp_line = ();
			@temp_line 		= split(" ", $line, 99999);
		print " >>> temp_line = @temp_line \n" if ($v);
			$first_string 		= shift @temp_line;
		print " process_rc : first_string 	= $first_string \n" if ($v) ;
			$expanded_first_string 		= expand_searchstring($first_string);
		print " process_rc : expanded first_string = $expanded_first_string \n" if ($v);
			$first_string           = quotemeta ($first_string);
		print " quotemeta process_rc : first_string 	= $first_string \n" if ($v);

			my @lines_constructed  	        = "";
			@lines_constructed 	        = construct_lines($expanded_first_string, $first_string, @temp_line);
		print "\n" if ($v);
		print " >>> lines_constructed = \n" if ($v);
		print "@lines_constructed\n"  if ($v);
		print "----------------E N D -----------------\n" if ($v);
		foreach $temp (@lines_constructed) {
			push (@ttl_lines_constructed , "$temp END_OF_A_RECORD");
		}
		#	push (@ttl_lines_constructed , "END_OF_RECORD");	

		
         	} 
      } 
      close( RCFILE ); 
print "Resource File Read" if ($v);
return (@ttl_lines_constructed);

}


sub expand_searchstring {
     my ( $file ) = @_;
     #my ( $yyyy,$yy,$mm,$dd,$hh,$file ) = @_; 
     ($file = $file) =~ s/%y4/[0-9][0-9][0-9][0-9]/g; 
     ($file = $file) =~ s/%y2/[0-9][0-9]/g; 
     ($file = $file) =~ s/%m3/[A-Za-z][A-Za-z][A-Za-z]/g;
     ($file = $file) =~ s/%m2/[0-1][0-9]/g; 
     ($file = $file) =~ s/%d2/[0-3][0-9]/g; 
     ($file = $file) =~ s/%h2/[0-2][0-9]/g; 
     ($file = $file) =~ s/%s/^\.(.*?)/g; 
     #($file = $file) =~ s/%n/[^A-Za-z]/g; 
     return $file; 
} 

sub construct_lines {	
	my ($expanded_first_string, $first_string, @temp_line) = @_;
	my @lines_constructed = "";
	my $single_line = "";
	print " construct_lines - \n" if ($v);
	print " construct_lines - expanded_first_string = $expanded_first_string\n" if ($v);
	print " construct_lines - first_string = $first_string\n" if ($v);
	print " construct_lines - temp_line    = @temp_line\n" if ($v);
	chdir ($work_dir);
	find sub {
		$filename_temp 	= basename ($File::Find::name);
		if ($v) {print "  --- Found ---> $filename_temp \n" if (/$expanded_first_string/); }
		if (/$expanded_first_string/) {
			@temp_line_NOT = ();
		 	$single_line = construct_single($filename_temp, $first_string, @temp_line);
			print "  construct_lines :  single_line = $single_line \n" if ($v);
			push (@lines_constructed, $single_line);
		} 
	},
	'.';
	chdir($pwd);
	return (@lines_constructed);
}

sub construct_single {
	my ($filename_temp, $first_string, @temp_line ) = @_;
	my $construct_final_line = "";
	my $second_string = "";
	print "  construct_single -  \n" 				if ($v);
	print "  construct_single - temp_line = @temp_line\n" 		if ($v);
	print "  construct_single - filename_temp = $filename_temp\n" 	if ($v);
	print "  construct_single - first_string = $first_string\n" 	if ($v);
	foreach	$temp_element (@temp_line) {
		print "  construct_single: temp_element = $temp_element <------------- \n"	if ($v);
		if ($temp_element =~ /\%s(.*)/) {
			print "  construct_single : string found ---  calling construct_2ndstring \n" if ($v);
			$second_string = construct_2ndstring($first_string, $filename_temp, $temp_element); 
			$construct_final_line = "$construct_final_line $work_dir$second_string";
		} elsif ($temp_element =~ /\%file/) {	
			$construct_final_line = "$construct_final_line $work_dir$filename_temp";
		} else {
			$construct_final_line = "$construct_final_line $temp_element";
		}
	}
	$construct_final_line = "$construct_final_line\n";
	return ($construct_final_line);
}

sub call_pasta {
	my ($filename_temp, $first_string) = @_;
	my $y4 = $y2 = $m2 = $m3 = $d2 = $h2 = $s = $h = "";
	$first_string =~ s/\\//g;
	$filename_temp = basename ($filename_temp);

	print "  call_pasta \n"						if ($v);
	print "  call_pasta filename_temp = $filename_temp \n"		if ($v);
	print "  call_pasta first_string  = $first_string  \n"		if ($v);

	#$results = system ("home/jyoon/yoon/bacon/pasta $filename_temp $first_string");
	#$results = system("/home/jyoon/yoon/bacon/pasta");

	$results = `/home/jyoon/yoon/bacon/pasta $filename_temp $first_string`;
	print "  call_pasta results = $results \n"			if ($v);	
	($y4, $y2, $m2, $m3, $d2, $h2, $s, $h) = split (" " , $results);
	#	($y4, $y2, $m2, $m3, $d2, $h2, $s) = system("pasta $filename_temp $first_string");
	print "  call_pasta results =  $y4, $y2, $m2, $m3, $d2, $h2, $s \n" if ($v);
	return ($y4, $y2, $m2, $m3, $d2, $h2, $s);
}
	
sub construct_2ndstring {
	my ($first_string, $filename_temp, $temp_element) = @_; 
	my $y4 = $y2 = $m2 = $m3 = $d2 = $h2 = $s = "";
	print "  inside of construct_2ndstring \n"					if ($v);
	print "  inside of construct_2ndstring first_string = $first_string\n"		if ($v);
	print "  inside of construct_2ndstring filename_temp = $filename_temp\n"	if ($v);
	print "  inside of construct_2ndstring before  temp_element = $temp_element\n"	if ($v);

	# ($y4, $y2, $m2, $m3, $d2, $h2, $s) = call_pasta($filename_temp, $first_string);

	($y4, $y2, $m2, $m3, $d2, $h2, $s) = pasta_replacement($filename_temp, $first_string);
     	$temp_element =~ s/%y4/$y4/g; 
	$temp_element =~ s/%y2/$y2/g; 
     	$temp_element =~ s/%m3/$m3/g;
     	$temp_element =~ s/%m2/$m2/g; 
     	$temp_element =~ s/%d2/$d2/g; 
     	$temp_element =~ s/%h2/$h2/g; 
     	$temp_element =~ s/%s/$s/g; 
	print "  inside of construct_2ndstring after   temp_element = $temp_element\n"	if ($v);
	return ($temp_element);
}

sub run_lines {
	my (@lines_to_run ) = @_;

	$lines_scaler = join (" ", @lines_to_run);
	@lines_array = split ("END_OF_A_RECORD", $lines_scaler);

	# test system call 
	#push (@lines_array , "ls -glas ");	

	foreach $lines_single (@lines_array) {	
	     chomp ($lines_single);
		 
	     if ($lines_single =~ /\w+/) {
		print "\n";
		if ($lines_single =~ /\&/ && ! $nofork ) {	
			print " >>>- BACKGROUND LAUNCH --> $lines_single\n";
		} else {
			print " >>>- Launching ---> $lines_single\n " ;
		}
		$exit_status = system ("$lines_single");
		if ($exit_status) {
			print " !!! exit_status = $exit_status  \n";
		} else {
			print " - SUCCESSFUL -> $lines_single \n";
		}
		print "\n" if ($v);
	     }
	}
A
}

sub pasta_replacement {

	# Same function as Pasta.c
	# but written in perl.

	my ($filename_temp, $first_string) = @_;
	print "first_string  = $first_string \n  filename_temp = $filename_temp\n" if ($v);
	$y4 = "yyyy"; $y2 = "YY"; $m2 = "mm"; $m3 = "MMM"; $d2 = "DD"; $h2 = "HH"; $s  = "";   

	$first_string =~ s/\\//g;      
	$filename_temp = basename ($filename_temp);    
	$first_string =~ s/%y4/yyyy/g;
	$first_string =~ s/%y2/YY/g;
	$first_string =~ s/%m3/MMM/g;
	$first_string =~ s/%m2/mm/g;
	$first_string =~ s/%d2/DD/g;
	$first_string =~ s/%h2/HH/g;

	$string_index = index ($first_string, "%s");
	$period_index = index ($filename_temp, ".", $string_index);
	$string_length = $period_index - $string_index;
	$s = substr ($filename_temp, $string_index, $string_length);
	$first_string  =~ s/%s/$s/g;

	if ($first_string =~ /yyyy/) {
		$index_temp = index($first_string, "yyyy");
		$y4    = substr ($filename_temp, $index_temp, 4);
	}
	if ($first_string =~ /YY/ ) {
		$index_temp = index($first_string, "YY" );
		$y2    = substr ($filename_temp , $index_temp, 2);
	}
	if ($first_striong =~ /MMM/ ) {
		$index_temp = index($first_string, "MMM" );
		$m3         = substr ($filename_temp, $index_temp, 3);
	}
	if ($first_string =~ /mm/ ) {
		$index_temp = index($first_string, "mm" );
		$m2         = substr ($filename_temp, $index_temp, 2);
	}
	if ($first_string =~ /DD/) {
		$index_temp = index($first_string, "DD" );
		$d2         = substr ($filename_temp, $index_temp, 2);
	}
	if ($first_string =~ /HH/) {
		$index_temp = index($first_string, "HH" );
		$h2         = substr ($filename_temp, $index_temp, 2);
	}
	print "  pasta results =  $y4, $y2, $m2, $m3, $d2, $h2, $s \n" if ($v);   
	#print "  pasta results =  $y4, $y2, $m2, $m3, $d2, $h2, $s \n" ;   
	return ($y4, $y2, $m2, $m3, $d2, $h2, $s);
}

#......................................................................

sub manpage {
print<<"EOF1";

NAME
	bacon - (Ba)tch File (Con)verter

SYNOPSIS
	
	bacon [...options...]

DESCRIPTION
	
	Bacon is a general purpose utility for launching batch jobs using a list
	of file templates specified in the resource file (see RESOURCE FILE below).
	It performs tasks on a list of files specified by means of GrADS 
	like templates.
	For example, a resource file could specify a file name of the form: 
	  %s.bkg.eta.%y4%m2%d2.nc4   dyn2prs.x -o %s.ana.prs.%y4%m2%d2.nc4 %file	

OPTIONS
	
	-1 		single processor mode (no forks) .  This mode overrides the
			 "&" (ampersand) option set in the resource files and
			forces Bacon to wait for completion of each executable listed
			in the resource file before moving on to next executable. 
	-d path 	working (local) directory (default: ./)
	-rc fname 	resource file name (default: bacon.rc)
	-v		verbose mode (default is real quiet)
	-h		help, prints this page
	

RESOURCE FILES

	Bacon resource files ( bacon.rc) consist of comment lines starting with
	'#' or a file name templates of the form
		
	filetemplate	executable [ options ] [ filetemplate2,3,4 ] file [ & ]

        SHORT EXPLANATION : 

		First, Bacon finds all files that match the first file template 
		Second, the GrADS like patterns are extracted and second, third, or fourth 
			set of "file templates" is expanded.
		Third, the "executable" is launched.

	For example, a typical line in the bacon.rc file would be:
		
	%s.bkg.eta.%y4%m2%d2.nc4   dyn2prs.x -o %s.ana.prs.%y4%m2%d2.nc4 %file &
	%s.bkg.eta.%y4%m2%d2.nc4   coards2grib %file 

	In this example, the filename "template" is a GrADS like pattern for
	matching file names. 
	Supported tokens are:
		
          %y4       year,  e.g., 1997 
          %y2       year,  e.g., 97 
          %m2       month, e.g., 12 
          %d2       day,   e.g., 31 
          %h2       hour,  e.g., 18 
 
	  %s	    any string, e.q., v016a_b55
	
	In addition to GrADS-like tokens, any defined environment variable
	can be used in the file name template.  


     ------------------------------------------
        DETAILED EXPLANATION OF ABOVE EXAMPLE: 
     ------------------------------------------

		First, the first file-template (%s.bkg.eta.%y4%m2%d2.nc4) is used 
		to find all files that match the template.

		Lets assume it found the following 3 files: 
			v016a_b55.bkg.eta.19971231.nc4
			vaaaa_v12.bkg.eta.19981131.nc4
			vffff_a11.bkg.eta.19990128.nc4

		From here, Bacon utilizes the same logic found in Pasta.pl to 
		extract the GrADS like patterns such as %y4, %m2, %d2, %s...
		
		These matched values are pluged into the second file-template 
		if found, %s.ana.prs.%y4%m2%d2.nc4 and expanded to produce :
	
			v016a_b55.ana.prs.19971231.nc4
	
		Same is done with the remaining files found above,
                    	vaaaa_v12.bkg.eta.19981131.nc4
                        vffff_a11.bkg.eta.19990128.nc4

		As a result, bacon will have the following lines queued for launch.

	    dyn2prs.x -o v016a_b55.bkg.eta.19971231.nc4 v016a_b55.ana.prs.19971231.nc4 &
	    dyn2prs.x -o vaaaa_v12.bkg.eta.19981131.nc4 vaaaa_v12.ana.prs.19981131.nc4 &
	    dyn2prs.x -o vffff_a11.bkg.eta.19990128.nc4 vffff_a11.ana.prs.19990128.nc4 &

     -----------------
      RC file Options
     -----------------

      & (ampersand )  - if an ampersand is attached at the end of a line in a
	resource file, that particular executable will be launched in the 
	background. 

	Example: 

	%s.bkg.eta.%y4%m2%d2.nc4   dyn2prs.x -o %s.ana.prs.%y4%m2%d2.nc4 %file &
	
	In this case, dyn2prs.x and it's arguments will be executed with the & (ampersand)
	attached. This is useful if you don't want to wait around for one job to finish.

     --------------------------------------------------------------------------------------
     
SEE ALSO

	acquire - data acquisition utility

	pesto   - (P)ut (E)xperiments in Mass (Sto)rage 

	pasta   - Utility that returns experiment id, year, month, day, hour
   given a file name and a GrADS-like template

AUTHORS

	Joon Yoon (jyoon\@dao.gsfc.nasa.gov)
	Arlindo da Silva (dasilva\@dao.gsfc.nasa.gov)
	
EOF1
  exit(1)

}

