#!/usr/bin/env perl
#----------------------------------------------------------------------------
#
# Name: eng_hold.pl
#
# This perl script is used for three pipeline processes. The resource file or
# target_class name specifies the database records that is uses to control the
# pipeline. Interactive mode is used only during testing as it cannot update
# or create OSFs.
#
# Interactive Usage:
#	>eng_hold.pl <eng_rootname> -c <target_class>
#
#       where eng_rootname is Tyyyydddhhmm (no extension), and
#       <target_class> is FGS, GSA, or AST.  In interactive mode the
#       product_eng_map is updated and tested, and the test results
#       are logged but no OSFs are updated.
#
# Pipeline Usage:
#       command:eng_hold.pl 
#     
#       In the pipeline the resource file must set the following ENV 
#       variables: OSF_DATASET, TARGET_CLASS, TARGET_NEW, TARGET_COLUMN,
#       TARGET_READY, and TARGET_WAITING.
#
#	Note that the following environment variables (logicals) are 
#       always required in both modes: OPUS_SERVER and OPUS_DB.
#
#
# History:
# mm/dd/yy OPR      Who         Reason
# -------- -------- ----------  ---------------------------------------------
# 06/26/01 43966    Baum        Initial code
# 04/29/02 45738    Baum        Use external subroutines.
# 10/16/02 46785    Baum        Support lowercase OSF rootnames
# 10/31/02 46785-02 Baum        Retry after OSF_CREATE failure
# 05/16/03 48573    Baum        Use qolink_sms.status for non-GSA types. Set
#                               complete_status
# 06/09/03 48573-01 Baum        Move db2->dbclose to assure success, set
#                               Set dataset_type for EPC. Update interactive
#                               interface for EPC processing.
# 08/11/05 53803    MSwam       Replace PATH_FILE_NAME with PATH_BASENAME
# 10/22/09 44712    MSwam       Replace ST_DBlib with DBI interface
# 06/30/10 64432    MSwam       Use single quotes for SQLServer
# 08/22/11 48287    LThompson   Alter log messages to track FGS OSF conflicts 
#                                   between rjhold, rcheck, and gsacqd
# 09/18/12 72255    Sherbert    get rid of DSQUERY
#----------------------------------------------------------------------------

# set up external routines
unshift @INC,(split /:/, $ENV{PATH});
require 'printmsg.pl';       # prints a formatted status message
require 'do_dbi_pkg.pl';     # run queries that return records

#specify exit status values

    $OSF_FAILURE =      1;   # exit status for XPOLL
    $OSF_NO_PRODUCTS =  9;   # exit status for XPOLL
    $OSF_HOLD =        11;   # exit status for XPOLL

#check for arguments

    $num_arg = scalar @ARGV;

    if ($num_arg > 0 && substr($ARGV[0],0,1) ne "-") {
      $interactive = 1;
    } else {
      $interactive = 0;
    }
    if ($interactive) {
      $fail_msg = 
        "Usage example: >eng_hold.pl T20012430600 -c FGS\nTry again.\n"; 
      if ($num_arg != 3) {
        print $fail_msg;
        exit( $OSF_FAILURE);
      }
      # Verify arguments
      $osf_root = $ARGV[0];
      $eng_root = uc($ARGV[0]);
      if (!($eng_root=~/^T\d\d\d\d\d\d\d\d\d\d\d$/)) {
        print $fail_msg;
        exit( $OSF_FAILURE);
      }
      if ($ARGV[1] ne "-c") {
        print $fail_msg;
        exit( $OSF_FAILURE);
      }
      $target_class = uc($ARGV[2]);
      if ($target_class ne "FGS" &&
          $target_class ne "GSA" &&
	  $target_class ne "EPC" &&
          $target_class ne "AST") {
        print "Third argument must be FGS, GSA, EPC or AST\n";
        exit( $OSF_FAILURE);
      }
      $target_ready = "TARGET_READY";
      $target_waiting = "TARGET_WAITING";
    } else { # not interactive
      # Verify ENV variables
      $osf_root = $ENV{"OSF_DATASET"};
      $eng_root = uc($osf_root);
      $path    = $ENV{"PATH_BASENAME"};
      $colon   = rindex($path,":");
      $path    = substr($path,$colon+1);
      $target_class = uc($ENV{"TARGET_CLASS"});
      $target_new = $ENV{"TARGET_NEW"};
      $target_column = $ENV{"TARGET_COLUMN"};
      $target_ready = $ENV{"TARGET_READY"};
      $target_waiting = $ENV{"TARGET_WAITING"};
      if (!defined($eng_root) || !defined($target_class) || 
          !defined($target_new) || !defined($target_column) ||
          !defined($target_ready) || !defined($target_waiting)) 
      {
        PrintMsg("E","Missing ENV variable in resource file.");
        PrintMsg("E",
    "Need: TARGET_CLASS,TARGET_NEW,TARGET_COLUMN,TARGET_READY,TARGET_WAITING");
        exit( $OSF_FAILURE);
      }
    } # end if interactive
    $OPUS_SERVER=          $ENV{"OPUS_SERVER"};
    $OPUS_DB=           lc($ENV{"OPUS_DB"});
    $data_id=           lc($target_class);
    $data_class=        $target_class;
    if ($data_class eq "EPC") {$data_class = "FGS";}
          
# begin processing

    PrintMsg ("I","--- start --- Check and Hold $osf_root File -------");
#---------------------------------------------------------------------
# open database for queries
#---------------------------------------------------------------------
    $db = DoDBIopen( $OPUS_SERVER, $OPUS_DB, $OSF_FAILURE);
#---------------------------------------------------------------------
# update status in product_eng_map
#---------------------------------------------------------------------
    $query = <<"EOQ";
UPDATE product_eng_map
SET eng_ready = 'Y'
WHERE eng_rootname='$eng_root' and product_type='$target_class'
EOQ

    $update_count = DoDBI( $db, $query);

    if (!defined($update_count)) {
      $process_status = $OSF_FAILURE;
    } elsif ($update_count == 0) {
      PrintMsg("I","No $target_class products need this file.");
      PrintMsg("I","File not held for $target_class products.");
      $process_status = $OSF_NO_PRODUCTS;
    } else { 
#---------------------------------------------------------------------
#  Count incomplete products using product_eng_map and product_status
#---------------------------------------------------------------------

$query = <<"EOQ";
SELECT COUNT(m.product_rootname) 
FROM product_eng_map m, product_status s
WHERE m.eng_rootname='$eng_root' and
  m.product_type='$target_class' and
  m.product_rootname = s.product_rootname and
  m.product_type = s.product_type and
  s.complete_flag = 'N'
EOQ

      $err_msg = "Cannot query incomplete product count.";
      @product_count = DoDBIselect( $db, $query);
      if ($product_count[0] == 0) {
        PrintMsg("I","No incomplete $target_class products need this file.");
        PrintMsg("I","File not held for $target_class products.");
        $process_status = $OSF_NO_PRODUCTS;
      } else {

#---------------------------------------------------------------------
#  Use product_eng_map (twice) and product_status to find all products,
#  completion status, and the minimum eng_ready status for all
#  eng files of that product. 
#---------------------------------------------------------------------

        if ($target_class ne "GSA") {

$query = <<"EOQ";
SELECT m.product_rootname, s.complete_flag, q.status, MIN(m2.eng_ready) 
FROM product_eng_map m, product_status s, product_eng_map m2, dataset_link l,
  qolink_sms q
WHERE m.eng_rootname='$eng_root' and
  m.product_type='$target_class' and
  s.product_rootname = m.product_rootname and
  s.product_type = m.product_type and
  m2.product_type = s.product_type and
  m2.product_rootname = s.product_rootname and
  l.dataset_rootname = m.product_rootname and
  l.dataset_type = '$data_class' and
  q.program_id = l.program_id and
  q.obset_id = l.obset_id and
  q.ob_number = l.ob_number
GROUP BY m.product_rootname, s.complete_flag, q.status
EOQ

#---------------------------------------------------------------------
#           open second database for product_status
#---------------------------------------------------------------------
            $db2 = DoDBIopen( $OPUS_SERVER, $OPUS_DB, $OSF_FAILURE);
        } else {

$query = <<"EOQ";
SELECT m.product_rootname, s.complete_flag, '/', MIN(m2.eng_ready) 
FROM product_eng_map m, product_status s, product_eng_map m2
WHERE m.eng_rootname='$eng_root' and
  m.product_type='$target_class' and
  s.product_rootname = m.product_rootname and
  s.product_type = m.product_type and
  m2.product_type = s.product_type and
  m2.product_rootname = s.product_rootname 
GROUP BY m.product_rootname, s.complete_flag
EOQ

        }
        $err_msg = "Cannot query first product_rootname.";
        $err_msg2 = "Cannot query next product_rootname.";
	$count = 0;
	$target_status = "NULL";
        $sth = DoDBIexecute( $db, $query);
        while ( ($rootname,$complete, $sci_stat, $min_ready) = DoDBIfetch( $db, $query, $sth) ) 
        {
	  $product_rootname = lc( $rootname);
          if ($complete eq "Y") {
            # report completion status
            $target_status = "NULL";
            PrintMsg("I","$product_rootname is already completed.");
	  } elsif ($sci_stat eq "N") {
            # report science status
            $target_status = "NULL";
            PrintMsg("I","$product_rootname has qolink_sms.status=N.");
	    MarkComplete( $db2, $rootname, $target_class);	  
          } elsif ($min_ready eq "N") {
            # there is at least one eng_ready=N value for this product
            $target_status = $target_waiting;
            PrintMsg("I","$product_rootname is waiting for more files.");
          } else {
            # all eng_ready values must be Y
            $target_status = $target_ready;
            PrintMsg("I","$product_rootname is ready for generation.");
          }
          if ((!$interactive) && $target_status ne "NULL") {
            ProcessProduct($product_rootname, $target_status);
          }
          if ( $target_status ne "NULL" ) { $count += 1;}
        } # end while
        if ($count > 0) {
          PrintMsg("I","This file will be held for $target_class generation.");
          $process_status = $OSF_HOLD;
	} else {
	  PrintMsg("I","This file not held for $target_class products.");
          $process_status = $OSF_NO_PRODUCTS;
	}
        if ($target_class ne "GSA") {DoDBIclose($db2);}
      } # end else
    } # end else
#---------------------------------------------------------------------
# end of all queries
#---------------------------------------------------------------------
    DoDBIclose($db);

    PrintMsg ("I","---  end  --- Check and Hold $osf_root File -------");
    exit( $process_status);  

#===============================================================================
# end of main procedure -- subroutines follow
#===============================================================================


#-------------------------------------------------------------------------------
# subroutine Process Product - to create/update the specified OSF:
#  *search for the desired OSF
#   if search returns an error status, log err msg and exit with failure
#   if desired OSF is not found, create it with status ENV.TARGET_NEW
#    if create fails on 1st try (it is because gsacqd created the OSF in between 
#       the search and the create), return to * and try again
#    if create fails on 2nd try, log err msg and exit with failure (this should 
#       not happen, because on the retry the search should find the entry)
#   update the OSF (whether create attempted/succeeded or not) to either 
#      ENV.TARGET_WAITING or ENV.TARGET_READY
#   if update fails, log err msg and exit with failure (no log evidence that 
#      this ever fails)
#-------------------------------------------------------------------------------
sub ProcessProduct
{
    my ($product_name, $target_status) = @_;
    my $cmd;
    my $dcf_num;
    my $retry = 0;  # -1 = success, 0 = first, 1 = retry, 2 = failure

    while ($retry != -1) {
       $cmd = "osf_test -p $path -f $product_name -t $data_id -pr dcf_num";
       $dcf_num = `$cmd`;            # backticks invoke child process
       if ($?) {                     # tests child process status where 0 is OK
          PrintMsg("E", "Failed: $cmd");
          exit ($OSF_FAILURE);
       }
       if ($dcf_num eq "") {
          # create new OSF for product using target_new status
          $cmd = "osf_create -p $path -f $product_name -t $data_id ".
            "-s $target_new";
          `$cmd`;
          if ($?) {
             $retry++;
             if ($retry > 1) {
                PrintMsg("E", "FAILED: $cmd");
                exit ($OSF_FAILURE);
             }
             PrintMsg("I", "Failed: $cmd");
          } else {
             # OSF created
             PrintMsg("I", "$cmd");
             $retry = -1;
          }
       } else {
          # OSF already exists; skip to update
          #  (FGS OSF could have already been created by gsacqd)
          $retry = -1;
       }
    }   # end retry while loop

    # update OSF for product using target_status 
    $cmd = "osf_update -p $path -f $product_name -t $data_id ".
      "-c \"$target_column\" -s $target_status";
    `$cmd`;
    if ($?) {
       PrintMsg("E", "FAILED: $cmd");
       exit ($OSF_FAILURE);
    }
    # OSF updated
    PrintMsg("I", "$cmd");

}   # end subroutine ProcessProduct


#---------------------------------------------------------------------
# subroutine to set complete_flag
#---------------------------------------------------------------------
sub MarkComplete
{
    my ($db, $product_name, $type) = @_;
    my $query;
    my $update_count;

    $query = <<"EOQ";
UPDATE product_status
SET complete_flag = 'Y'
WHERE product_rootname='$product_name' and product_type='$type'
EOQ

    $update_count = DoDBI( $db, $query);
    if ($update_count > 0) {
	PrintMsg("I", "Set product_status.complete_flag=Y for $product_name");
    } else {
	PrintMsg("W", 
	   "Could not set product_status.complete_flag=Y for $product_name");
    }
}   # end subroutine MarkComplete
