Function RDS_Actions(Action, CalcColName, FSList, Handle, Name, FMC, Record, Status, OrigRecord, Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10)
/***********************************************************************************************************************

    This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written
    permission from Infineon.

    Name        :   RDS_Actions

    Description :   Handles calculated columns and MFS calls for the current table.

    Notes       :   This function uses @ID, @RECORD, and @DICT to make sure {ColumnName} references work correctly.
                    If called from outside of a calculated column these will need to be set and restored.

    Parameters  :
        Action          [in] -- Name of the action to be taken
        CalcColName     [in] -- Name of the calculated column that needs to be processed. Normally this should only be
                                populated when the CalcField action is being used.
        FSList          [in] -- The list of MFSs and the BFS name for the current file or volume. This is an @SVM
                                delimited array, with the current MFS name as the first value in the array, and the BFS
                                name as the last value. Normally set by a calling MFS.
        Handle          [in] -- The file handle of the file or media map being accessed. Note, this does contain the
                                entire handle structure that the Basic+ Open statement would provide. Normally set by a
                                calling MFS.
        Name            [in] -- The name (key) of the record or file being accessed. Normally set by a calling MFS.
        FMC             [in] -- Various functions. Normally set by a calling MFS.
        Record          [in] -- The entire record (for record-oriented functions) or a newly-created handle (for
                                "get handle" functions). Normally set by a calling MFS.
        Status      [in/out] -- Indicator of the success or failure of an action. Normally set by the calling MFS but
                                for some actions can be set by the action handler to indicate failure.
        OrigRecord      [in] -- Original content of the record being processed by the current action. This is
                                automatically being assigned by the WRITE_RECORD and DELETE_RECORD actions within
                                BASE_MFS.
        Param1-10   [in/out] -- Additional request parameter holders
        ActionFlow     [out] -- Used to control the action chain (see the ACTION_SETUP insert for more information.)
                                Can also be used to return a special value, such as the results of the CalcField
                                method.

    History     :   (Date, Initials, Notes)
        04/10/18    dmb     Original programmer.
        10/04/18    djs     Added a trigger within the WRITE_RECORD event, which fires when the reactor number has
                            changed. When this occurs the related RDS_LAYER records for this RDS record are populated
                            with the most recent associated TOOL_PARMS record. (related by PSN and Reactor)

***********************************************************************************************************************/

#pragma precomp SRP_PreCompiler

$Insert FILE.SYSTEM.EQUATES
$Insert ACTION_SETUP
$Insert RDS_EQUATES
$Insert CLEAN_INSP_EQUATES
$Insert COMPANY_EQUATES
$Insert RDS_LAYER_EQUATES
$Insert TOOL_PARMS_EQUATES
$Insert RLIST_EQUATES
$Insert APP_INSERTS
$Insert QA_MET_EQUATES
$Insert PRS_STAGE_EQUATES
$Insert WO_MAT_EQUATES
$Insert WO_MAT_QA_EQUATES
$Insert LOT_EVENT_EQUATES
$Insert IFX_EQUATES

Equ COMMA$ to ','

Declare function    Error_Services, Database_Services, obj_RDS_Test, Logging_Services, Environment_Services
Declare function    Tool_Parms_Services, Signature_Services, obj_WO_Mat_QA, Datetime
Declare function	Rds_Services, SRP_DateTime, SRP_Math, obj_WO_Mat, Lot_Services, SRP_Array
Declare function    Lot_Event_Services, GetTickCount, Work_Order_Services
Declare subroutine  Error_Services, Database_Services, Logging_Services, Service_Services, obj_WO_React
Declare Subroutine  Mona_Services, Work_Order_Services

LogPath     = Environment_Services('GetApplicationRootPath') : '\LogFiles\RDS'
LogDate     = Oconv(Date(), 'D4/')
LogTime     = Oconv(Time(), 'MTS')
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' RDS Log.csv'
Headers     = 'Logging DTM' : @FM : 'User' : @FM : 'RDS Key ID' : @FM : 'Notes'
objLog      = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$)
LoggingDTM  = LogDate : ' ' : LogTime   ; // Logging DTM

LogPath      = Environment_Services('GetApplicationRootPath') : '\LogFiles\RDS'
LogFileName  = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' RDS Erase attempt.csv'
Headers      = 'Logging DTM' : @FM : 'RDSNo' : @FM : 'WONo' : @FM : 'CassNo' : @FM : 'Reactor Type'
objLog3      = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$)

IsProd = Environment_Services('IsProd')
If IsProd EQ True$ then
	MonaResource = 'GRP_OPENINSIGHT_MES_OP_FE_RDSACTIONS'
end else
	MonaResource = 'GRP_OPENINSIGHT_MES_OP_FE_DEV_RDSACTIONS'
end	

If KeyID then GoSub Initialize_System_Variables

Begin Case

    Case Action _EQC 'CalculateColumn'      ;   GoSub CalculateColumn
    Case Action _EQC 'READ_RECORD_PRE'      ;   GoSub READ_RECORD_PRE
    Case Action _EQC 'READ_RECORD'          ;   GoSub READ_RECORD
    Case Action _EQC 'READONLY_RECORD_PRE'  ;   GoSub READONLY_RECORD_PRE
    Case Action _EQC 'READONLY_RECORD'      ;   GoSub READONLY_RECORD
    Case Action _EQC 'WRITE_RECORD_PRE'     ;   GoSub WRITE_RECORD_PRE
    Case Action _EQC 'WRITE_RECORD'         ;   GoSub WRITE_RECORD
    Case Action _EQC 'DELETE_RECORD_PRE'    ;   GoSub DELETE_RECORD_PRE
    Case Action _EQC 'DELETE_RECORD'        ;   GoSub DELETE_RECORD
    Case Otherwise$                         ;   Status = 'Invalid Action'

End Case

If KeyID then GoSub Restore_System_Variables

If Assigned(ActionFlow) else ActionFlow = ACTION_CONTINUE$

Return ActionFlow


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Calculated Columns 
//
// The typical structure of a calculated column will look like this:
//
// Declare function Database_Services
//
// @ANS = Database_Services('CalculateColumn')
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

CalculateColumn:

    // Make sure the ActionFlow return variable is cleared in case nothing is calculated.
    ActionFlow = ''

    Begin Case
        Case CalcColName EQ 'CURR_STAGE'            ; GoSub CURR_STAGE
        Case CalcColName EQ 'DATETIME_IN'           ; GoSub DATETIME_IN
        CAse CalcColName EQ 'DATETIME_OUT'          ; GoSub DATETIME_OUT
        Case CalcColName EQ 'PRE_INST'              ; GoSub PRE_INST
        Case CalcColName EQ 'PRE_INST_ACK_REQ'      ; GoSub PRE_INST_ACK_REQ
        Case CalcColName EQ 'FWI_INST'              ; GoSub FWI_INST
        Case CalcColName EQ 'FWI_INST_ACK_REQ'      ; GoSub FWI_INST_ACK_REQ
        Case CalcColName EQ 'LWI_INST'              ; GoSub LWI_INST
        Case CalcColName EQ 'LWI_INST_ACK_REQ'      ; GoSub LWI_INST_ACK_REQ
        Case CalcColName EQ 'QA_INST'               ; GoSub QA_INST
        Case CalcColName EQ 'QA_INST_ACK_REQ'       ; GoSub QA_INST_ACK_REQ
        Case CalcColName EQ 'LOAD_INST'             ; GoSub LOAD_INST
        Case CalcColName EQ 'LOAD_INST_ACK_REQ'     ; GoSub LOAD_INST_ACK_REQ
        Case CalcColName EQ 'UNLOAD_INST'           ; GoSub UNLOAD_INST
        Case CalcColName EQ 'UNLOAD_INST_ACK_REQ'   ; GoSub UNLOAD_INST_ACK_REQ
        Case CalcColName EQ 'ON_TW_FREQ'            ; GoSub ON_TW_FREQ
        Case CalcColName EQ 'POST_INST'             ; GoSub POST_INST
        Case CalcColName EQ 'POST_INST_ACK_REQ'     ; GoSub POST_INST_ACK_REQ
        Case CalcColName EQ 'ROTR_ACTION'           ; GoSub ROTR_ACTION
        Case CalcColName EQ 'RDS_LAYER_ACK_REQ'     ; GoSub RDS_LAYER_ACK_REQ
        Case CalcColName EQ 'RUNTIME'               ; GoSub RUNTIME
        Case CalcColName EQ 'SUPPL_ACK_REQ'         ; GoSub SUPPL_ACK_REQ
        Case CalcColName EQ 'WAFER_COUNT_ACK_REQ'   ; GoSub WAFER_COUNT_ACK_REQ
        Case CalcColName EQ 'TW_PROD'               ; GoSub TW_PROD
        Case CalcColName EQ 'ABBREV_OR_CO_NAME'     ; GoSub ABBREV_OR_CO_NAME
        Case CalcColName EQ 'LOAD_LOCK_REQ'         ; GoSub LOAD_LOCK_REQ
        Case CalcColName EQ 'UNLOAD_THICK_TEST'     ; GoSub UNLOAD_THICK_TEST
        Case CalcColName EQ 'WO_MAT_KEY'            ; GoSub WO_MAT_KEY
        Case CalcColName EQ 'HOT_LOT'               ; GoSub HOT_LOT
    End Case

return


DATETIME_IN:
    
    TimeIn     = {TIME_IN}
    TimeIn     = TimeIn/86400
    TimeIn     = SRP_Math('ROUND', TimeIn, 5)
    TimeIn     = TimeIn[2, 6]
    ActionFlow = {DATE_IN}:TimeIn
    
return


DATETIME_OUT:
    
    TimeOut    = {TIME_OUT}
    TimeOut    = TimeOut/86400
    TimeOut    = SRP_Math('ROUND', TimeOut, 5)
    TimeOut    = TimeOut[2, 6]
    ActionFlow = {DATE_OUT}:TimeOut
    
return


LOAD_LOCK_REQ:
    
    ActionFlow  = False$
    ReactorType = {REACTOR_TYPE}
    LoadLock    = {LOAD_LOCK_SIDE}

    If ( ( (ReactorType EQ 'ASM+') or (ReactorType EQ 'HTR') ) and (LoadLock EQ '') ) then ActionFlow = True$
    
return


CURR_STAGE:
    
    Stage = ''
    RDSNo = @ID
    Stage = Rds_Services('GetCurrentStage', RDSNo)          
    ActionFlow = Stage
    
return


PRE_INST:
    
    PSN = {PROD_SPEC_ID}
    StageInst = Xlate('PRS_STAGE', PSN:'*PRE', 'INST', 'X')
    Convert @TM to ' ' in StageInst
    ActionFlow = StageInst
    
return


PRE_INST_ACK_REQ:
    
    If ( ({PRE_INST} NE '') and ( ({PRE_INST_ACK} EQ '') or ({PRE_INST_ACK} EQ False$) ) and ({CURR_STAGE} EQ 'VER') ) then
        ActionFlow = True$
    end else
        ActionFlow = False$
    end
    
return


FWI_INST:
    
    PSN = {PROD_SPEC_ID}
    StageInst = Xlate('PRS_STAGE', PSN:'*FWI', 'INST', 'X')
    Convert @TM to ' ' in StageInst
    ActionFlow = StageInst
    
return


FWI_INST_ACK_REQ:
    
    If ( ({FWI_INST} NE '') and ( ({FWI_INST_ACK} EQ '') or ({FWI_INST_ACK} EQ False$) ) and ({CURR_STAGE} EQ 'LOAD') ) then
        ActionFlow = True$
    end else
        ActionFlow = False$
    end
    
return


LWI_INST:
    
    PSN = {PROD_SPEC_ID}
    StageInst = Xlate('PRS_STAGE', PSN:'*LWI', 'INST', 'X')
    Convert @TM to ' ' in StageInst
    ActionFlow = StageInst
    
return


LWI_INST_ACK_REQ:
    
    If ( ({LWI_INST} NE '') and ( ({LWI_INST_ACK} EQ '') or ({LWI_INST_ACK} EQ False$) ) and ({CURR_STAGE} EQ 'UNLOAD') ) then
        ActionFlow = True$
    end else
        ActionFlow = False$
    end
    
return


POST_INST:
    
    PSN = {PROD_SPEC_ID}
    StageInst = Xlate('PRS_STAGE', PSN:'*POST', 'INST', 'X')
    Convert @TM to ' ' in StageInst
    ActionFlow = StageInst
    
return


POST_INST_ACK_REQ:
    
    If ( ({POST_INST} NE '') and ( ({POST_INST_ACK} EQ '') or ({POST_INST_ACK} EQ False$) ) and ({CURR_STAGE} EQ 'POST') ) then
        ActionFlow = True$
    end else
        ActionFlow = False$
    end
    
return


QA_INST:
    
    PSN = {PROD_SPEC_ID}
    StageInst = Xlate('PRS_STAGE', PSN:'*QA', 'INST', 'X')
    Convert @TM to ' ' in StageInst
    ActionFlow = StageInst
    
return


QA_INST_ACK_REQ:
    
    If ( ({QA_INST} NE '') and ( ({QA_INST_ACK} EQ '') or ({QA_INST_ACK} EQ False$) ) and ({CURR_STAGE} EQ 'QA') ) then
        ActionFlow = True$
    end else
        ActionFlow = False$
    end
    
return


LOAD_INST:
    
    PSN = {PROD_SPEC_ID}
    StageInst = Xlate('PRS_STAGE', PSN:'*LOAD', 'INST', 'X')
    Convert @TM to ' ' in StageInst
    ActionFlow = StageInst
    
return


LOAD_INST_ACK_REQ:
    
    If ( ({LOAD_INST} NE '') and ( ({LOAD_INST_ACK} EQ '') or ({LOAD_INST_ACK} EQ False$) ) and ({CURR_STAGE} EQ 'LOAD') ) then
        ActionFlow = True$
    end else
        ActionFlow = False$
    end
    
return


UNLOAD_INST:
    
    PSN = {PROD_SPEC_ID}
    StageInst = Xlate('PRS_STAGE', PSN:'*UNLOAD', 'INST', 'X')
    Convert @TM to ' ' in StageInst
    ActionFlow = StageInst
    
return


UNLOAD_INST_ACK_REQ:
    
    If ( ({UNLOAD_INST} NE '') and ( ({UNLOAD_INST_ACK} EQ '') or ({UNLOAD_INST_ACK} EQ False$) ) and ({CURR_STAGE} EQ 'UNLOAD') ) then
        ActionFlow = True$
    end else
        ActionFlow = False$
    end
    
return


UNLOAD_THICK_TEST:
    
    UnloadThickTest  = ''
    Parms            = {WO_MAT_KEY}:@RM
    Parms           := '':@RM
    Parms           := FIELD(@RECORD<256>,'*',2):@RM              ;* WOStep
    Parms           := 'UNLOAD':@RM
    Parms           := WO_MAT_QA_PROFILE$
    QAMetArray       = obj_WO_Mat_QA('GetQAMet', Parms)
    For each Row in QAMetArray using @FM setting fPos
        Locate 'THICK_ONLY' in Row using @VM setting vPos then
            UnloadThickTest = True$
        end
    Until UnloadThickTest EQ True$
    Next Row
    ActionFlow = UnloadThickTest
    
return


SUPPL_ACK_REQ:

    ActionFlow = False$
    SupplementFlag = {SUPPLEMENT}
    SupplAck       = {SUPPL_ACK}
    If ( (SupplementFlag EQ True$) and ( (SupplAck EQ '') or (SupplAck EQ False$) ) ) then
        ActionFlow = True$
    end
    
return


RDS_LAYER_ACK_REQ:
    
    ActionFlow  = False$
    IsTestWafer = {ON_TW_FREQ}
    RDSLayerAck = {RDS_LAYER_ACK}
    If ( (IsTestWafer EQ True$) and ( (RDSLayerAck EQ False$) or (RDSLayerAck EQ '') ) ) then
        ActionFlow = True$
    end

return


WAFER_COUNT_ACK_REQ:
    
    ActionFlow = False$
    If ( ({CURR_STAGE} EQ 'VER') and ( ({WAFER_COUNT_ACK} EQ False$) or ({WAFER_COUNT_ACK} EQ '') ) ) then
        ActionFlow = True$
    end
    
return


ON_TW_FREQ:
    
    ActionFlow  = False$
    CassNo      = {CASS_NO}
    PSNo        = {PROD_SPEC_ID}
    UnloadKey   = PSNo:'*UNLOAD'
    UnloadRec   = Database_Services('ReadDataRow', 'PRS_STAGE', UnloadKey)
    Intervals   = UnloadRec<PRS_STAGE_MET_INTERVAL$>
    Starts      = UnloadRec<PRS_STAGE_MET_START$>
    MetTests    = UnloadRec<PRS_STAGE_MET_TEST$>
    TestSlots   = UnloadRec<PRS_STAGE_MET_SLOT$>
    Found       = False$
    For each MetTest in MetTests using @VM setting vPos
        TestSlot = TestSlots<0, vPos>
        If (MetTest EQ 'THICK_ONLY') and (TestSlot EQ 'L') then Found = True$
    Until Found EQ True$
    Next MetTest
    If Found EQ True$ then
        TestWaferFlag = 0
        Interval      = Intervals<0, vPos>
        Start         = Starts<0, vPos>		
        IF Interval NE '' AND Start NE '' THEN
            IF Interval = Start THEN
                IF REM(CassNo,Interval) = 0 THEN TestWaferFlag = 1
            END ELSE
                IF ABS((Start + INT(CassNo/Interval)*Interval) - CassNo) = 0 THEN TestWaferFlag = 1
            END
        end
        ActionFlow = TestWaferFlag
    end    
return


ROTR_ACTION:

    CleanInspRow    = Database_Services('ReadDataRow', 'CLEAN_INSP', {LWI_CI_NO})
    ROTRAction      = CleanInspRow<CLEAN_INSP_ROTR_ACTION$>
    If ROTRAction EQ 'F' then
        // Before returning a Fail, check to see if there is an acceptance for the results.
        AcceptedSignature   = CleanInspRow<CLEAN_INSP_SIGN_ROTR_SIGNATURE$>
        AcceptedReason      = CleanInspRow<CLEAN_INSP_SIGN_ROTR_REASON$>
        If (AcceptedSignature NE '') AND (AcceptedReason NE '') then ROTRAction = 'A'
    end
    ActionFlow  = ROTRAction

return


TW_PROD:

    IF {REACTOR_TYPE} = 'EPP' THEN
        WaferChars = @RECORD<275>
        PktChars = @RECORD<268>
        OutCnt = COUNT(PktChars,@VM) + (PktChars NE '')
        Ans = 0
        FOR I = 1 TO OutCnt
             PktChar = PktChars<1,I>
             WfrChar = WaferChars<1,I>
             IF PktChar = 'TEST' AND WfrChar = 'PROD' THEN  Ans += 1
        NEXT I
        ActionFlow = Ans
    END ELSE
         TestKeys   = XLATE('RDS_LAYER',@RECORD<150>,3,'X')
         ActionFlow = obj_RDS_Test('ProdTestCount',TestKeys)
    END
    
return


ABBREV_OR_CO_NAME:

    CompRec         = Database_Services('ReadDataRow', 'COMPANY', {CUST_NO})
    CustomerName    = CompRec<COMPANY_ABBREV$>
    ActionFlow      = CustomerName
    
return


WO_MAT_KEY:
    
    ActionFlow = ''
    ReactType = {REACTOR_TYPE}
    IF {REACTOR_TYPE} NE 'EPP' THEN
       WONo = @RECORD<6>
       CassNo = @RECORD<260>
       IF WONo NE '' AND CassNo NE '' THEN
            ActionFlow = WONo:'*':CassNo
       END
    END
    
    If ActionFlow EQ '' and ReactType NE 'EPP' and ReactType NE 'GAN' then
        RDSNo = @ID
        // Log the above data to troubleshoot.
        LogData = ''
        LogData<1> = LoggingDTM
        LogData<2> = RDSNo
        LogData<3> = @Record<RDS_WO$>
        LogData<4> = @Record<RDS_CASS_NO$>
        LogData<5> = ReactType
        Logging_Services('AppendLog', objLog3, LogData, @RM, @FM)
    end
    
return


RUNTIME:

    LoadDTM      = IConv(OConv({DATE_IN}, 'D'):' ':OConv({TIME_IN}, 'MT'), 'DT')
    LoadEx2DTM   = IConv(OConv({OP_IN_EX2_DATE}, 'D'):' ':OConv({OP_IN_EX2_TIME}, 'MT'), 'DT')
    LoadEx3DTM   = IConv(OConv({OP_IN_EX3_DATE}, 'D'):' ':OConv({OP_IN_EX3_TIME}, 'MT'), 'DT')
    UnloadEx1DTM = IConv(OConv({OP_OUT_EX1_DATE}, 'D'):' ':OConv({OP_OUT_EX1_TIME}, 'MT'), 'DT')
    UnloadEx2DTM = IConv(OConv({OP_OUT_EX2_DATE}, 'D'):' ':OConv({OP_OUT_EX2_TIME}, 'MT'), 'DT')
    UnloadDTM    = IConv(OConv({DATE_OUT}, 'D'):' ':OConv({TIME_OUT}, 'MT'), 'DT')
    Begin Case
        Case UnloadEx2DTM NE ''
            Runtime = UnloadEx2DTM - LoadEx3DTM
        Case UnloadEx1DTM NE ''
            Runtime = UnloadEx1DTM - LoadEx2DTM
        Case Otherwise$
            Runtime = UnloadDTM - LoadDTM
    End Case
    
    ActionFlow = Runtime
    
return


HOT_LOT:
    
    ActionFlow = Xlate('WO_LOG', {WO}, 'HOT_FLAG', 'X')
    
return


// ----- MFS calls -----------------------------------------------------------------------------------------------------

READ_RECORD_PRE:
    // In order to stop a record from being read in this action these lines of code must be used:
    //
    //    OrigFileError   = 100 : @FM : KeyID
    //    Status          = 0
    //    Record          = ''
    //    ActionFlow      = ACTION_STOP$
    
    * This code prevents an anomaly where an @SVM appears when the value is read
    * and causes an error when copying the record to SQL.
    WafersIn               = Record<RDS_WAFERS_IN$>
    WafersIn               = WafersIn<1, 1, 1>
    Record<RDS_WAFERS_IN$> = WafersIn
    
return

READ_RECORD:

    // In order to stop a record from being read in this action these lines of code must be used:
    //
    //    OrigFileError   = 100 : @FM : KeyID
    //    Status          = 0
    //    Record          = ''
    
    Shift = Record<RDS_SHIFT$>
    If Num(Shift) then
    	Begin Case
    		Case Shift EQ 1
    			Record<RDS_SHIFT$> = 'A'
    		Case Shift EQ 2
    			Record<RDS_SHIFT$> = 'B'
    		Case Shift EQ 3
    			Record<RDS_SHIFT$> = 'C'
    		Case Shift EQ 4
    			Record<RDS_SHIFT$> = 'D'
    		Case Otherwise$
    			Null
    	End Case
    end     
    
return


READONLY_RECORD_PRE:
    // In order to stop a record from being read in this action these lines of code must be used:
    //
    //    OrigFileError   = 100 : @FM : KeyID
    //    Status          = 0
    //    Record          = ''
    //    ActionFlow      = ACTION_STOP$
return


READONLY_RECORD:
    // In order to stop a record from being read in this action these lines of code must be used:
    //
    //    OrigFileError   = 100 : @FM : KeyID
    //    Status          = 0
    //    Record          = ''
    
	Shift = Record<RDS_SHIFT$>
    If Num(Shift) then
    	Begin Case
    		Case Shift EQ 1
    			Record<RDS_SHIFT$> = 'A'
    		Case Shift EQ 2
    			Record<RDS_SHIFT$> = 'B'
    		Case Shift EQ 3
    			Record<RDS_SHIFT$> = 'C'
    		Case Shift EQ 4
    			Record<RDS_SHIFT$> = 'D'
    		Case Otherwise$
    			Null
    	End Case
    end
    
return

WRITE_RECORD_PRE:

	ErrorMsg = ''
	StartTick = GetTickCount()
    MetricName = 'WriteRecordPre'
	
	Shift = Record<RDS_SHIFT$>
    If Num(Shift) then
    	Begin Case
    		Case Shift EQ 1
    			Record<RDS_SHIFT$> = 'A'
    		Case Shift EQ 2
    			Record<RDS_SHIFT$> = 'B'
    		Case Shift EQ 3
    			Record<RDS_SHIFT$> = 'C'
    		Case Shift EQ 4
    			Record<RDS_SHIFT$> = 'D'
    		Case Otherwise$
    			Null
    	End Case
    end
    SaveRecord = Record

    RDSNo    = Name
    RDSKeyID = Name
    
    OrigReactor = OrigRecord<RDS_REACTOR$>
    NewReactor  = Record<RDS_REACTOR$>
    
    // Verify / Pre-Epi Signature
    OrigVerSig      = Trim(OrigRecord<RDS_PRE_EPI_SIG$>)
    OrigVerDate     = Trim(OrigRecord<RDS_PRE_EPI_SIG_DATE$>)
    OrigVerTime     = Trim(OrigRecord<RDS_PRE_EPI_SIG_TIME$>)
    NewVerSig       = Trim(Record<RDS_PRE_EPI_SIG$>)
    NewVerDate      = Trim(Record<RDS_PRE_EPI_SIG_DATE$>)
    NewVerTime      = Trim(Record<RDS_PRE_EPI_SIG_TIME$>)
    If Not(Num(NewVerDate)) then Record<RDS_PRE_EPI_SIG_DATE$> = IConv(NewVerDate, 'D')
    If Not(Num(NewVerTime)) then Record<RDS_PRE_EPI_SIG_TIME$> = IConv(NewVerTime, 'MT')
    // Load Signature
    OrigLoadSig     = Trim(OrigRecord<RDS_OPERATOR_IN$>)
    OrigLoadDate    = Trim(OrigRecord<RDS_DATE_IN$>)
    OrigLoadTime    = Trim(OrigRecord<RDS_TIME_IN$>)
    NewLoadSig      = Trim(Record<RDS_OPERATOR_IN$>)
    NewLoadDate     = Trim(Record<RDS_DATE_IN$>)
    NewLoadTime     = Trim(Record<RDS_TIME_IN$>)
    If Not(Num(NewLoadDate)) then Record<RDS_DATE_IN$> = IConv(NewLoadDate, 'D')
    If Not(Num(NewLoadTime)) then Record<RDS_TIME_IN$> = IConv(NewLoadTime, 'MT')
    // Unload signature
    OrigDateOut    = OrigRecord<RDS_DATE_OUT$>
    OrigTimeOut    = OrigRecord<RDS_TIME_OUT$>
    OrigTimeOutSig = OrigRecord<RDS_OPERATOR_OUT$>
    DateOut        = Record<RDS_DATE_OUT$>
    TimeOut        = Record<RDS_TIME_OUT$>
    TimeOutSig     = Record<RDS_OPERATOR_OUT$>
    If Not(Num(DateOut)) then Record<RDS_DATE_OUT$> = IConv(DateOut, 'D')
    If Not(Num(TimeOut)) then Record<RDS_TIME_OUT$> = IConv(TimeOut, 'MT')
    // FQA signature
    OrigFQADate    = OrigRecord<RDS_SUP_VER_SIG_DATE$>
    OrigFQATime    = OrigRecord<RDS_SUP_VER_SIG_TIME$>
    OrigFQASig     = OrigRecord<RDS_SUP_VER_SIG$>
    FQADate        = Record<RDS_SUP_VER_SIG_DATE$>
    FQATime        = Record<RDS_SUP_VER_SIG_TIME$>
    FQASig         = Record<RDS_SUP_VER_SIG$>
    If Not(Num(FQADate)) then Record<RDS_SUP_VER_SIG_DATE$> = IConv(FQADate, 'D')
    If Not(Num(FQATime)) then Record<RDS_SUP_VER_SIG_TIME$> = IConv(FQATime, 'MT')
    
    CurrDTM      = Datetime()
    VerDTM       = IConv(OConv(NewVerDate, 'D'):' ':OConv(NewVerTime, 'MT'), 'DT')
    LoadDTM      = IConv(OConv(NewLoadDate, 'D'):' ':OConv(NewLoadTime, 'MT'), 'DT')
    LoadEx2DTM   = IConv(OConv({OP_IN_EX2_DATE}, 'D'):' ':OConv({OP_IN_EX2_TIME}, 'MT'), 'DT')
    LoadEx3DTM   = IConv(OConv({OP_IN_EX3_DATE}, 'D'):' ':OConv({OP_IN_EX3_TIME}, 'MT'), 'DT')
    UnloadEx1DTM = IConv(OConv({OP_OUT_EX1_DATE}, 'D'):' ':OConv({OP_OUT_EX1_TIME}, 'MT'), 'DT')
    UnloadEx2DTM = IConv(OConv({OP_OUT_EX2_DATE}, 'D'):' ':OConv({OP_OUT_EX2_TIME}, 'MT'), 'DT')
    UnloadDTM    = IConv(OConv(DateOut, 'D'):' ':OConv(TimeOut, 'MT'), 'DT')
    PostDTM      = IConv(OConv({POST_EPI_SIG_DATE}, 'D'):' ':OConv({POST_EPI_SIG_TIME}, 'MT'), 'DT')
    FQADTM       = IConv(OConv({SUP_VER_SIG_DATE}, 'D'):' ':OConv({SUP_VER_SIG_TIME}, 'MT'), 'DT')

	If NewLoadSig EQ '' then
		// Audit the LOT_EVENT table for missing LOAD event (i.e., signature)
		ExistingNGLotId = Lot_Services('GetLotIdByLegacyLotIdAndType', RDSNo, 'RDS')
		If RowExists('LOT', ExistingNGLotId) then
			LotEvents      = Lot_Event_Services('GetLotEventsInSequence', ExistingNGLotId)
			If LotEvents NE '' then 
				LotEventsRev      = SRP_Array('Reverse', LotEvents, @FM)
				LotEventsTypesRev = Xlate('LOT_EVENT', LotEventsRev, LOT_EVENT_LOT_EVENT_TYPE$, 'X')
				If LotEventsTypesRev NE '' then
					Done = False$
					For each LotEventType in LotEventsTypesRev using @FM setting EventPos
						Begin Case
							Case LotEventType EQ 'LOAD'
								Done = True$
								If NewLoadSig EQ '' then
									// Load signature is missing from RDS record
									NewLoadSig               = Xlate('LOT_EVENT', LotEventsRev<EventPos>, LOT_EVENT_EVENT_OPERATOR_ID$, 'X')
									NewLoadSigDtm            = Xlate('LOT_EVENT', LotEventsRev<EventPos>, LOT_EVENT_EVENT_DATETIME$, 'X')
									NewLoadDate              = SRP_DateTime("Date", NewLoadSigDtm)
									NewLoadTime              = SRP_DateTime("Time", NewLoadSigDtm)
									Record<RDS_OPERATOR_IN$> = NewLoadSig
									Record<RDS_DATE_IN$>     = NewLoadDate
									Record<RDS_TIME_IN$>     = NewLoadTime
									LogData                  = ''
									LogData<1>               = LoggingDTM
									LogData<2>               = @User4
									LogData<3>               = RDSKeyID
									LogData<4>               = 'Detected missing LOAD signature from RDS record. Restored signature from LOT_EVENT table.'
									Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$)							
								end
							Case LotEventType EQ 'UNSIGN_LOAD'
								Done = True$
								// No need to check for missing load signature
						End Case
					Until Done
					Next LotEventType
				end
			end
		end
	end
    
    Begin Case
    	
    	Case  ( (OrigTimeOutSig NE '') and (OrigReactor NE NewReactor) )
            LogData    = ''
            LogData<1> = LoggingDTM
            LogData<2> = @USER4
            LogData<3> = RDSKeyID
            LogData<4> = 'Reactor number cannot be changed or removed once the load signature is set!'
            Logging_Services('AppendLog', ObjLog, LogData, @RM, @FM, False$)
            
            // User is attempting to erase data that is prohibited from being erased Set the FS104 error and block the write.
            ErrorMsg = 'Reactor number cannot be changed or removed once the unload signature is set!'
            OrigFileError = 104:': Reactor number cannot be changed or removed once the unload signature is set!'
            Status        = 0
            Record        = ''
            ActionFlow    = ACTION_STOP$            
            
        Case ( (VerDTM GT CurrDTM) or (LoadDTM GT CurrDTM) or (LoadEx2DTM GT CurrDTM) or (LoadEx3DTM GT CurrDTM) |
            or (UnloadEx1DTM GT CurrDTM) or (UnloadEx2DTM GT CurrDTM) or (UnloadDTM GT CurrDTM) |
            or (PostDTM GT CurrDTM) or (FQADTM GT CurrDTM) )
            RDSKeyID   = Name
            LogData    = ''
            LogData<1> = LoggingDTM
            LogData<2> = @USER4
            LogData<3> = RDSKeyID
            LogData<4> = 'Signature datetime is greater than current datetime!'
            Logging_Services('AppendLog', ObjLog, LogData, @RM, @FM, False$)       
            
            ErrorMsg = 'Signature datetime is greater than current datetime!'
            OrigFileError = 104:': Signature datetime is greater than current datetime!'
            Status        = 0
            Record        = ''
            ActionFlow    = ACTION_STOP$
            
        Case ( ((VerDTM NE '' and LoadDTM NE '') and (LoadDTM LE VerDTM)) |
            or (LoadDTM NE '' and UnloadDTM NE '') and (UnloadDTM LT LoadDTM) |
            or (UnloadEx1DTM NE '' and LoadDTM NE '') and (UnloadEx1DTM LT LoadDTM) |
            or (LoadEx2DTM NE '' and UnloadEx1DTM NE '') and (LoadEx2DTM LT UnloadEx1DTM) |
            or (UnloadEx2DTM NE '' and LoadEx3DTM NE '') and (LoadEx3DTM LT UnloadEx2DTM) |
            or (UnloadDTM NE '' and LoadEx3DTM NE '') and (UnloadDTM LT LoadEx3DTM) )
            // QA > POST > Unload > LoadEx3 > UnloadEx2 > LoadEx2 > UnloadEx1 > Load
            RDSKeyID   = Name
            LogData    = ''
            LogData<1> = LoggingDTM
            LogData<2> = @USER4
            LogData<3> = RDSKeyID
            LogData<4> = 'Signature datetime is less than a previous signature datetime!'
            Logging_Services('AppendLog', ObjLog, LogData, @RM, @FM, False$)       
            
            ErrorMsg = 'Signature datetime is less than a previous signature datetime!'
            OrigFileError = 104:': Signature datetime is less than a previous signature datetime!'
            Status        = 0
            Record        = ''
            ActionFlow    = ACTION_STOP$
            
        Case Otherwise$
            SaveRecord = Record
            
    End Case
    
    EndTick = GetTickCount()
    Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick)
    
    If ErrorMsg NE '' then
    	Error_Services('Add', ErrorMsg)
    end
    
return


WRITE_RECORD:

	StartTick  = GetTickCount()
    MetricName = 'WriteRecord'
    
    LotVoided = Lot_Services('GetLotIdByLegacyLotIdAndType', {SEQ}, 'RDS')
    IsLotVoided = Work_Order_Services('IsLotVoided', LotId)
    
    If Not(IsLotVoided) then
        Service_Services('PostProcedure', 'RDS_SERVICES', 'PushSigProfileToWoMat':SD$:Name)
    end
    
    WONo    	= Record<RDS_WO$>
    OrigDateOut = OrigRecord<RDS_DATE_OUT$>
    NewDateOut  = Record<RDS_DATE_OUT$>
    
    RDSNo = {SEQ}
    Reactor = Record<RDS_REACTOR$>
    OrgReactNo = OrigRecord<RDS_REACTOR$>
    CassNo  = Record<RDS_CASS_NO$>
    PSNo    = Record<RDS_PROD_SPEC_ID$>
    WOStep  = Xlate('RDS', RDSNo, 'WO_STEP', 'X')
    
     BEGIN CASE
        CASE OrgReactNo = '' AND Reactor NE ''
            //Assignment to a reactor where there was no prior assigned reactor
            obj_WO_React('AddRdsNo',WONo:@RM:WOStep:@RM:Reactor:@RM:RDSNo:@RM:CassNo:@RM:PSNo)
            
        CASE OrgReactNo NE '' AND Reactor = ''
            //Reactor Assignment is being cleared.
            obj_WO_React('RemRdsNo',WONo:@RM:WOStep:@RM:OrgReactNo:@RM:RDSNo:@RM:CassNo:@RM:PSNo)
            
        CASE OrgReactNo NE Reactor
            //Reactor Assignment is changing
            obj_WO_React('RemRdsNo',WONo:@RM:WOStep:@RM:OrgReactNo:@RM:RDSNo:@RM:CassNo:@RM:PSNo)
            obj_WO_React('AddRdsNo',WONo:@RM:WOStep:@RM:Reactor:@RM:RDSNo:@RM:CassNo:@RM:PSNo)
            
        CASE Otherwise$
            NULL
            
    END CASE	
    
    If ( ( (OrigDateOut EQ '') and (NewDateOut NE '') ) ) then
        // Mark this cassette as processed in the schedule event record
        DatetimeOut = {DATETIME_OUT}
		ReactType   = Xlate('WO_LOG', WONo, 'REACT_TYPE', 'X')
		EpiPro      = (ReactType EQ 'EPP')        
        If EpiPro then           
            WMIKeys   = {WM_IN_KEY}
            For each WMIKey in WMIKeys using @VM setting vPos
                CassNo = Field(WMIKey, '*', 3)
                Service_Services('PostProcedure', 'SCHEDULE_SERVICES', 'UpdateCassProcStatus':SD$:WONo:SD$:CassNo:SD$:DatetimeOut)
            Next WMIKey
        end else
            CassNo = Record<RDS_CASS_NO$>
            Service_Services('PostProcedure', 'SCHEDULE_SERVICES', 'UpdateCassProcStatus':SD$:WONo:SD$:CassNo:SD$:DatetimeOut)
        end
    end
    
    OrigPocketChar = OrigRecord<RDS_POCKET_CHAR$>
    NewPocketChar  = Record<RDS_POCKET_CHAR$>
    If (OrigPocketChar NE NewPocketChar) then
        OrigScrapQty = Count(OrigPocketChar, 'TEST')
        NewScrapQty  = Count(NewPocketChar, 'TEST')
        AdjustQty    = NewScrapQty - OrigScrapQty
        If AdjustQty NE 0 then
            Work_Order_Services('AdjustScrappedQty', WONo, AdjustQty)
        end
    end
    
    If {WO} NE '' then Service_Services('PostProcedure', 'RDS_SERVICES', 'VerifyWOLogRDSKeyIndex':SD$:Name)
    If {WO_MAT_KEY} NE ''  then Service_Services('PostProcedure', 'RDS_SERVICES', 'VerifyWOMatRDSNoIndex':SD$:Name)
    If {WO_STEP_KEY} NE '' then Service_Services('PostProcedure', 'RDS_SERVICES', 'VerifyWOStepRDSKeyIndex':SD$:Name)
    
    EndTick = GetTickCount()
    Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick)
    
return


DELETE_RECORD_PRE:

    Notes      = RetStack()
    Swap @FM with ' | ' in Notes
    LogData    = ''
    LogData<1> = LoggingDTM
    LogData<2> = @User4
    LogData<3> = Name
    LogData<4> = Notes
    Logging_Services('AppendLog', objLog, LogData, @RM, @FM) 
	ActionFlow = ACTION_STOP$
	
return


DELETE_RECORD:
	
	Notes      = RetStack()
    Swap @FM with ' | ' in Notes
    LogData    = ''
    LogData<1> = LoggingDTM
    LogData<2> = @User4
    LogData<3> = Name
    LogData<4> = Notes
    Logging_Services('AppendLog', objLog, LogData, @RM, @FM) 
	ActionFlow = ACTION_STOP$
	
return


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Internal GoSubs
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

ClearCursors:
    For counter = 0 to 8
        ClearSelect counter
    Next counter
return


Initialize_System_Variables:

    // Save these for restoration later
    SaveDict        = @DICT
    SaveID          = @ID
    SaveRecord      = @RECORD
    OrigFileError   = @FILE.ERROR

    // Now make sure @DICT, ID, and @RECORD are populated
    CurrentDictName = ''
    If @DICT then
        DictHandle = @DICT<1, 2>
        Locate DictHandle in @TABLES(5) Using @FM Setting fPos then
            CurrentDictName = Field(@TABLES(0), @FM, fPos, 1)
        end
    end

    If CurrentDictName NE DictName then
         Open DictName to @DICT else Status = 'Unable to initialize @DICT'
    end    

    @ID = KeyID
    If Record else
        // Record might not have been passed in. Read the record from the database table just to make sure.
        @FILE.ERROR     = ''
        Open TableName to hTable then
            FullFSList  = hTable[1, 'F' : @VM]
            BFS         = FullFSList[-1, 'B' : @SVM]
            LastHandle  = hTable[-1, 'B' : \0D\]
            FileHandle  = \0D\ : LastHandle[1, @VM]

            Call @BFS(READO.RECORD, BFS, FileHandle, KeyID, FMC, Record, ReadOStatus)
        end
    end
    @RECORD = Record

return


Restore_System_Variables:

    Transfer SaveDict   to @DICT
    Transfer SaveID     to @ID
    Transfer SaveRecord to @RECORD
    @FILE.ERROR = OrigFileError

return

