require "flush.pl";
require "$ENV{SERVER_BIN}/parse.pl";

#
# Parser.pl does the following things:
#
# 1) extracts user's address from header and saves in job.address
# 2) determines the solver being requested and saves in job.type
# 3) calls parse.pl to extract the data from job.received
# 4) wakes up the scheduler to schedule the parsed job
#

#
# Arguments
#

$jobNumber  = $ARGV[0]; 

#
# Misc. variables 
#

$| = 1; # don't buffer stdout


#
# Go to the job's directory
#

chdir("$ENV{SERVER_JOBS}/job.$jobNumber"); 
chomp($interface = `cat job.interface`);
open(jobHandle, ">>job.out");
print jobHandle "<CLEAR_SCREEN>\n";
print jobHandle "Parsing:\n\n"; &flush(jobHandle);

$ADDRESS = "unknown";

#
# Extract address from header in job.received
# and save in job.address
# 

if($ENV{SERVER_EMAIL_READY}) {
    $ADDRESS = "email";
    chomp($ADDRESS = `$ENV{SERVER_BIN}/address < job.received`);
} else {

    open(READ, "job.received") or (system("touch BAD_PARSE"));
    while(defined($line = <READ>)) {
	if($line =~ m/^From:(.*)$/) {
	    $ADDRESS = $1;
	    $ADDRESS =~ s/\s//g;
	    last;	     
	}
    }
}
			     
open (handle, ">job.address");
print handle "$ADDRESS\n";
close(handle);


#
# The first non-blank line after the email-style header should be
# either 1) the token "help" or 2) the token "type" followed by
# the token "solver."
#

open (HANDLE, "job.received"); 

#
# Skip past header (to first newline)
#

$lineCount = 1;
while (<HANDLE>) {
  $lineCount++;
  last if (/^\n$/);
}

#
# Skip white space after header
#

while (<HANDLE>) {
  $lineCount++;
  last if (/\S+/);
}

if (/help/i) {

  #
  # First non-blank line after header contains "help" 
  #
  # This is shortcut to typing:
  #
  # type admin
  # solver help  
  # help <type:solver>
  #

  $SOLVER = "ADMIN:HELP";
  $lineCount--;

} else {

  #
  # First non-blank line after header should contain "type" 
  #

  $SOLVER = "?:?";
  if (/type\s*=?\s*(\S+)/i) {
    $TYPE = "\U$1"; $TYPE =~ s/\s//g;
    while (<HANDLE>) {
      $lineCount++;
      last if (/\S+/);
    }

    #
    # Second non-blank line after header should contain "solver"
    #

    if (/solver\s*=?\s*(.+)/i) {
      $SOLVER = "\U$1"; $SOLVER =~ s/\s//g;
    } else {
      &parsingError("The second non-blank line after header specifies the solver.");
      &schedule($SOLVER, $jobNumber);
    }
  } else {
    &parsingError("The first non-blank line after the header should specify the type.  \nYour line:\n$_\n");
    &schedule($SOLVER, $jobNumber);
  }
  $SOLVER = "$TYPE:$SOLVER";
}
close(HANDLE);

unless (&solverExists($SOLVER)) {
    &parsingError("Solver \"$SOLVER\" does not exist or has been temporarily disabled.");
    &schedule($SOLVER, $jobNumber);
    exit(0);
}   

#
# If the SOLVER exists then use its config file to
# parse the data in job.received.
#

if ($SOLVER =~ /^ADMIN:.+$/) {
  $SOLVER_LIB = $ENV{SERVER_ADMIN_SOLVERS};
} else {
  $SOLVER_LIB = $ENV{SERVER_SOLVERS};
}


#
# Call parse() to extract the data from the file
#

if (&parse("$SOLVER_LIB/$SOLVER/config", $lineCount) == -1) {
    if($SOLVER eq "ADMIN:HELP") {
	unlink("BAD_PARSE");
    } else {
	&parsingError($errorMessage);
    }
}

#
# if "help.type" exists after parsing, then help is being requested
# for SOLVER.  We change the SOLVER to ADMIN:HELP and let it
# handle the request. 
#

if (-f "help.type") {
  if ($SOLVER ne "ADMIN:HELP") {
    system("echo $SOLVER > help.type");
  }
  $SOLVER = "ADMIN:HELP";
}

&received($SOLVER, $jobNumber, $ADDRESS, $interface);
&schedule($SOLVER, $jobNumber);

#
# Misc. Subroutines 
#

sub schedule {

  #
  # Save name of solver in job.type (with no newline char.)
  #

  open (handle, ">job.type");
  print handle $_[0];
  close(handle);


  #
  # Make the scheduler aware of the job and exit.
  #

  open (TYPE, ">$ENV{SERVER_SPOOL}/JOBS/job.$_[1]");
  print TYPE $_[0];
  close (TYPE);
  system("touch $ENV{SERVER_SPOOL}/JOBS/JOBS");

  #
  # Output for monitor
  #

  chop($date = `date`);
  if (-f "FORWARD") {
    chop($forward = `cat FORWARD`);
    print "$date: $_[0] job #$_[1] submitted via $interface by $ADDRESS($forward)\n"; &flush(STDOUT);
  } else {
    print "$date: $_[0] job #$_[1] submitted via $interface by $ADDRESS\n"; &flush(STDOUT);
  }
  exit(0);
}

sub solverExists {
  local(@SOLVERS, $solver);

  chomp(@SOLVERS = `cat $ENV{SERVER_VAR}/lib/solver_list`);
  chomp(@SOLVERS = (@SOLVERS, `cat $ENV{SERVER_LIB}/admin_list`));
  push(@SOLVERS, "Help Facility=ADMIN:HELP");
  foreach $solver (@SOLVERS) {
    $solver =~ /(.+)=(.+)/;
    if ($2 eq $_[0]) {
      return 1;
    }
  }
  return 0;
}

sub parsingError {
  local($count);
  system("touch BAD_PARSE");
  open(RESULTS,'>job.results');
  print RESULTS "Parsing Error:\n\n";
  print RESULTS "$_[0]\n\n";
  if ($interface eq "mail") {
    print RESULTS "Mail: \n\nhelp\nEND-SERVER-INPUT\n\nto $ENV{SERVER_EMAIL} for further information.\n\n";
  }
  print RESULTS "----------------------begin job-------------------------\n";
  open(handle, "job.received");
  while (<handle>) {
    $count++;
    printf RESULTS ("%4d $_", $count);  
  }
  close(handle);
  system("cat job.received >> job.results");
  print RESULTS "----------------------end job---------------------------\n";
  close(RESULTS);
}

sub received {
    local($solver) = $_[0];
    local($job) = $_[1];
    local($address) = $_[2];
    local($interface) = $_[3];

    undef $forwardaddress;
    if(open(IN, "$ENV{SERVER_JOBS}/job.$job/job.forward")) {
      $forwardaddress = <IN>;
      close IN;
      $forwardaddress =~ s/\s//g;
      $address = $forwardaddress;
    }

    if ($interface eq "mail" or defined($forwardaddress))
    {
	$passwd = "";
	if(open(PASS, "$ENV{SERVER_JOBS}/job.$job/job.password")) {
	    chomp($passwd = <PASS>);
	    close PASS;
	}
	open(MAIL, "|sendmail -oi -t") or print "System call sendmail inoperative\n" and return;
	print MAIL <<END_JOB_RECEIVED;
To: $address 
From: $ENV{SERVER_NAME} Server <$ENV{SERVER_COMMENTS}>
Subject: NEOS Job

The server received your job request for $solver and will 
schedule it for execution as job #$job with password $passwd.

END_JOB_RECEIVED
    close(MAIL);
        
    }
}

