#!/s/std/bin/perl -I/p/gams/remote_condor
# daemon.pl: Monitoring the condor directory ($DaemonRootdir) to submit
#            to gams on SUN OS machine using CONDOR, results are returned
#            to user via email.
#
# Requirement:
# 1. Only work with *.gms with the 'solve' statement in them.
# 2. The script will look for file names after '$include' and
#    '$batinclude' command for submission and 'file' command for output.
#
# Krung Sinapiromsaran, 5/18/2000

# Initialize PERL setting.
$| = 1;           # Flush output for every print command.

# String list of files to do submission and send to email
$GAMSinfiles  = '';
$GAMSoutfiles = '';

# Default setting
%users = ();
$screen = 1;
# Check option if we need to interact on screen or not.
foreach $i (@ARGV) {
  next unless ($i =~ /^-/);
  $screen = 0 if($i =~ /quiet/i); 
}
use InitDaemon;

#######################
#  Program Start here #
#######################
# Generate the log file
chdir($DaemonRootdir);
&Get_time(@DaemonMonth);
$message = "Start log on $date at $timestamp.";

# Clear the log file
$filename = $DaemonRootdir. $DirSep . $DaemonLog;
open(OUT, ">$filename") || die "Cannot open logfile $!\n";
close(OUT);
chmod(0666, $filename);

&Write_log($DaemonRootdir.$DirSep, $DaemonLog, $message); 
print $message, "\n" if $screen;

# Get user information
@allusers = &Read_user($DaemonRootdir.$DirSep, $DaemonDatafile);
# print "@allusers\n" if $screen;

# Loop forever
while(1) {
  # Go up the root directory
  chdir($DaemonRootdir);

  # Look through all users
  foreach $user (@allusers) {
    next if ($user =~ /^$DaemonExcludedir/);

    # Set the user directory assuming, there exists user directory
    $f_dir = $DaemonRootdir.$DirSep.$user;
    last unless (-d $f_dir);

    # Make sure the user can access their directory
    chmod(0755, $f_dir);
    # print "$user\n" if $screen;

    # Check all processes of the form *.run/ for result of submission
    #                             and *.gms  for new CONDOR submission
    opendir(DIR, $f_dir) || die "Cannot read $f_dir $!\n";
      @temp = readdir(DIR);
      @rundirs = grep(/$DaemonExtRun/, @temp);
      @gams    = grep(/$DaemonExtGams/, @temp);
    closedir(DIR);
    #    print "$user: @rundirs, @gams\n" if $screen;

    # Get a new time
    &Get_time(@DaemonMonth);
    &CheckNewSubmission($user, @gams);
    &CheckOldSubmission($user, @rundirs);
  # End of all possible users
  }
  # last;
  # Go to sleep for 20 seconds 
  sleep(20);

# End of loop forever
}
1;

sub CheckNewSubmission {
#   Create a new submission for GAMS condor to run on SUN OS platform
    local($user, @gams) = @_;
    local($fname, @GAMSlist, $filename, $check);

    # Check for new submission.
    # print "$user, @gams\n" if $screen;
    foreach $f (@gams) {
       # Check if the model contains solve statement
       $check = &GamsCheck($DaemonRootdir.$DirSep.$user, $f, $screen);
       next unless $check;

       # Trim the name by getting rid of the GAMS extension
       $f =~ s/$DaemonExtGams//;

       # If there is a run directory then report the duplication via email
       $f_dir = $DaemonRootdir.$DirSep.$user.$DirSep;
       if(-d "$f_dir$f$DaemonExtRun") {
          &DuplicateFile($user, $f);
	  next;
       }

       # Prepare the new CONDOR submission.
       $message = "New submission $user:$f -> $date at $timestamp.";
       &Write_log($DaemonRootdir.$DirSep, $DaemonLog, $message);
       print $message, "\n" if $screen;

       # Create a CONDOR submission directory
       mkdir("$f_dir$f$DaemonExtRun", 0777);
       chmod(0777, "$f_dir$f$DaemonExtRun");

       # Make sure that the CONDOR can write on this directory
       $psdir = $f_dir.$f.$DaemonExtRun;
       system "$DaemonFsdir\/fs setac $psdir $DaemonAfsuser write";

       # Create a batch file for solving this GAMS
       &Create_rungams($psdir.$DirSep.$DaemonRungams);

       # Create a CONDOR submission file
       &Create_submission($user, $f, $psdir.$DirSep.$f.$DaemonExtCondor,
			  $GAMSinfiles, $GAMSoutfiles);

       # Make sure that it is readable by all
       $filename = $psdir.$DirSep.$f.$DaemonExtGams;
       rename("$f_dir$f$DaemonExtGams", $filename);
       chmod(0766, $filename);

#       print "Additional files: $GAMSinfiles, $GAMSoutfiles \n" if $screen;
       # Move all files related to this GAMS
       @GAMSlist = split(/,/, $GAMSinfiles);
       foreach $fname (@GAMSlist) {
	  $fname =~ s/\s//g;
	  next unless $fname;
          $filename = $psdir.$DirSep.$fname;
          rename("$f_dir$fname",  $filename);
          chmod(0766, $filename);
       }

       # Submit CONDOR job in this directory
       chdir("$f_dir$f$DaemonExtRun");
       $command = "$DaemonCondordir\/condor_submit $f$DaemonExtCondor";
       $command .= " > /dev/null" unless $screen;
       system $command;
    }
}

sub GamsCheck {
#   Check the GAMS $include and $batinclude for input files and
#   'file' for output file
    local($dir, $f, $screen) = @_;
    local($result, $fname, $junk1, $junk2);

    # Initialize the input and output files
    $GAMSinfiles = '';
    $GAMSoutfiles = '';
    $result = 0;

    # Go inside the user directory
    open(IN, $dir.$DirSep.$f);
       while(<IN>) {
           chop;
           # First make sure that 'solve' statement is in the GAMS file
           $result = 1 if(/^\s*solve\s+/i);

           # Look for file name after '$include' or '$batinclude' statement
           if(/^\$include\s+(\S+)\s*/) {
              $fname = $1; $fname =~ s/\"//g;
              #   Add the file name only if it exists.
              if(-e "$dir$DirSep$fname") {
                  $GAMSinfiles .= ", $fname";
              } elsif(-e "$dir$DirSep$fname$DaemonExtGams") {
                  $GAMSinfiles .= ", $fname$DaemonExtGams";
              } else {
        	return $result;
              }
           }
           if(/^\$batinclude\s+(\S+)\s*/) {
              $fname = $1; $fname =~ s/\"//g;
              #   Add the file name only if it exists.
              if(-e "$dir$DirSep$fname") {
                  $GAMSinfiles .= ", $fname";
              } elsif(-e "$dir$DirSep$fname$DaemonExtGams") {
                  $GAMSinfiles .= ", $fname$DaemonExtGams";
              } else {
        	return $result;
              }
           }

	   # Look for file name after 'file' statement
           if(/^\s*file/) {
              ($junk1, $fname, $junk2) = split(/\//, $_);
              $fname =~ s/\s//g;
              $GAMSoutfiles .= ", $fname";
           }
       }
    close(IN);
    print "$f: $GAMSinfiles, $GAMSoutfiles\n" if $screen;
    $result;
}

sub DuplicateFile {
    local($user, $file) = @_;
    # Email the user of this duplicate file 
    open(MAIL, "| $DaemonMaildir\/sendmail $user$DaemonExtEmail");
         print MAIL "Subject: Duplicate file -> $file$DaemonExtGams\n";
         print MAIL "There is a job with the name $file$DaemonExtGams\n";
    close(MAIL);
}

sub Create_rungams {
    local($filename) = @_;
# Create rungams 
open(OUT, ">$filename") || die "Cannot create $filename $!\n";
print OUT<<GAMSPAGE;
#!/bin/csh
set path = ( $DaemonGAMSdir . $DaemonCPLEXdir \$path )
setenv CPLEXLICENSE $DaemonCPLEXdir\/cplexlicfile
$DaemonGAMSdir\/gams \$1 \$2
GAMSPAGE
close(OUT);
chmod(0755, $filename);
}

sub Create_submission {
    local($user, $f, $filename, $infiles, $outfiles) = @_;
# Create submittion file
open(OUT, ">$filename");
print OUT<<CONDOR_SUB;
##########################################################
# Condor Submit file for GAMS
# Written for Krung Sinapiromsaran 
##########################################################
executable = $DaemonRungams
universe = vanilla
transfer_input_files = $DaemonRungams, $f$DaemonExtGams$infiles
transfer_output_files = $f$DaemonExtLst, $f$DaemonExtLog$outfiles 
arguments = $f$DaemonExtGams $DaemonGamsParameter
getenv = True
log = $user$DaemonExtLog
notify-user = $user$DaemonExtEmail
notification = Error
queue
CONDOR_SUB
close(OUT);
chmod(0766, $filename);
}

sub CheckOldSubmission {
# Check the old submission, email results to the user if it is complete.
    local($user, @rundirs) = @_;

    foreach $f (@rundirs) {
       # Strip off run extension
       $f =~ s/$DaemonExtRun//;

       # Check the existence of run directory
       $f_dir = $DaemonRootdir.$DirSep.$user.$DirSep.$f.$DaemonExtRun;

       $filename = $f_dir.$DirSep.$user.$DaemonExtLog;

       # Open the CONDOR log file to check if it terminates normally
       if(-e $filename) {
          open(IN, $filename);
          while(<IN>) { last if /$DaemonExitmessage/i; }
          close(IN);

          if(/$DaemonExitmessage/i) {
             # Found the terminated CONDOR message, i.e. the job is done!
             chdir("$DaemonRootdir$DirSep$user");

             # Looking inside the CONDOR submission to get the output file names
             $fcon = $f.$DaemonExtCondor;
             open(IN, "$f_dir$DirSep$fcon") || die "Cannot read $fcon $!\n";
                  while(<IN>) {
                    if(/$DaemonOutputmessage/i) {
                       # Lists of files to get from
                       ($junk, $usedfiles) = split(/\=/, $_);
                       $usedfiles =~ s/\,//g;
                       @outfiles = split(/\s+/, $usedfiles);
                       last;
                    }
                  }
             close(IN);
   
             # Email results to the user 
             open(MAIL, "| $DaemonMaildir\/sendmail $user$DaemonExtEmail");
                  print MAIL "Subject: $f$DaemonExtLst$GAMSoutfiles\n";
                  print MAIL "CONDOR Daemon version $DaemonVersion\n";
	          print MAIL "running $DaemonOS ";
                  print MAIL "on $date at $timestamp.\n\n";
                  foreach $out (@outfiles) {
                     next unless $out;
                     print MAIL "\n";
                     print MAIL "=" x 20, " Start  $out ", "=" x 20, "\n";
                     open(IN, "$f_dir$DirSep$out");
                        while(<IN>) {print MAIL;}
                     close(IN);
                     print MAIL "=" x 20, " End of $out ", "=" x 20, "\n";
                  }
             close(MAIL);

             # Remove the directory
             system "$DaemonBindir\/rm -r $f_dir";
   
             # Updated the logfiles
             $message = "Remove job $user:$f -> $date, $timestamp.";
             &Write_log($DaemonRootdir.$DirSep, $DaemonLog, $message);
             print "Remove job $user:$f -> $date at $timestamp\n" if $screen;
          }
       } else {
          # Do submit CONDOR job again in this directory
          chdir("$f_dir");
          $command = "$DaemonCondordir\/condor_submit $f$DaemonExtCondor";
          $command .= " > NUL" unless $screen;
          system $command;
       }
    }
}

sub Get_time {
#   Get the current date and time
    local(@month) = @_;
    # Get the new time
    ($sec,$min,$hour,$mday,$mon,$year) = localtime(time);
    $year += 1900;
    # Keep date and time format
    $date = "$mday $month[$mon] $year";
    $timestamp = "$hour\:$min\:$sec";
    # Start from the daemon directory
}

sub Write_log {
#   Writing the log file
    local($daemon_dir, $daemonlog, $message) = @_;
    open(LOG, ">>$daemon_dir$daemonlog");
         print LOG $message, "\n";
    close(LOG);
}

sub Read_user {
#   Read all users of this CONDOR-GAMS daemon directories
    local($dir, $file) = @_;
    @allusers = ();
    open(IN, "$dir$file") || die "Cannot read user files $!\n";
         while(<IN>) {
	     chop;
             push(@allusers, $_);
	 }
    close(IN);
    @allusers;
}

