Function REACT_RUN_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        :   REACT_RUN_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 REACT_RUN_EQUATES
$Insert RETAINED_WAFERS_EQUATES
$Insert WO_LOG_EQUATES
$Insert GAN_STAGE_CYCLE_TIME_EQUATES

Equ COMMA$ to ','

Declare function    Error_Services, Database_Services, obj_RDS_Test, Environment_Services, GaN_Services
Declare function    Tool_Parms_Services, Datetime
Declare subroutine  Error_Services, Database_Services, Set_Status, Engineering_Services, Obj_Tables, Material_Services

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 'UNLOAD_DT'                     ; GoSub UNLOAD_DT
        Case CalcColName EQ 'CHAR_STATUS'                   ; GoSub CHAR_STATUS
        Case CalcColName EQ 'NUM_ANKO_CRITICAL_FAIL_WFRS'   ; GoSub NUM_ANKO_CRITICAL_FAIL_WFRS
        Case CalcColName EQ 'NUM_CRITICAL_FAIL_WFRS'        ; GoSub NUM_CRITICAL_FAIL_WFRS
        Case CalcColName EQ 'WFR_GRADES'                    ; GoSub WFR_GRADES
        Case CalcColName EQ 'WFR_RETAIN_BOX'                ; GoSub WFR_RETAIN_BOX
        Case CalcColName EQ 'WFR_RETAIN_SLOT'               ; GoSub WFR_RETAIN_SLOT
        Case CalcColName EQ 'WFR_SCRIBES'                   ; GoSub WFR_SCRIBES
        Case CalcColName EQ 'WFR_TRACK_PART'                ; GoSub WFR_TRACK_PART
    End Case

return


NUM_CRITICAL_FAIL_WFRS:
    
    NumFailures = 0
    InWfrIDs    = {IN_WFR_ID}
    For each WfrID in InWfrIDs using @VM setting vPos
        NumFailures += ( Xlate('WO_WFR', WfrID, 'CRITICAL_FAILURE', 'X') EQ True$ )
    Next WfrID
    ActionFlow = NumFailures
    
return


NUM_ANKO_CRITICAL_FAIL_WFRS:
    
    NumCritFailWfrs = 0
    InWfrIDs        = {IN_WFR_ID}
    PSNo            = Xlate('RDS', @ID, 'PROD_SPEC_ID', 'X')
    ANKOMetPockets  = Xlate('PROD_SPEC', PSNo, 'ANKO_MET_POCKETS', 'X')
    For each WfrID in InWfrIDs using @VM setting vPos
        ANKOMetPocket  = ANKOMetPockets<0, vPos>
        If ANKOMetPocket EQ True$ then
            NumCritFailWfrs += ( Xlate('WO_WFR', WfrID, 'CRITICAL_FAILURE', 'X') EQ True$ ) 
        end
    Next WfrID
    ActionFlow = NumCritFailWfrs
    
return


WFR_GRADES:
    
    InWfrIDs = {IN_WFR_ID}
    For each WfrID in InWfrIDs using @VM setting vPos
        ActionFlow<0, -1> = Xlate('WO_WFR', WfrID, 'GRADE', 'X')
    Next WfrID
    
return


WFR_RETAIN_BOX:
    
    InWfrIDs = {IN_WFR_ID}
    For each WfrID in InWfrIDs using @VM setting vPos
        ActionFlow<0, -1> = Xlate('WO_WFR', WfrID, 'RETAIN_BOX', 'X')
    Next WfrID
    
return


WFR_RETAIN_SLOT:
    
    InWfrIDs = {IN_WFR_ID}
    For each WfrID in InWfrIDs using @VM setting vPos
        ActionFlow<0, -1> = Xlate('WO_WFR', WfrID, 'RETAIN_SLOT', 'X')
    Next WfrID
    
return


WFR_SCRIBES:
    
    InWfrIDs = {IN_WFR_ID}
    For each WfrID in InWfrIDs using @VM setting vPos
        ActionFlow<0, -1> = Xlate('WO_WFR', WfrID, 'SCRIBE', 'X')
    Next WfrID
    
return


CHAR_STATUS:
    
    RDSClosed    = {DISP_COMPLETE}
*    CharDone     = ( Sum({CHAR_WFR_FLAG}) GT 0 )
    CharDone     = False$
    PrevCharRuns = Xlate('WO_LOG', {WO_NO}, 'LAST_CHAR_RUN', 'X')
    If PrevCharRuns EQ '' then PrevCharRuns = 1
    NumCharRuns  = DCount(PrevCharRuns, @VM)
    LastCharRun  = PrevCharRuns<0, NumCharRuns>
    If LastCharRun EQ '' then LastCharRun = 1                                                                             
    CharInterval = Xlate('PROD_SPEC',  {PS_NO}, 'CHAR_INTERVAL', 'X')
    RunNo        = {CASS_NO}
    Begin Case
        Case RunNo EQ 1
            CharReq = True$
        Case RunNo LT LastCharRun
            PrevCharRun = ''
            RDSNos = Xlate('WO_STEP', {WO_NO}:"*":1, 'RDS_KEY', 'X')
            For RunIndex = RunNo - 1 to 1 Step - 1
                RunRDSNo         = RDSNos<0, RunIndex>
                WfrIDs           = Xlate('REACT_RUN', RunRDSNo, 'IN_WFR_ID', 'X')
                RunCharFlags     = Xlate('REACT_RUN', RunRDSNo, 'CHAR_WFR_FLAG', 'X')
                RunCharacterized = False$
                For each WfrID in WfrIDs using @VM setting WfrIndex
                    WfrChar = RunCharFlags<0, WfrIndex>
                    If WfrChar then
                        CharType = GaN_Services('GetCharType', WfrID)
                        If CharType EQ 'Full' then RunCharacterized = True$
                    end
                Until RunCharacterized = True$
                Next WfrID
                If RunCharacterized EQ True$ then PrevCharRun = RunIndex
            Until PrevCharRun NE ''
            Next RunIndex
            If PrevCharRun EQ '' then PrevCharRun = 1
            CharReq = ( Mod( ( (RunNo) - PrevCharRun), CharInterval ) EQ 0 )
        Case Otherwise$
            CharReq = ( Mod( ( (RunNo) - LastCharRun), CharInterval ) EQ 0 )
    End Case
    
    WfrIDs    = {IN_WFR_ID}
    CharFlags = {CHAR_WFR_FLAG}
    For each WfrID in WfrIDs using @VM setting WfrIndex
        WfrChar = CharFlags<0, WfrIndex>
        If WfrChar then
            CharType = GaN_Services('GetCharType', WfrID)
            If CharType EQ 'Full' then CharDone = True$
        end
    Until CharDone EQ True$
    Next WfrID
    
    Begin Case
        Case ( (CharDone EQ True$) and (CharReq EQ True$) )
            ActionFlow = 'Sched-Done'
        Case CharDone EQ True$
            ActionFlow = 'Done'
        Case ( (CharReq  EQ True$) and (RDSClosed EQ True$) )
            ActionFlow = 'Skipped'
        Case CharReq  EQ True$
            ActionFlow = 'Sched'
        Case Otherwise$
            ActionFlow = ''
    End Case 
    
return


UNLOAD_DT:
    
    UnloadDt = {UNLOAD_SIG_DTM}[1,'.']
    ActionFlow = UnloadDt
    
return


WFR_TRACK_PART:
    
    WONo       = {WO_NO}
    ActionFlow = Xlate('WO_LOG', WONo, 'WAFER_TRACK_PART', '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.
    LoadWfrCnt                      = Record<REACT_RUN_LOAD_WFR_CNT$>
    LoadWfrCnt                      = LoadWfrCnt<1, 1, 1>
    Record<REACT_RUN_LOAD_WFR_CNT$> = LoadWfrCnt
    
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<REACT_RUN_SHIFT$>
    If Num(Shift) then
    	Begin Case
    		Case Shift EQ 1
    			Record<REACT_RUN_SHIFT$> = 'A'
    		Case Shift EQ 2
    			Record<REACT_RUN_SHIFT$> = 'B'
    		Case Shift EQ 3
    			Record<REACT_RUN_SHIFT$> = 'C'
    		Case Shift EQ 4
    			Record<REACT_RUN_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<REACT_RUN_SHIFT$>
    If Num(Shift) then
    	Begin Case
    		Case Shift EQ 1
    			Record<REACT_RUN_SHIFT$> = 'A'
    		Case Shift EQ 2
    			Record<REACT_RUN_SHIFT$> = 'B'
    		Case Shift EQ 3
    			Record<REACT_RUN_SHIFT$> = 'C'
    		Case Shift EQ 4
    			Record<REACT_RUN_SHIFT$> = 'D'
    		Case Otherwise$
    			Null
    	End Case
    end
    
return

WRITE_RECORD_PRE:
    
    Shift = Record<REACT_RUN_SHIFT$>
    If Num(Shift) then
    	Begin Case
    		Case Shift EQ 1
    			Record<REACT_RUN_SHIFT$> = 'A'
    		Case Shift EQ 2
    			Record<REACT_RUN_SHIFT$> = 'B'
    		Case Shift EQ 3
    			Record<REACT_RUN_SHIFT$> = 'C'
    		Case Shift EQ 4
    			Record<REACT_RUN_SHIFT$> = 'D'
    		Case Otherwise$
    			Null
    	End Case
    end
    SaveRecord = Record      
    
    If OrigRecord NE Record then
    	
        RDSNo         = Name
        ProdTWs	      = ''
        GaNRunID      = Record<REACT_RUN_GAN_RUN_ID$>
        Scribes       = {WFR_SCRIBES}
        SigProfile    = Record<REACT_RUN_WFR_STAGE$>
        SigProfileCnt = DCount(SigProfile, @VM)

        // Count the number of Test Wafers
        InWfrIDs = Record<REACT_RUN_IN_WFR_ID$>
        For each InWfrID in InWfrIDs using @VM setting vPos
            // Presume false until proven otherwise
            ProdTWs<0, vPos> = False$
            If InWfrID NE '' then
                Scribe = Scribes<0, vPos>
                ScrapID = GaNRunID[1,7]:'W'
                If (Scribe[1, 8] EQ ScrapID) then
                    ProdTWs<0, vPos> = True$
                end else
                    For SigProfileIndex = 1 to SigProfileCnt
                        Destroyed = False$
                        Stage     = SigProfile<1, SigProfileIndex>
                        WfrKID    = InWfrID
                        Convert '*' to '.' in WfrKID                                
                        WfrStageKey = RDSNo:'*':Stage:'*':WfrKID
                                              
                        StageDestTest	= XLATE('RUN_STAGE_WFR',WfrStageKey,'DEST_TEST','X')
                        StageCompSig	= XLATE('RUN_STAGE_WFR',WfrStageKey,'COMP_BY','X')
                        StageStatus     = Xlate('RUN_STAGE_WFR',WfrStageKey,'STATUS','X')
                        StageSkipped    = StageStatus EQ 'SKIP'
                        If ( (StageDestTest EQ True$) and (StageCompSig NE '') and (StageSkipped EQ False$) ) then
                            ProdTWs<0, vPos> = True$
                            Destroyed        = True$
                        end                               
                    until Destroyed	EQ True$                                  
                    next SigProfileIndex
                end
            end
        Next InWfrID
        SaveRecord<REACT_RUN_TEST_WAFER$> = ProdTWs
    end
    
return

WRITE_RECORD:

    WfrIDs = {IN_WFR_ID}
    For each WfrID in WfrIDs using @VM setting WfrIndex
        RetainBox = Xlate('WO_WFR', WfrID, 'RETAIN_BOX', 'X')
        If RetainBox NE '' then
            // Copy recipe and part number to RETAINED_WAFERS table
            RetWfrRec = Database_Services('ReadDataRow', 'RETAINED_WAFERS', WfrID)
            RetWfrRec<RETAINED_WAFERS.RECIPE$>  = {GAN_RECIPE} 
            RetWfrRec<RETAINED_WAFERS.PART_NO$> = {EPI_PART_NO}
            Database_Services('WriteDataRow', 'RETAINED_WAFERS', WfrID, RetWfrRec, True$, False$, True$)
        end
    Next WfrID
    *JRO
    WO_NO = {WO_NO}
    ReactType = XLATE('WO_LOG', WO_NO,67,'X')
    OrigUnloadDTMs = OrigRecord<REACT_RUN_UNLOAD_SIG_DTM$> : @VM
    NewUnloadDTMs = Record<REACT_RUN_UNLOAD_SIG_DTM$> : @VM
    
    //JRO 10/22/2020
    IF ReactType EQ 'GAN' then
        //Jro
        
        IF OrigUnloadDTMs NE NewUnloadDTMs then
            
            StartDTM = Record<REACT_RUN_ENTER_DTM$>
            StopDTM = Record<REACT_RUN_UNLOAD_SIG_DTM$>
            OperatorStart = Record<REACT_RUN_ENTER_BY$>
            OperatorStop = Record<REACT_RUN_UNLOAD_SIG$>
            StageName = 'EPI_DEPOSITION'
            Tool = 'R':Record<REACT_RUN_REACTOR$>
            ToolClass = 'GAN REACTOR'
            Exported = 0
            RecordTime = Datetime()
            GanStageCycleTimeRecKey = @ID : '*EPI_DEPOSITION'
            GanStageCycleTimeRec = XLATE('GAN_STAGE_CYCLE_TIME', GanStageCycleTimeRecKey, '', 'X')
            
            GanStageCycleTimeRec = Insert(GanStageCycleTimeRec, GAN_STAGE_CYCLE_TIME_STAGE$, 1, 0, StageName)
            GanStageCycleTimeRec = Insert(GanStageCycleTimeRec, GAN_STAGE_CYCLE_TIME_START$, 1, 0, StartDTM)
            GanStageCycleTimeRec = Insert(GanStageCycleTimeRec, GAN_STAGE_CYCLE_TIME_STOP$, 1, 0, StopDTM)
            GanStageCycleTimeRec = Insert(GanStageCycleTimeRec, GAN_STAGE_CYCLE_TIME_WFR_ID$, 1, 0, '')
            GanStageCycleTimeRec<GAN_STAGE_CYCLE_TIME_RUN_CREATION_DATE$> = RecordTime
            GanStageCycleTimeRec<GAN_STAGE_CYCLE_TIME_OPERATOR_START$> = OperatorStart
            GanStageCycleTimeRec<GAN_STAGE_CYCLE_TIME_OPERATOR_STOP$> = OperatorStop
            GanStageCycleTimeRec<GAN_STAGE_CYCLE_TIME_TOOL$> = Tool
            GanStageCycleTimeRec<GAN_STAGE_CYCLE_TIME_TOOL_CLASS$> = ToolClass
            GanStageCycleTimeRec<GAN_STAGE_CYCLE_TIME_RDS_NO$> = @ID
            IF StopDTM NE '' then
            	Obj_Tables('WriteRec', 'GAN_STAGE_CYCLE_TIME':@RM:GanStageCycleTimeRecKey:@RM:@RM:GanStageCycleTimeRec)
            end

            
            //Jro
        end
        null
    end
    //JRO 10/22/2020

return

DELETE_RECORD_PRE:
return

DELETE_RECORD:
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

