COMPILE FUNCTION Clean_Insp(EntID,Event,Parm1,Parm2,Parm3,Parm4,Parm5)
#pragma precomp SRP_PreCompiler

/*
	Commuter module for CLEAN_INSP (Clean & Inspection) window
	
	08/05/2009 - John C. Henry, J.C. Henry & Co., Inc.
	03/07/2017 - djs - Changed the SCAN_RESULTS.GOT_FOCUS event to a CHAR event instead to allow users to select
	                   the scan results row of their choice (to view those individual wafer results) without being
	                   prompted for a manual entry data override.
	10/29/2019 - djs - Fixed "SigRow EQ 1" to 'SelectedRow EQ 1' logic check within SignClean, SignInsp,
	                   and SignScan subroutines
	04/23/2021 - djs - Updated SIGN_ROTR_ACCEPTANCE.CLICK event to not block acceptance signatures when a 100%
	                   failure scan is required.
	05/13/2024 - djs - Replaced Ole Tab control (OLE_TAB_ROTR) with a groupbox control (ROTR_GROUP) to mitigate
	                   form behavior bugs in OI 10 post migration.
	06/13/2024	djm		Add new stage-specific supplement system.
*/

DECLARE SUBROUTINE Set_Property, End_Dialog, Send_Event, Set_Status, Center_Window, Post_Event, Comm_RDS
DECLARE SUBROUTINE ErrMsg, Send_Message, Set_Property, Send_Event, Btree.Extract, obj_AppWindow, Signature_Services
DECLARE SUBROUTINE obj_Notes, Security_Err_Msg, End_Window, Forward_Event, Start_Window, Create_Note
DECLARE SUBROUTINE obj_WO_Mat_Log, obj_WO_Mat, obj_Clean_Insp, Unlock, Lock, Database_Services, Yield
DECLARE SUBROUTINE Override_Log_Services, Dialog_Box, obj_WO_Wfr, Error_Services, Hold_Services

DECLARE FUNCTION   Get_Property, Get_Status, Dialog_Box, Utility, Popup, Collect.Ixvals, Environment_Services
DECLARE FUNCTION   Send_Message, Msg, Security_Check, obj_React_Run_CI, Select_Into, MemberOf, Database_Services
DECLARE FUNCTION   Start_Window, Create_Dialog, Database_Services, Set_Property, Error_Services, SRP_DateTime
DECLARE FUNCTION   obj_NCR, SRP_Array, Supplement_Services

$INSERT LOGICAL
$INSERT MSG_EQUATES
$INSERT APPCOLORS
$INSERT LSL_USERS_EQU
$INSERT SECURITY_RIGHTS_EQU
$INSERT REACT_EVENT_EQUATES
$INSERT POPUP_EQUATES
$INSERT RTI_STYLE_EQUATES
$INSERT CLEAN_INSP_EQUATES
$INSERT TOOL_CLASS_EQUATES
$INSERT TOOL_EQUATES
$INSERT WO_MAT_EQUATES
$INSERT WO_LOG_EQUATES
$INSERT SPC_QUEUE_EQUATES
$INSERT WM_OUT_EQUATES
$INSERT REACTOR_EQUATES
$INSERT NOTIFICATION_EQUATES

EQU PROTECTED$      TO 8
EQU CRLF$	        TO \0D0A\
EQU TAB$	        TO \09\
Equ ESC$            TO Char(27)

EQU COL$CLEAN_TOOL		TO 1
EQU COL$CLEAN_BOAT_ID	TO 2
EQU COL$CLEAN_SRD_NO	TO 3
EQU COL$CLEAN_SIG		TO 4
EQU COL$CLEAN_SIG_DTM	TO 5

EQU COL$DUMMY_1_PIXEL_WIDE		TO 1	;* Used for both INSP_SPEC and INSP controls

EQU COL$INSP_SPEC_LPD          TO 2
EQU COL$INSP_SPEC_SCRATCHES    TO 3
EQU COL$INSP_SPEC_SCRATCH_LEN  TO 4
EQU COL$INSP_SPEC_PITS         TO 5
EQU COL$INSP_SPEC_MOUNDS       TO 6
EQU COL$INSP_SPEC_STACK_FAULTS TO 7
EQU COL$INSP_SPEC_SPIKES       TO 8
EQU COL$INSP_SPEC_SPOTS        TO 9
EQU COL$INSP_SPEC_FOV          TO 10
EQU COL$INSP_SPEC_BL_DEFECTS   TO 11

EQU COL$INSP_TOOL         TO 2	;* Added INSP_TOOL column 10/29/2012 JCH
EQU COL$INSP_LPD          TO 3
EQU COL$INSP_SCRATCHES    TO 4
EQU COL$INSP_SCRATCH_LEN  TO 5
EQU COL$INSP_PITS         TO 6
EQU COL$INSP_MOUNDS       TO 7
EQU COL$INSP_STACK_FAULTS TO 8
EQU COL$INSP_SPIKES       TO 9
EQU COL$INSP_SPOTS        TO 10
EQU COL$INSP_FOV          TO 11
EQU COL$INSP_BL_DEFECTS   TO 12
EQU COL$INSP_SIG          TO 13
EQU COL$INSP_SIG_DTM      TO 14

EQU COL$INSP_SPEC_BSIDE_SCRATCHES		TO 1
EQU COL$INSP_SPEC_BSIDE_SCRATCH_LEN		TO 2
EQU COL$INSP_SPEC_BSIDE_NODULES			TO 3
EQU COL$INSP_SPEC_BSIDE_SPIKES			TO 4

EQU COL$INSP_BSIDE_SCRATCHES		TO 1
EQU COL$INSP_BSIDE_SCRATCH_LEN		TO 2
EQU COL$INSP_BSIDE_NODULES			TO 3
EQU COL$INSP_BSIDE_SPIKES			TO 4

EQU COL$SCAN_SPEC_SURF_RECIPE$	TO 1
EQU COL$SCAN_SPEC_SURF_DEFECTS$	TO 2
EQU COL$SCAN_SPEC_SURF_HAZE$	TO 3
EQU COL$SCAN_SPEC_SCRATCHES$	TO 4

EQU COL$SCAN_RECIPE				TO 1
EQU COL$SCAN_TOOL				TO 2
EQU COL$SCAN_SUM_OF_DEF_MIN		TO 3
EQU COL$SCAN_SUM_OF_DEF_MAX		TO 4
EQU COL$SCAN_SUM_OF_DEF_AVG		TO 5

EQU COL$SCAN_HAZE_AVG_AVG TO 6
EQU COL$SCAN_DCNMM2       TO 7
EQU COL$SCAN_REASON       TO 8
EQU COL$SCAN_SIG          TO 9
EQU COL$SCAN_SIG_DTM      TO 10
EQU COL$SCAN_TEST_RUN_DTM TO 11

EQU COL$SLOT			TO 1
EQU COL$WAFER_ID		TO 2
EQU COL$SLOT_NCR		TO 3
EQU COL$MET_NO$			TO 4
EQU COL$MOVED_TO_SLOT	TO 5
EQU COL$MU_WAFER_ID		TO 6
EQU COL$MOVED_FROM_SLOT	TO 7
EQU COL$REPLACED_BY		TO 8
EQU COL$MU_ADD_DATE     TO 9
EQU COL$MU_REM_DATE     TO 10

EQU COL$EPP_SLOT        TO 1
EQU COL$EPP_RDS_NO      TO 2
EQU COL$EPP_REACT_NO    TO 3
EQU COL$EPP_RDS_STATUS  TO 4
EQU COL$EPP_POCKET      TO 5
EQU COL$EPP_ZONE        TO 6
EQU COL$EPP_IN_CASS     TO 7
EQU COL$EPP_IN_SLOT     TO 8
EQU COL$EPP_SLOT_NCR    TO 9
EQU COL$EPP_MU_WO_NO    TO 10
EQU COL$EPP_MU_WO_STEP  TO 11
EQU COL$EPP_MU_CASS_NO  TO 12
EQU COL$EPP_MU_SLOT_NO  TO 13
EQU COL$EPP_UMW_CASS_ID TO 14
EQU COL$EPP_UMW_SLOT_NO TO 15
EQU COL$EPP_MU_BY       TO 16
EQU COL$EPP_MU_ADD_DATE TO 17
EQU COL$EPP_MU_REM_DATE TO 18

EQU HIDDEN$		TO 32
EQU SKIPPED$	TO 4100

ErrTitle = 'Error in CleanInsp'
ErrorMsg = ''

Result = ''

BEGIN CASE
    CASE EntID = @WINDOW
        BEGIN CASE
            CASE Event = 'CLEAR'			; GOSUB Clear
            CASE Event = 'CREATE' 			; GOSUB Create
            CASE Event = 'CLOSE'			; GOSUB Close
            CASE Event = 'WRITE'			; GOSUB Write
            CASE Event = 'READ'				; GOSUB Read
            CASE Event = 'VSCROLL'			; GOSUB VScroll
            CASE Event[1,3] = 'QBF'			; GOSUB Refresh
        END CASE
        
    CASE EntID = @WINDOW:'.SIGN_CLEAN'			    AND Event = 'CLICK'	 	    ; GOSUB SignClean
    CASE EntID = @WINDOW:'.SIGN_INSP'			    AND Event = 'CLICK'	 	    ; GOSUB SignInsp
    CASE EntID = @WINDOW:'.SIGN_SCAN'			    AND Event = 'CLICK'	 	    ; GOSUB SignScan
    CASE EntID = @WINDOW:'.SIGN_ROTR_ACCEPTANCE'	AND Event = 'CLICK'	 	    ; GOSUB SIGN_ROTR_ACCEPTANCE.CLICK
    CASE EntID = @WINDOW:'.BTN_WAFER_DETAILS'	    AND Event = 'CLICK'	 	    ; GOSUB BTN_WAFER_DETAILS.CLICK
    CASE EntID = @WINDOW:'.SCAN_RESULTS'	        AND Event = 'CHAR'  	    ; GOSUB SCAN_RESULTS.CHAR
    CASE EntID = @WINDOW:'.SCAN_RESULTS'            AND Event = 'POSCHANGED'    ; GOSUB SCAN_RESULTS.POSCHANGED 
    CASE EntID = @WINDOW:'.SPEC_BRIGHTLIGHT'	    AND Event = 'CLICK'		    ; GOSUB Refresh
    CASE EntID = @WINDOW:'.SPEC_MICROSCOPE' 	    AND Event = 'CLICK'		    ; GOSUB Refresh
    CASE EntID = @WINDOW:'.CHK_EDGE'                AND Event = 'CLICK'         ; GOSUB Refresh
    CASE EntID = @WINDOW:'.REFRESH_SPEC' 		    AND Event = 'CLICK'		    ; GOSUB RefreshSpec
    CASE EntID = @WINDOW:'.CI_TAB' 				    AND Event = 'CLICK'		    ; GOSUB Page
    CASE EntID = @WINDOW:'.INSP_RESULTS' 		    AND Event = 'POSCHANGED'	; GOSUB InspPC
    CASE EntID = @WINDOW:'.INSP_RESULTS_BSIDE'	    AND Event = 'POSCHANGED'	; GOSUB BSideInspPC
        
        
    CASE EntID = @WINDOW:'.SEND_SPC' AND Event = 'CLICK' 	; GOSUB SendSPC
        
    CASE 1
        
        ErrorMsg = 'Unknown Parameters ':EntID:' - ':Event:' passed to commuter'
        ErrMsg(ErrorMsg)
        
END CASE

IF ErrorMsg NE '' THEN
    ErrMsg(ErrTitle:@SVM:ErrorMsg)
END

RETURN Result



* * * * * * *
Create:
* * * * * * *
    
    obj_Appwindow('Create',@WINDOW)
    
    IF MemberOf(@USER4, 'OI_SUPERUSER') THEN
        Set_Property(@WINDOW:'.SEND_SPC','VISIBLE',1)
        Set_Property(@WINDOW:'.SPC_DTM','VISIBLE',1)
    END ELSE
        Set_Property(@WINDOW:'.SEND_SPC','VISIBLE',0)
        Set_Property(@WINDOW:'.SPC_DTM','VISIBLE',0)
    END
    
    CIKey = Get_Property(@Window : '.CI_NO', 'TEXT')
    
    * Setup Cleans Section
    
    CleanStyles = Send_Message(@WINDOW:'.CLEAN_RESULTS','COLSTYLE',0,'')
    
    CleanStyles<COL$CLEAN_TOOL>		= BitOr(CleanStyles<COL$CLEAN_TOOL>,DTCS_DROPDOWN$)
    CleanStyles<COL$CLEAN_BOAT_ID>	= BitOr(CleanStyles<COL$CLEAN_BOAT_ID>,DTCS_DROPDOWN$)
    CleanStyles<COL$CLEAN_SRD_NO>	= BitOr(CleanStyles<COL$CLEAN_SRD_NO>,DTCS_DROPDOWN$)
    
    Send_Message(@WINDOW:'.CLEAN_RESULTS','COLSTYLE',0,CleanStyles)				;* Set Styles

    * Setup Inspection Section
    
    InspStyles = Send_Message(@WINDOW:'.INSP_RESULTS','COLSTYLE',0,'')
    
    InspStyles<COL$INSP_TOOL> = BitOr(InspStyles<COL$INSP_TOOL>,DTCS_DROPDOWN$)
    
    Send_Message(@WINDOW:'.INSP_RESULTS','COLSTYLE',0,InspStyles)
    
    InspTools = 'SCOPE':@VM:'FF EDGE INSP':@VM:'SCOPE/FF EDGE INSP'

    Send_Message(@WINDOW:'.INSP_RESULTS','COLFORMAT',COL$INSP_TOOL,InspTools)
    
    * Setup Scan Section
    
    ScanStyles = Send_Message(@WINDOW:'.SCAN_RESULTS','COLSTYLE',0,'')
    
    ScanStyles<COL$SCAN_RECIPE>		= BitOr(ScanStyles<COL$SCAN_RECIPE>,DTCS_DROPDOWN$)
    ScanStyles<COL$SCAN_TOOL>		= BitOr(ScanStyles<COL$SCAN_TOOL>,DTCS_DROPDOWN$)
    
    Send_Message(@WINDOW:'.SCAN_RESULTS','COLSTYLE',0,ScanStyles)
    
    ScanTools = XLATE('TOOL_CLASS','TENCOR',TOOL_CLASS_TOOL$,'X')	;* Tencor class tools
    
    Send_Message(@WINDOW:'.SCAN_RESULTS','COLFORMAT',COL$SCAN_TOOL,ScanTools)
    
    IF MemberOf(@USER4, 'OI_SUPERUSER') THEN
        Set_Property(@WINDOW:'.REFRESH_SPEC','VISIBLE',1)
    END ELSE
        Set_Property(@WINDOW:'.REFRESH_SPEC','VISIBLE',0)
    END
    
    CIKey = Get_Property(@Window : '.CI_NO', 'TEXT')
    ReactorNo = Xlate('CLEAN_INSP', CIKey, 'REACT_NO', 'X')
    
    Stage = Get_Property(@Window : '.STAGE', 'TEXT')
    If Stage EQ 'LWI' then
        CanEdit     = Memberof(@USER4, 'ENGINEERING') or Memberof(@USER4, 'LEAD') or Memberof(@USER4, 'SUPERVISOR') |
        or Memberof(@USER4, 'FINAL_QA') or Memberof(@USER4, 'ROTR_OVERRIDE')
        // Check if manual entry lock is temporarily disabled for all users due to ROTR queue overflow.
        ManualEntryLock = Xlate('APP_INFO', 'ROTR_DATA_ENTRY_LOCK', 1, 'X')
        If (ManualEntryLock EQ False$) then CanEdit = True$
        Set_Property(@Window, '@CAN_EDIT', CanEdit)
        If Not(CanEdit) then
            // Disable manual entry of data.
            ScanStyles	= Send_Message(@Window : '.SCAN_RESULTS', 'COLSTYLE', 0, '')
            For column = 1 to 7
                ScanStyles<column> = BitOr( ScanStyles<column>, PROTECTED$ )
            Next column
            // Disable dropdown menus for recipe and tool columns.
            ScanStyles<COL$SCAN_RECIPE>		= BitAnd(ScanStyles<COL$SCAN_RECIPE>, BitNot(DTCS_DROPDOWN$) )
            ScanStyles<COL$SCAN_TOOL>		= BitAnd(ScanStyles<COL$SCAN_TOOL>, BitNot(DTCS_DROPDOWN$) )
            ScanStyles	= Send_Message(@Window : '.SCAN_RESULTS', 'COLSTYLE', 0, ScanStyles)
        end
    end
    
RETURN


* * * * * * *
Page:
* * * * * * *
    
    Page = Get_Property(@WINDOW:'.CI_TAB', 'VALUE')
    
    Set_Property(@WINDOW,'VPOSITION', Page)
    
RETURN


* * * * * * *
VScroll:
* * * * * * *
    
    Page = Parm1
    
    Set_Property(@WINDOW:'.CI_TAB','VALUE', Page)
    
    
RETURN


* * * * * * *
Clear:
* * * * * * *
    
    Send_Event(@WINDOW,'PAGE',1)
    
    
* * * * * * *
Refresh:
* * * * * * *

    CIKey     = Get_Property(@WINDOW:'.CI_NO', 'TEXT')
    // Hide or show the Cass No label and edit line based on the whether the reactor is EpiPro or not. - 04/10/2018 - dmb
    WONo      = Get_Property(@Window : '.WO_NO', 'TEXT')
    WOLogRow  = Database_Services('ReadDataRow', 'WO_LOG', WONo)
    ReactType = WOLogRow<WO_LOG_REACT_TYPE$>
    If ReactType NE 'EPP' then
        Visible     = True$
    end else
        Visible     = False$
    end
    Set_Property(@Window : '.CASS_NO_LABEL', 'VISIBLE', Visible)
    Set_Property(@Window : '.CASS_NO', 'VISIBLE', Visible)
    
    Stage = Get_Property(@WINDOW:'.STAGE','TEXT')
    
    * * * * * 
    
    Ctrls  = @WINDOW:'.STAGE':@RM					; Props  = 'TEXT':@RM
    Ctrls := @WINDOW:'.SPEC_FWI_LWI':@RM			; Props := 'TEXT':@RM
    Ctrls := @WINDOW:'.SPEC_CLEAN_TOOL_REP':@RM		; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.SPEC_BRIGHTLIGHT':@RM		; Props := 'CHECK':@RM
    Ctrls := @WINDOW:'.SPEC_MICROSCOPE':@RM			; Props := 'CHECK':@RM
    Ctrls := @WINDOW:'.CHK_EDGE':@RM			    ; Props := 'CHECK':@RM
    Ctrls := @WINDOW:'.SPEC_CLEAN_TOOL'				; Props := 'DEFPROP'
    
    Vals = Get_Property(Ctrls,Props)
    
    Stage            = Vals[1,@RM]
    SpecFwiLwi       = Vals[COL2()+1,@RM]
    SpecCleanToolRep = Vals[COL2()+1,@RM]
    SpecBrightlight  = Vals[COL2()+1,@RM]
    SpecMicroscope   = Vals[COL2()+1,@RM]
    SpecEdge         = Vals[COL2()+1,@RM]
    SpecCleanTool    = Vals[COL2()+1,@RM]
    
    SpecCleanTools = Get_Property(@WINDOW:'.SPEC_CLEAN_TOOL$','ARRAY')
    
    IF SpecCleanTools = '' THEN
        AkrionCleanTools	= XLATE('TOOL_CLASS','AKRION',TOOL_CLASS_TOOL$,'X')
        WetBenchTools		= XLATE('TOOL_CLASS','WET BENCH',TOOL_CLASS_TOOL$,'X')
        
        BEGIN CASE
            CASE AkrionCleanTools NE '' AND WetBenchTools NE ''	; SpecCleanTools = AkrionCleanTools:@VM:WetBenchTools
            CASE AkrionCleanTools NE '' AND WetBenchTools = ''	; SpecCleanTools = AkrionCleanTools
            CASE AkrionCleanTools = '' AND WetBenchTools NE ''	; SpecCleanTools = WetBenchTools
            CASE 1 ; NULL
        END CASE
    END
    
    LOOP
    UNTIL SpecCleanTools[-1,1] NE @VM OR SpecCleanTools = ''
        SpecCleanTools[-1,1] = ''
    REPEAT
    
    ScanRecipes = Get_Property(@WINDOW:'.SPEC_SURFSCAN','ARRAY')<COL$SCAN_SPEC_SURF_RECIPE$>		;* 1/22/2013 JCH ***********
    Send_Message(@WINDOW:'.SCAN_RESULTS','COLFORMAT',COL$SCAN_RECIPE,ScanRecipes)
    
    BEGIN CASE
        CASE Stage = 'PRE'
            LabelText = 'Pre Epi Cleaning && Inspection'
            Send_Message(@WINDOW:'.CLEAN_RESULTS','COLFORMAT',COL$CLEAN_TOOL,SpecCleanTools)
            Send_Message(@WINDOW:'.CLEAN_RESULTS','COLFORMAT',COL$CLEAN_BOAT_ID,XLATE('LISTBOX_CONFIG','PRECLEANCASSID',1,'X'))
            Send_Message(@WINDOW:'.CLEAN_RESULTS','COLFORMAT',COL$CLEAN_SRD_NO,XLATE('LISTBOX_CONFIG','PRECLEANSRD',1,'X'))
            
        CASE Stage = 'POST'
            LabelText = 'Post Epi Cleaning && Inspection'
            Send_Message(@WINDOW:'.CLEAN_RESULTS','COLFORMAT',COL$CLEAN_TOOL,SpecCleanTools)
            Send_Message(@WINDOW:'.CLEAN_RESULTS','COLFORMAT',COL$CLEAN_BOAT_ID,XLATE('LISTBOX_CONFIG','POSTCLEANCASSID',1,'X'))
            Send_Message(@WINDOW:'.CLEAN_RESULTS','COLFORMAT',COL$CLEAN_SRD_NO,XLATE('LISTBOX_CONFIG','POSTCLEANSRD',1,'X'))
            
            
        CASE Stage = 'FWI'							; LabelText = 'First Wafer Inspection'
        CASE Stage = 'LWI'							; LabelText = 'Last Wafer Inspection'
        CASE Stage = 'WFR' AND SpecFwiLwi = 'FWI'	; LabelText = 'First Wafer Inspection'
        CASE Stage = 'WFR' AND SpecFwiLwi = 'LWI'	; LabelText = 'Last Wafer Inspection'
        CASE Stage[1,3] = 'WFR'						; LabelText = 'Wafer ':Stage[4,99]:' Extra Inspection'
        CASE 1										; LabelText = 'Cleaning && Inspection'
    END CASE
    Set_Property(@WINDOW:'.WINDOW_LABEL_FIX','TEXT',LabelText)
       
    Ctrls  = @WINDOW:'.SPEC_CLEAN_SUBOXIDE':@RM				; Props  = 'CHECK':@RM
    Ctrls := @WINDOW:'.SPEC_CLEAN_TOOL':@RM					; Props := 'TEXT':@RM
    Ctrls := @WINDOW:'.SPEC_CLEAN_AKRION_RECIPE':@RM		; Props := 'TEXT':@RM
    Ctrls := @WINDOW:'.SPEC_BRIGHTLIGHT':@RM				; Props := 'CHECK':@RM
    Ctrls := @WINDOW:'.SPEC_MICROSCOPE':@RM					; Props := 'CHECK':@RM
    Ctrls := @WINDOW:'.CHK_EDGE':@RM                        ; Props := 'CHECK':@RM
    Ctrls := @WINDOW:'.SPEC_SURFSCAN'						; Props := 'ARRAY'
    
    Vals = Get_Property(Ctrls,Props)
    
    SCSubOxide     = Vals[1,@RM]
    SCTool         = Vals[COL2()+1,@RM]
    SCAkrionRecipe = Vals[COL2()+1,@RM] 
    SBrightLight   = Vals[COL2()+1,@RM]
    SMicroscope    = Vals[COL2()+1,@RM]
    SEdge          = Vals[COL2()+1,@RM]
    SSurfScanArray = Vals[COL2()+1,@RM]
    
    ScanRecipes = SSurfScanArray<COL$SCAN_SPEC_SURF_RECIPE$>
    
    CONVERT @VM TO '' IN ScanRecipes
    
    SSurfScanRecipe = ScanRecipes
    
    Ctrls  = @WINDOW:'.SPEC_CLEAN_REQ':@RM		; Props  = 'CHECK':@RM
    Ctrls := @WINDOW:'.SPEC_INSP_REQ':@RM		; Props := 'CHECK':@RM
    Ctrls := @WINDOW:'.SPEC_SURFSCAN_REQ'		; Props := 'CHECK'
    
    Vals = Get_Property(Ctrls,Props)
    
    CleanSigReq		= Vals[1,@RM]
    InspSigReq		= Vals[COL2()+1,@RM]
    SurfScanSigReq	= Vals[COL2()+1,@RM]
    
    IF SCTool NE '' OR CleanSigReq = 1 then
        CleanSigReq = 1
    end else
        CleanSigReq = 0
    end
    
    InspReq = Xlate('CLEAN_INSP', CIKey, 'SPEC_INSP_REQ', 'X')
    If InspReq EQ '' then InspReq = Xlate('CLEAN_INSP', CIKey, 'INSP_REQ', 'X')
    // Old records may have more than one RDS/CLEAN_INSP key.
    InspInterval = Xlate('CLEAN_INSP', CIKey, 'INSP_INTERVAL', 'X')<0, 1>
    If InspInterval NE '' then
        // Use the stored interval
        RDSNo        = Xlate('CLEAN_INSP', CIKey, 'RDS_NO', 'X')<0, 1>
        PSNo         = Xlate('CLEAN_INSP', CIKey, 'PS_NO', 'X')<0, 1>
        WONo         = Xlate('CLEAN_INSP', CIKey, 'WO_NO', 'X')<0, 1>
        WOQty        = Xlate('WO_LOG', WONo, 'QTY', 'X')<0, 1>
        RunNo        = Xlate('RDS', RDSNo, 'RUN_ORDER_NUM', 'X')<0, 1>
        StageKey     = PSNo:'*LWI'
        LastRun      = ( (RunNo * 25) EQ WOQty )
        InspReq      = ( (Mod((RunNo - 1), InspInterval) EQ 0) or LastRun )
    end else
        // Use the current PRS_STAGE interval
        InspReq = Xlate('CLEAN_INSP', CIKey, 'INSP_REQ', 'X')
    end
    
    If InspReq EQ False$ then
        Set_Property(@WINDOW:'.INSP_RESULT_GROUP', 'TEXT', 'Visual Inspection Not Required')
    end
    
    IF SBrightLight = 1 OR SMicroscope = 1 OR SEdge OR InspSigReq = 1	THEN
        InspSigReq = 1
    end ELSE
        InspSigReq = 0
    end
    
    IF SSurfScanRecipe NE '' OR SurfScanSigReq = 1	THEN
        SurfScanSigReq = 1
    end ELSE
        SurfScanSigReq = 0
    end
    
    DefBack = Get_Property(@WINDOW,'BACKCOLOR')
    
    ReqBackColor = CI_GROUP_BLUE$
    
    * ROTR 2/1/2012
    
    RotrAction = Get_Property(@WINDOW:'.ROTR_ACTION','TEXT')
    
    BEGIN CASE
        CASE RotrAction = 'Passed'
            RBackColor    = GREEN$	;*LS1_GREEN$
            BypassEnabled = False$
        CASE RotrAction = 'Failed'
            RBackColor    = RED$
            BypassEnabled = MemberOf(@USER4, 'ENGINEERING') OR MemberOf(@USER4, 'LEAD') OR MemberOf(@USER4, 'SUPERVISOR') OR MemberOf(@USER4, 'OI_ADMIN') OR MemberOf(@USER4, 'ROTR_OVERRIDE')
        CASE RotrAction = 'Waived'
            RBackColor    = YELLOW$	;*CMB_YELLOW$
            BypassEnabled = False$
        CASE RotrAction = 'Accepted'
            RBackColor    = ORANGE$	
            BypassEnabled = False$
        CASE 1
            IF SurfScanSigReq THEN
                RBackColor = ReqBackColor
            END ELSE
                RBackColor = DefBack
            END
            BypassEnabled   = False$
    END CASE
    
    Ctrls  = @WINDOW:'.ROTR_STATUS_LABEL':@FM			; Props  = 'BACKCOLOR':@FM	; Vals   = RBackColor:@FM
    Ctrls := @WINDOW:'.ROTR_REASON_LABEL':@FM			; Props := 'BACKCOLOR':@FM	; Vals  := RBackColor:@FM
    Ctrls := @WINDOW:'.SIGN_ROTR_SIGNATURE_LABEL':@FM	; Props := 'BACKCOLOR':@FM	; Vals  := RBackColor:@FM
    Ctrls := @WINDOW:'.SIGN_ROTR_REASON_LABEL':@FM		; Props := 'BACKCOLOR':@FM	; Vals  := RBackColor:@FM   
    Ctrls := @WINDOW:'.ROTR_GROUP':@FM			        ; Props := 'BACKCOLOR':@FM	; Vals  := RBackColor:@FM
    Ctrls := @WINDOW:'.ROTR_ACTION':@FM		            ; Props := 'ENABLED':@FM	; Vals  := 0:@FM
    Ctrls := @WINDOW:'.EDL_ROTR_REASON':@FM		        ; Props := 'ENABLED':@FM	; Vals  := 0:@FM
    Ctrls := @WINDOW:'.SIGN_ROTR_ACCEPTANCE':@FM        ; Props := 'ENABLED':@FM	; Vals  := BypassEnabled:@FM
    Ctrls := @WINDOW                                    ; Props := 'REDRAW'         ; Vals  := 1
    
    Convert @FM to @RM in Ctrls
    Convert @FM to @RM in Props
    Convert @FM to @RM in Vals
    Set_Property(Ctrls,Props,Vals)
    Set_Property(@Window:'.OLE_PIC_ROTR', 'OLE.BackgroundColor', RBackColor)
    
    IF Get_Property(@WINDOW:'.SPC_DTM','DEFPROP') = '' THEN
        Set_Property(@WINDOW:'.SEND_SPC','TEXT','Send to SPC')
    END ELSE
        Set_Property(@WINDOW:'.SEND_SPC','TEXT','Resend to SPC')
    END
    
    
    * Check for out of spec on the Inspection
    
    InspSpecs		= Get_Property(@WINDOW:'.SPEC_INSP','LIST')
    InspResults		= Get_Property(@WINDOW:'.INSP_RESULTS','LIST')
    BSInspSpecs		= Get_Property(@WINDOW:'.SPEC_INSP_BSIDE','LIST')
    BSInspResults	= Get_Property(@WINDOW:'.INSP_RESULTS_BSIDE','LIST')
    
    InspComplete  = 1
    InspOutOfSpec = 0
    ResultLineNo  = 1
    OutOfSpecLine = 0
    
    LOOP
        InspResult = InspResults[1,@FM]
        InspResults = DELETE(InspResults,1,0,0)
        
        BSInspResult = BSInspResults[1,@FM]
        BSInspReults = DELETE(BSInspResults,1,0,0)
        
    UNTIL InspOutOfSpec OR InspResult = '' OR InspResult[1,9] = @VM:@VM:@VM:@VM:@VM:@VM:@VM:@VM:@VM
        
        * Check Frontside columns
        
        FOR Col = COL$INSP_SPEC_LPD TO COL$INSP_SPEC_BL_DEFECTS 
            ColSpec		= InspSpecs<1,Col>
            colResult	= InspResult<1,Col + 1>  ;* Results has the tool column in front of the actual data
            
            IF ColSpec NE '' AND colResult = '' THEN InspComplete = 0
            
            IF colResult > 0 AND ColSpec NE '' THEN
                BEGIN CASE
                    CASE Col = COL$INSP_SPEC_SCRATCH_LEN
                        IF ColResult GT ColSpec THEN InspOutOfSpec = 1
                        
                    CASE Col = COL$INSP_SPEC_FOV
                        IF ColResult GT ColSpec THEN InspOutOfSpec = 1
                        
                    CASE 1
                        IF ColResult GE ColSpec THEN InspOutOfSpec = 1
                END CASE
            END
        NEXT Col
        
        * Check Backside columns
        
        FOR Col = COL$INSP_SPEC_BSIDE_SCRATCHES TO COL$INSP_SPEC_BSIDE_SPIKES
            ColSpec		= BSInspSpecs<1,Col>
            colResult	= BSInspResult<1,Col>
            
            IF ColSpec NE '' AND colResult = '' THEN InspComplete = 0
            
            IF colResult > 0 AND ColSpec NE '' THEN
                BEGIN CASE
                    CASE Col = COL$INSP_SPEC_BSIDE_SCRATCH_LEN
                        IF ColResult GT ColSpec THEN InspOutOfSpec = 1
                        
                    CASE 1
                        IF ColResult GE ColSpec THEN InspOutOfSpec = 1
                        
                END CASE
            END
        NEXT Col
        
        
        IF NOT(InspOutOfSpec) THEN
            ResultLineNo += 1
        END
        
    REPEAT
    
    IF InspOutOfSpec THEN
        Set_Property(@WINDOW:'.INSP_RESULTS','BACKCOLOR',RED$)
        Set_Property(@WINDOW:'.INSP_RESULTS_BSIDE','BACKCOLOR',RED$)
        Set_Property(@WINDOW:'.SIGN_INSP','ENABLED',0)
    END ELSE
        Set_Property(@WINDOW:'.INSP_RESULTS','BACKCOLOR',WHITE$)
        Set_Property(@WINDOW:'.INSP_RESULTS_BSIDE','BACKCOLOR',WHITE$)
        Set_Property(@WINDOW:'.SIGN_INSP','ENABLED',1)
    END
    
    
    IF NOT(InspComplete) THEN
        Set_Property(@WINDOW:'.SIGN_INSP','ENABLED',0)
    END
    
    
    * Check for out of spec on the Surface Scan results  *******************************
    
    SSurfRecipes	= SSurfScanArray<COL$SCAN_SPEC_SURF_RECIPE$>
    SSurfDefects	= SSurfScanArray<COL$SCAN_SPEC_SURF_DEFECTS$>
    SSurfHazes		= SSurfScanArray<COL$SCAN_SPEC_SURF_HAZE$>
    
    
    LOOP
        SSurfRecipe = SSurfRecipes[-1,'B':@VM]
    UNTIL SSurfRecipe NE '' OR SSurfRecipes = ''
        SSurfRecipes[COL1(),1] = ''
    REPEAT
    
    SurfResults	= Get_Property(@WINDOW:'.SCAN_RESULTS','LIST')
    
    * Remove empty lines from control
    
    LOOP
        SurfResLine = SurfResults[-1,'B':@FM]
        CONVERT @VM TO '' IN SurfResLine
    UNTIL SurfResLine NE '' OR SurfResults = ''
        SurfResults[COL1(),99] = ''
    REPEAT
    
    CurrRec     = Get_Property(@Window, 'RECORD')
    ScanResults = CurrRec<CLEAN_INSP_SCAN_RESULT$>
    CtrlName    = @WINDOW:'.SCAN_RESULTS'
    For each ScanResult in ScanResults using @VM setting Line   
        Begin Case
            Case ScanResult EQ 'P'
                Color = GREEN$:@FM:BLACK$:@FM:BGREEN$:@FM:BLACK$
            Case ScanResult EQ 'F'
                Color = RED$:@FM:BLACK$:@FM:BRED$:@FM:BLACK$
            Case Otherwise$
                Null         
        End Case
        // Color the row
        stat  = Send_Message(CtrlName, 'COLOR_BY_POS', 0, Line, Color)
    Next ScanResult
    
    Set_Property(@Window:'.SPEC_MICROSCOPE', 'ENABLED', False$)
    Set_Property(@Window:'.CHK_EDGE', 'ENABLED', False$)
    
    * QBF buttons
    
    Ctrls  = @WINDOW:'.QBF_FIRST_FIX':@RM		; Props  = 'ENABLED':@RM
    Ctrls := @WINDOW:'.QBF_PREV_FIX':@RM		; Props := 'ENABLED':@RM
    Ctrls := @WINDOW:'.QBF_ABS_FIX':@RM			; Props := 'ENABLED':@RM
    Ctrls := @WINDOW:'.QBF_NEXT_FIX':@RM		; Props := 'ENABLED':@RM
    Ctrls := @WINDOW:'.QBF_LAST_FIX':@RM		; Props := 'ENABLED':@RM
    Ctrls := @WINDOW:'.QBF_STOP_FIX'			; Props := 'ENABLED'
    
    IF Get_Property(@WINDOW,'QBFLIST') = '' THEN
        Vals = 0:@RM:0:@RM:0:@RM:0:@RM:0:@RM:0
    END ELSE
        Vals = 1:@RM:1:@RM:1:@RM:1:@RM:1:@RM:1
    END
    
    Set_Property(Ctrls,Props,Vals)
    
    * Turn edit table symbolic column backgrounds to green **************************************************
    
    ETSymbolics = Get_Property(@WINDOW,'@ET_SYMBOLICS')		;* Loaded during 'Create' in obj_Appwindow
    
    ETCtrls	= ETSymbolics<1>
    ETCols	= ETSymbolics<2>
    
    FOR I = 1 TO COUNT(ETCtrls,@VM) + (ETCtrls NE '')
        ETCtrl	= ETCtrls<1,I>
        ETList = Get_Property(ETCtrl,'LIST')
        FOR Line = 1 TO COUNT(ETList,@FM) + (ETList NE '')
            IF ETList<Line,1> NE '' THEN
                FOR N = 1 TO COUNT(ETCols<1,I>,@SVM) + (ETCols<1,I> NE '')
                    stat = Send_Message(ETCtrl,'COLOR_BY_POS',ETCols<1,I,N>,Line,GREEN$)
                NEXT N
            END
        NEXT I
    NEXT I
    
    ScanResultsArray = Get_Property(@Window : '.SCAN_RESULTS', 'ARRAY')
    TestDTMs = ScanResultsArray<COL$SCAN_TEST_RUN_DTM>
    Done = False$
    For each DTM in TestDTMs using @VM setting vPos
        If DTM NE '' then Done = True$
    Until Done EQ True$
    Next DTM
    Convert @VM to '' in TestDTMs
    TestDTMs = Trim(TestDTMs)
    If TestDTMs EQ '' then
        Set_Property(@Window : '.BTN_WAFER_DETAILS', 'ENABLED', False$)
    end else
        Set_Property(@Window : '.SCAN_RESULTS', 'SELPOS', 1:@FM:vPos)
    end
    
RETURN


* * * * * * *
Read:
* * * * * * *
    
    GOSUB Refresh
    
RETURN


* * * * * * *
Write:
* * * * * * *

    DontClose = Get_Property(@WINDOW,'@DONT_CLOSE')
    
    IF NOT(DontClose) THEN
    	Forward_Event()
        Post_Event(@WINDOW,'CLOSE')
    END ELSE
        Set_Property(@WINDOW,'@DONT_CLOSE',0)
        Result = 1
    END
    
RETURN


* * * * * * *
Close:
* * * * * * *
    
    obj_Appwindow('DetailReturn',@WINDOW)
    
RETURN



* * * * * * *
Delete:
* * * * * * *
    
RETURN


* * * * * * *
SignClean:
* * * * * * *
    
    CtrlID = @WINDOW:'.CLEAN_RESULTS'
    
    CtrlList = Get_Property(CtrlID,'LIST')
    
    SlotSelection	= Get_Property(CtrlID,'SELPOS')
    SelectedRow		= SlotSelection<2>
    
    SigRow = CtrlList<SelectedRow>
    
    
    IF SigRow<1,COL$CLEAN_TOOL>  = '' THEN
        ErrMsg('Process Error':@SVM:'Clean Tool column is required.')
        Set_Property(CtrlID,'SELPOS',COL$CLEAN_TOOL:@FM:SelectedRow)
        RETURN
    END
    
    
    CONVERT @VM TO '' IN SigRow
    
    ****
    
    Ctrls  = @WINDOW:'.WO_NO':@RM		; Props  = 'DEFPROP':@RM
    Ctrls := @WINDOW:'.WO_STEP':@RM		; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.CASS_NO':@RM		; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.STAGE':@RM		; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.RDS_NO'			; Props := 'DEFPROP'
    
    Vals = Get_Property(Ctrls,Props)
    
    WONo	= Vals[1,@RM]
    WOStep	= Vals[COL2()+1,@RM]
    CassNo	= Vals[COL2()+1,@RM]
    Stage	= Vals[COL2()+1,@RM]
    RDSNo	= Vals[COL2()+1,@RM]
    
    WOLogRow   = Database_Services('ReadDataRow', 'WO_LOG', WONo)
    ReactType  = WOLogRow<WO_LOG_REACT_TYPE$>
    
    IF Stage = 'POST' THEN
        IF RDSNo = '' THEN
            * Epi Pro wafers
            SigAction = WOStep:'MO_PSTC'
            SigStage = 'MO_PSTC'
        END ELSE
            SigAction	= WOStep:'PSTC'
            SigStage	= 'PSTC'
        END
        
    END ELSE
        SigAction	= WOStep:Stage:'C'
        SigStage	= Stage:'C'
    END
    
    IF SigRow NE '' AND CtrlList<SelectedRow,COL$CLEAN_SIG> = '' THEN
        
        If SelectedRow EQ 1 then
            WOMatKey = WONo:'*':CassNo
            Signature_Services('CheckSigOrder', WOMatKey, SigStage, RDSNo)
            If Error_Services('HasError') then
                ErrMsg(Error_Services('GetMessage'))
                return
            end   
        end
        
       // Add check for supplement signatures
        ValidStages = Supplement_Services('GetStagesForLot', 'RDS', RDSNo)
        If Count(ValidStages, SigStage) NE 0 then
            UnacknowledgedSupp = Supplement_Services('UnacknowledgedSupplementCheck', 'RDS', RDSNo, SigStage)
            If UnacknowledgedSupp NE FALSE$ then
                Response = Dialog_Box('NDW_RDS_SUPP_SIG', @Window, RDSNo :@FM: SigStage :@FM: FALSE$)
				If Response EQ False$ then return
            end
        End
        
        IF MemberOf(@USER4, 'OI_SUPERUSER') THEN
            Valid = 1
        END ELSE
            Valid = Dialog_Box('NDW_VERIFY_USER', @Window, @User4)
            Valid = Valid<1>
        END
        
        IF Valid = 1 THEN
            
            CurrDate = OCONV(Date(),'D4/')
            CurrTime = OCONV(Time(),'MTHS')
            CurrDTM = CurrDate:' ':CurrTime
            Signer = @USER4
            
            ToolID		= CtrlList<SelectedRow,COL$INSP_TOOL>
            ToolRec 	= XLATE('TOOL',ToolID,'','X')
            
            ToolWHCd	= ToolRec<TOOL_TOOL_WH$>
            ToolLoc		= ToolRec<TOOL_TOOL_LOC$>
            Tag			= ''
            
            owmParms = WONo:@RM:CassNo:@RM:WOStep:@RM:SigStage:@RM:Signer:@RM:CurrDTM:@RM:ToolID:@RM:ToolWHCd:@RM:ToolLoc:@RM:Tag		;* Sets PSTC signature
            
            IF Get_Status(errCode) THEN
                CALL ErrMsg(ErrCode)
                RETURN
            END
            
            ToolID		= CtrlList<SelectedRow,COL$CLEAN_TOOL>
            ToolRec 	= XLATE('TOOL',ToolID,'','X')
            
            ToolWHCd	= ToolRec<TOOL_TOOL_WH$>
            ToolLoc		= ToolRec<TOOL_TOOL_LOC$>
            
            LogFile	= 'WO_MAT'			; WOMLParms  = LogFile:@RM
            LogDTM	= CurrDTM			; WOMLParms := LogDTM:@RM
            Action	= SigAction			; WOMLParms := Action:@RM
            WhCd	= ToolWHCd			; WOMLParms := WhCd:@RM
            LocCd	= ToolLoc			; WOMLParms := LocCd:@RM
            WONos	= WONo				; WOMLParms := WONos:@RM
            CassNos	= CassNo			; WOMLParms := CassNos:@RM
            UserID	= Signer			; WOMLParms := UserID:@RM
            Tags	= Tag				; WOMLParms := Tags:@RM
            ToolID	= ToolID			; WOMLParms := ToolID
            
            obj_WO_Mat_Log('Create',WOMLParms)											;* Stage PSTC log entry
            
            IF Get_Status(errCode) THEN
                ErrMsg(errCode)
                RETURN
            END
            
            Set_Property(CtrlID,'CELLPOS',Signer,COL$CLEAN_SIG:@FM:SelectedRow)
            Set_Property(CtrlID,'CELLPOS',CurrDTM,COL$CLEAN_SIG_DTM:@FM:SelectedRow)
            
            
            CINo = Get_Property(@WINDOW:'.CI_NO','DEFPROP')
            
            Set_Property(@WINDOW,'@DONT_CLOSE',1)
            
            Send_Event(@WINDOW,'WRITE')
            
            obj_AppWindow('LUValReturn',CINo:@RM:@WINDOW:'.CI_NO')
            
        END
        
    END ELSE
        IF SigRow = '' THEN
            ErrMsg('Process Error':@SVM:'Must have some information in selected row to sign.')
            RETURN
        END
        
        IF CtrlList<SelectedRow,COL$CLEAN_SIG> NE '' THEN
            ErrMsg('Process Error':@SVM:'Row is already signed.')
            RETURN
        END
    END
    
RETURN


* * * * * * *
SignInsp:
* * * * * * *
    
    CtrlID = @WINDOW:'.INSP_RESULTS'
    
    CtrlList = Get_Property(CtrlID,'LIST')
    
    SlotSelection	= Get_Property(CtrlID,'SELPOS')
    SelectedRows	= SlotSelection<2>
    
    SlotSelection	= Get_Property(CtrlID,'SELPOS')
    SelectedRow		= SlotSelection<2>
    
    SigRow     = CtrlList<SelectedRow>
    BackSigRow = Get_Property(@Window:'.INSP_RESULTS_BSIDE', 'LIST')<SelectedRow>
    
    FrontSpecRow = Get_Property(@Window:'.SPEC_INSP', 'LIST')
    BackSpecRow  = Get_Property(@Window:'.SPEC_INSP_BSIDE', 'LIST')
    
    InspTools = 'SCOPE':@VM:'FF EDGE INSP':@VM:'SCOPE/FF EDGE INSP'
    SelTool   = SigRow<1,COL$INSP_TOOL>
    
    IF SelTool = '' THEN
        ErrMsg('Process Error':@SVM:'Insp Tool column is required.')
        Set_Property(CtrlID,'SELPOS',COL$INSP_TOOL:@FM:SelectedRow)
        RETURN
    END
    
    // Ensure tool selected matches that of the prescribed inspection type
    EdgeInspReq  = Get_Property(@Window:'.CHK_EDGE', 'CHECK')
    ScopeInspReq = Get_Property(@Window:'.SPEC_MICROSCOPE', 'CHECK')
    Begin Case
        Case EdgeInspReq and ScopeInspReq
            If SelTool NE 'SCOPE/FF EDGE INSP' then
                ErrMsg('Process Error':@SVM:'Edge inspection and scope inspection are required. Selected tool must be "SCOPE/FF EDGE INSP"')
                Set_Property(CtrlID,'SELPOS',COL$INSP_TOOL:@FM:SelectedRow)
                return
            end
        Case ScopeInspReq 
            If SelTool NE 'SCOPE' then
                ErrMsg('Process Error':@SVM:'Microscope inspection is required. Selected tool must be "SCOPE"')
                Set_Property(CtrlID,'SELPOS',COL$INSP_TOOL:@FM:SelectedRow)
                return
            end
        Case EdgeInspReq
            If SelTool NE 'FF EDGE INSP' then
                ErrMsg('Process Error':@SVM:'Edge inspection is required. Selected tool must be "FF EDGE INSP"')
                Set_Property(CtrlID,'SELPOS',COL$INSP_TOOL:@FM:SelectedRow)
                return
            end
    End Case
    
    // Verify frontside inspection data
    For Col = COL$INSP_SPEC_LPD to COL$INSP_SPEC_BL_DEFECTS
        
        ColSpec = FrontSpecRow<1, Col>
        ColVal  = SigRow<1, Col + 1>  ;* Results has the tool column in front of the actual data
        If ( (ColSpec NE '') and (ColVal EQ '') ) then
            ErrMsg('Process Error':@SVM:'Data is missing in column number ':Col-1:'.')
            Set_Property(CtrlID,'SELPOS',Col:@FM:SelectedRow)
            RETURN
        end
        
    Next Col
    
    // Verify backside inspection data
    For Col = COL$INSP_SPEC_BSIDE_SCRATCHES to COL$INSP_SPEC_BSIDE_SPIKES
        
        ColSpec = BackSpecRow<1, Col>
        ColVal  = BackSigRow<1, Col>
        If ( (ColSpec NE '') and (ColVal EQ '') ) then
            ErrMsg('Process Error':@SVM:'Data is missing in column number ':Col-1:'.')
            Set_Property(CtrlID,'SELPOS',Col:@FM:SelectedRow)
            RETURN
        end
        
    Next Col
    
    CONVERT @VM TO '' IN SigRow
    
    Ctrls  = @WINDOW:'.WO_NO':@RM		; Props  = 'DEFPROP':@RM
    Ctrls := @WINDOW:'.WO_STEP':@RM		; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.CASS_NO':@RM		; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.STAGE':@RM		; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.RDS_NO'			; Props := 'DEFPROP'
    
    Vals = Get_Property(Ctrls,Props)
    
    WONo	= Vals[1,@RM]
    WOStep	= Vals[COL2()+1,@RM]
    CassNo	= Vals[COL2()+1,@RM]
    Stage	= Vals[COL2()+1,@RM]
    RDSNo	= Vals[COL2()+1,@RM]
    
    WOLogRow   = Database_Services('ReadDataRow', 'WO_LOG', WONo)
    ReactType  = WOLogRow<WO_LOG_REACT_TYPE$>
    
    IF Stage = 'POST' THEN
        IF RDSNo = '' THEN
            * Epi Pro wafers
            SigAction = WOStep:'MO_PSTI'
            SigStage = 'MO_PSTI'
        END ELSE
            SigAction	= WOStep:'PSTI'
            SigStage	= 'PSTI'
        END
        
    END ELSE
        SigAction	= WOStep:Stage:'I'
        SigStage	= Stage:'I'
    END
    
    IF SigRow NE '' AND CtrlList<SelectedRow,COL$INSP_SIG> = '' THEN
        
        If SelectedRow EQ 1 then
            WOMatKey = WONo:'*':CassNo
            Signature_Services('CheckSigOrder', WOMatKey, SigStage, False$, RDSNo)
            If Error_Services('HasError') then
                ErrMsg(Error_Services('GetMessage'))
                return
            end    
            
        END	;* End of check for 1st Signature row
        
        // Add check for supplement signatures
        ValidStages = Supplement_Services('GetStagesForLot', 'RDS', RDSNo)
        If Count(ValidStages, SigStage) NE 0 then
            UnacknowledgedSupp = Supplement_Services('UnacknowledgedSupplementCheck', 'RDS', RDSNo, SigStage)
            If UnacknowledgedSupp NE FALSE$ then
                Response = Dialog_Box('NDW_RDS_SUPP_SIG', @Window, RDSNo :@FM: SigStage :@FM: FALSE$)
				If Response EQ False$ then return
            end
        End
        
        // Check if edge inspection is prescribed. If so, prompt user whether or not edge defects are present.
        If EdgeInspReq then
            // If edge defects are present, present user with a wafer selection dialog and create an NCR for those wafers.
            Response = Msg(@Window, '', 'YESNO', '', 'Edge Defects':@FM:'Are any edge defects present?')
            If Response EQ True$ then
                // Display a popup of wafers in the RDS or WM_OUT cassette
                WONo      = Get_Property(@Window : '.WO_NO', 'TEXT')
                WOStepNo  = Get_Property(@Window:'.WO_STEP', 'TEXT')
                ReactType = Xlate('WO_LOG', WONo, 'REACT_TYPE', 'X')
                CassNo    = Get_Property(@Window:'.CASS_NO', 'TEXT')
                WOMatKey  = WONo:'*':CassNo
                
                If ReactType NE 'EPP' then
                    // Non-EpiPro
                    // Loop until user successfully creates an NCR
                    Loop
                        ErrFlag    = False$
                        // Prompt user to select affected wafers
                        Response   = Dialog_Box('DBW_WO_MAT_WAFER_SELECT', @Window, WOMatKey)
                        If Response EQ 'Cancel' then
                            ErrMsg('Signature operation aborted.')
                            return
                        end
                        SelRowData = SRP_Array('Rotate', Response, @FM, @VM)
                        
                        SlotNos  = SelRowData<COL$SLOT>
                        WfrIDs   = SelRowData<COL$WAFER_ID>
                        PrevNCRs = SelRowData<COL$SLOT_NCR>
                        MetNos   = SelRowData<COL$MET_NO$>
                        MUWfrIDs = SelRowData<COL$MU_WAFER_ID>
                        
                        IneligibleSlots   = ''  
                        For each SlotNo in SlotNos using @VM setting vPos
                            MetNo   = MetNos<0, vPos>
                            WfrID   = WfrIDs<0, vPos>
                            PrevNCR = PrevNCRs<0, vPos>
                            MUWfrID = MUWfrIDs<0, vPos>
                            If ( (MetNo NE '') or (WfrID EQ '') or (PrevNCR NE '' and MUWfrID EQ '') ) then
                                ErrFlag                = True$
                                IneligibleSlots<0, -1> = SlotNo
                            end
                        Next SlotNo            
                        
                        If ErrFlag EQ False$ then
                            
                            // Place the lot on hold if it isn't already.
                            HoldEntity   = 'WO_MAT'
                            HoldEntityID = WOMatKey
                            Set_Status(0)
                            OnHold       = Xlate('WO_MAT', WOMatKey, 'HOLD', 'X')
*                            If Not(OnHold) then obj_WO_Mat('ToggleHold',WOMatKey:@RM:HoldEntity:@RM:HoldEntityID:@RM:'')
							If Not(OnHold) then Hold_Services('ToggleHold', WOMatKey, HoldEntity, HoldEntityID, '', '', '', '')
                            ErrCode      = ''
                            If Not(Get_Status(ErrCode)) then
                                // Ensure the user didn't cancel the hold operation.
                                OnHold       = Xlate('WO_MAT', WOMatKey, 'HOLD', 'X')
                                If OnHold then
                                    
                                    // Set ROTR block on reactor
                                    Reactor                                 = Xlate('RDS', RDSNo, 'REACTOR', 'X')
                                    ReactorRec                              = Database_Services('ReadDataRow', 'REACTOR', Reactor)
                                    ReactorRec<REACTOR_ROTR_STATUS$>        = 'F'
                                    ReactorRec<REACTOR_ROTR_STATUS_REASON$> = 'Edge defects reported for RDS ':RDSNo:'.'
                                    Database_Services('WriteDataRow', 'REACTOR', RDSNo, ReactorRec)
                                    
                                    Def = ""
                                    Def<MTEXT$> = "Creating NCR...Please wait"
                                    Def<MTYPE$> = "U"
                                    MsgUp       = Msg(@window, Def)   ;* display the processing message
                                    
                                    WOMatKey  = WONo:'*':CassNo
                                    ncrParms  = WONo:@RM
                                    ncrParms := WOStepNo:@RM
                                    ncrParms := CassNo:@RM				                                    
                                    ncrParms := RDSNo:@RM				
                                    ncrParms := Reactor:@RM				
                                    ncrParms := '':@RM					                                    ;* Stage
                                    ncrParms := '':@RM					                                    ;* InCassNos
                                    ncrParms := SlotNos:@RM				                                    ;* InSlotNos
                                    ncrParms := '':@RM					                                    ;* EPP only - PockeNots
                                    ncrParms := '':@RM					                                    ;* EPP only - Zones
                                    ncrParms := '':@RM					                                    ;* EPP only - OutCassNos
                                    ncrParms := '':@RM					                                    ;* EPP only - OutSlotNos
                                    ncrParms := '':@RM					                                    ;* EPP only - Multiple RDSNos
                                    ncrParms := WfrIDs:@RM   			                                    ;* Rejected Wafer ID's
                                    ncrParms := PrevNCRs:@RM    		                                    ;* Previous NCR Nos
                                    ncrParms := '':@RM                                                      ;* EPP only - MU WONos
                                    ncrParms := '':@RM                                                      ;* EPP only - MU WO Step Nos
                                    ncrParms := '':@RM                                                      ;* EPP only - MU Cass Nos
                                    ncrParms := '':@RM                                                      ;* EPP only - MU Slot Nos
                                    ncrParms := 'C':@RM                                                     ;* Loss By
                                    ncrParms := 'Wafers removed due to edge defects':@RM                    ;* Containment Actions
                                    ncrParms := 'Edge defects discovered during post-epi inspection':@RM    ;* Loss Comments
                                    ncrParms := '':@RM                                                      ;* AC Comments
                                    ncrParms := '':@RM                                                      ;* Department Responsible
                                    ncrParms := '':@RM                                                      ;* AC Code
                                    ncrParms := 'D63':@RM                                                   ;* Loss Code
                                    ncrParms := 'O':@RM                                                     ;* NCR Status - Open
                                    ncrParms := '':@RM                                                      ;* Shift
                                    ncrParms := '':@RM                                                      ;* Shipment Signature
                                    ncrParms := '':@RM                                                      ;* Reject Signature
                                    ncrParms := '':@RM                                                      ;* Sent to SPC Datetime
                                    ncrParms := '':@RM                                                      ;* Shipment Signature Datetime
                                    ncrParms := 'Production'                                                ;* Department Handled
                                    
                                    Set_Status(0)
                                    NCRNo      = obj_NCR('Create',ncrParms)		;* Create new NCR for this wafer/group of wafers
                                    Msg(@window, MsgUp)         ;* take down the processing message
                                    
                                    SAPBatchNo = Xlate('WO_MAT', WOMatKey, 'SAP_BATCH_NO', 'X')
                                    
                                    IF Not(Get_Status(errCode)) THEN
                                        IF SAPBatchNo NE '' THEN
                                            IF SAPBatchNo[-1,1] NE 'R' THEN
                                                MUFlag       = Xlate('NCR', NCRNo, 'MAKEUP_BOX', 'X')
                                                MUFlag       = OCONV(MUFlag ,'BYes,')   
                                                PartNoID     = Xlate('NCR', NCRNo, 'WO_MAT_PART_NO', 'X')
                                                RejCnt       = Xlate('NCR', NCRNo, 'REJ_CNT', 'X')
                                                Recipients   = XLATE('NOTIFICATION', 'NCR_AFTER_GR', NOTIFICATION_USER_ID$, 'X')
                                                SentFrom     = @USER4
                                                Subject      = 'SAP Post - GR Scrap Qty - NCR Reported'																					;* Modified subject line - dkk 7/17/14
                                                Message      = "NCR: ":NCRNo:CRLF$:"Batch_No: ":SAPBatchNo:CRLF$:"MU Box: ":MUFlag:CRLF$:"Epi PN: ":PartNoID:CRLF$:"Qty: ":RejCnt		;* Added Epi PN on the end - dkk 7/17/14
                                                AttachWindow = 'NCR'
                                                AttachKey    = NCRNo
                                                SendToGroup  = ''
                                                Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup
                                                obj_Notes('Create',Parms)
                                            END
                                        END
                                        
                                        RejDTM = OCONV(Date(),'D4/'):' ':OCONV(Time(),'MTS')
                                        
                                        sCnt = COUNT(SlotNos,@VM) + (SlotNos NE '')
                                        FOR N = 1 TO sCnt
                                            * * * *   Added 3/23/2016  JCH - wafer history   * * * * 
                                            
                                            RejWfrID   = WfrIDs<1,N>
                                            CurrSlotID = WONo:'*':CassNo:'*':SlotNos<1,N>
                                            
                                            Convert '.' To '*' In RejWfrID
                                            
                                            Parms  = RejWfrID:@RM							;* WfrID
                                            Parms := RejDTM:@RM								;* EventDtm
                                            Parms := @USER4:@RM								;* EventBy
                                            Parms := 'NCR':@RM								;* Event
                                            Parms := '':@RM									;* NewSlotID
                                            Parms := '':@RM									;* RunLoc
                                            Parms := NCRNo:@RM								;* NCRNo
                                            Parms := '':@RM									;* TWUse
                                            Parms := CurrSlotID:@RM							;* CurrSlotID
                                            Parms := '':@RM									;* NewToolID
                                            Parms := '':@RM									;* CurrToolID
                                            Parms := '':@RM									;* NewInvLoc
                                            Parms := '':@RM									;* CurrInvLoc
                                            Parms := 'O'									;* Wfr Side
                                            
                                            obj_WO_Wfr('AddEvent',Parms)
                                            * * * * * * * * *
                                            LineNo = SlotNos<1,N>
                                        NEXT N
                                        
                                        // Display the new NCR so the user can fill in the details and sign it off.
                                        Dialog_Box('NCR', @Window, NCRNo)
                                        
                                    end else
                                        // Bail to force user to contact FI to correct issue.
                                        ErrMsg('Error creating NCR. Error message: ':ErrCode:'. Please contact FI for assistance.')
                                        return
                                    end
                                end else
                                    // User cancelled the hold operation.
                                    ErrMsg('The lot must be placed on hold. Signature operation cancelled.')
                                    return
                                end
                            end else
                                // Bail to force user to contact FI to correct issue.
                                ErrMsg('Error placing lot on hold. Error message: ':ErrCode:'. Please contact FI for assistance.')
                                return
                            end
                        end else
                            // Inform user ineligible wafer(s) were selected and loop to try again.
                            Swap @VM with ',' in IneligibleSlots
                            ErrMsg('Selected slot(s) ' : IneligibleSlots : ' are not eligible for NCR.')
                        end
                        
                    Until Not(ErrFlag)
                    Repeat
                    
                end else
                    // EpiPro
                    WMOKey       = WONo:'*':WOStepNo:'*':CassNo
                    
                    // Loop until user selects at least one eligible wafer to NCR.
                    Loop
                        ErrFlag  = False$
                        
                        // Prompt user to select affected wafers.
                        SelRows  = ''
                        Response = Dialog_Box('DBW_WM_OUT_WAFER_SELECT', @Window, WMOKey)
                        If Response EQ 'Cancel' then
                            ErrMsg('Signature operation aborted.')
                            return
                        end
                        SelRowData = SRP_Array('Rotate', Response, @FM, @VM)
                        
                        NCROutSlotNos        = SelRowData<COL$EPP_SLOT>
                        NCROutCassNos        = Str(CassNo:@VM, DCount(NCROutSlotNos, @VM))
                        NCROutCassNos[-1 ,1] = ''
                        NCRRDSNos            = SelRowData<COL$EPP_RDS_NO>
                        NCRPocketNos         = SelRowData<COL$EPP_POCKET>
                        NCRZones             = SelRowData<COL$EPP_ZONE>
                        NCRInCassNos         = SelRowData<COL$EPP_IN_CASS>
                        NCRInSlotNos         = SelRowData<COL$EPP_IN_SLOT>
                        NCRSlotNCRs          = SelRowData<COL$EPP_SLOT_NCR>
                        NCRMUWONos           = SelRowData<COL$EPP_MU_WO_NO>
                        NCRMUWOSteps         = SelRowData<COL$EPP_MU_WO_STEP>
                        NCRMUCassIDs         = SelRowData<COL$EPP_MU_CASS_NO>
                        NCRMUSlotNos         = SelRowData<COL$EPP_MU_SLOT_NO>
                        UsedMUCassIDs        = SelRowData<COL$EPP_UMW_CASS_ID>
                        
                        ErrFlag              = False$
                        For each SelSlot in NCROutSlotNos using @VM setting vPos
                            IF UsedMUCassIDs<0, vPos> = '' THEN
                                IF NCRRDSNos<0, vPos> NE '' THEN
                                    IF NCRSlotNCRs<0, vPos> = '' OR NCRMUWONos<0, vPos> NE '' THEN
                                        Null
                                    END ELSE
                                        ErrMsg('Slot ':SelSlot:' is empty.')
                                        ErrFlag = True$
                                    END	;* End of check for no Slot NCR (original wafer being rejected) or MU wafer data (makeup wafer being rejected)
                                END ELSE
                                    ErrMsg('Slot ':SelSlot:' is not used.')
                                    ErrFlag = True$
                                END	;* End of check for RDS (wafer) present and not used for makeup
                            END	ELSE
                                ErrMsg('Slot ':SelSlot:' has been used for makeup.')
                                ErrFlag = True$
                            END	;* End of check for slot Used for Makeup Wafer
                        Until ErrFlag
                        Next SelSlot
                        
                        // Create an NCR with edge defects loss code
                        If Not(ErrFlag) then
                            
                            // Place the lot on hold if it isn't already on hold.
                            HoldEntity   = 'WM_OUT'
                            HoldEntityID = WMOKey
                            Set_Status(0)
                            OnHold       = Xlate('WO_MAT', WOMatKey, 'HOLD', 'X')
*                            If Not(OnHold) then obj_WO_Mat('ToggleHold',WOMatKey:@RM:HoldEntity:@RM:HoldEntityID:@RM:'')
							If Not(OnHold) then Hold_Services('ToggleHold', WOMatKey, HoldEntity, HoldEntityID, '', '', '', '')
                            ErrCode      = ''
                            If Not(Get_Status(ErrCode)) then
                                
                                // Ensure the user didn't cancel the hold operation.
                                OnHold       = Xlate('WM_OUT', WMOKey, 'HOLD', 'X')
                                If OnHold then
                                    
                                    // Set ROTR block on reactor
                                    ROTRReactNos = SRP_Array('Clean', NCRRDSNos, 'TrimAndMakeUnique', @VM)
                                    If ROTRReactNos NE '' then
                                        For each ROTRReactNo in ROTRReactNos using @VM
                                            Reactor                                 = Xlate('RDS', ROTRReactNo, 'REACTOR', 'X')
                                            ReactorRec                              = Database_Services('ReadDataRow', 'REACTOR', Reactor)
                                            ReactorRec<REACTOR_ROTR_STATUS$>        = 'F'
                                            ReactorRec<REACTOR_ROTR_STATUS_REASON$> = 'Edge defects reported for outbound cassette ':WMOKey:'.'
                                            Database_Services('WriteDataRow', 'REACTOR', Reactor, ReactorRec)
                                        Next ROTRReactNo
                                    end
             
                                    Def         = ""
                                    Def<MTEXT$> = "Creating NCR...Please wait"
                                    Def<MTYPE$> = "U"
                                    MsgUp       = Msg(@window, Def)   ;* display the processing message
                                    
                                    ncrParms  = WONo:@RM
                                    ncrParms := WOStep:@RM
                                    ncrParms := CassNo:@RM							
                                    ncrParms := '':@RM									                    ;* Single RDS field - N/A for EpiPro
                                    ncrParms := '':@RM									                    ;* Reactor No - N/A for EpiPro
                                    ncrParms := 'POST':@RM
                                    ncrParms := NCRInCassNos:@RM
                                    ncrParms := NCRInSlotNos:@RM
                                    ncrParms := NCRPocketNos:@RM
                                    ncrParms := NCRZones:@RM
                                    ncrParms := NCROutCassNos:@RM
                                    ncrParms := NCROutSlotNos:@RM
                                    ncrParms := NCRRDSNos:@RM
                                    ncrParms := '':@RM									                    ;* Placeholder for RejWaferIDS - N/A for EpiPro	
                                    ncrParms := NCRSlotNCRs:@RM							
                                    ncrParms := NCRMUWONos:@RM
                                    ncrParms := NCRMUWOSteps:@RM
                                    ncrParms := NCRMUCassIDs:@RM
                                    ncrParms := NCRMUSlotNos:@RM
                                    ncrParms := 'C':@RM                                                     ;* Loss By
                                    ncrParms := 'Wafers removed due to edge defects':@RM                    ;* Containment Actions
                                    ncrParms := 'Edge defects discovered during post-epi inspection':@RM    ;* Loss Comments
                                    ncrParms := '':@RM                                                      ;* AC Comments
                                    ncrParms := '':@RM                                                      ;* Department Responsible
                                    ncrParms := '':@RM                                                      ;* AC Code
                                    ncrParms := 'D63':@RM                                                   ;* Loss Code
                                    ncrParms := 'O':@RM                                                     ;* NCR Status - Open
                                    ncrParms := '':@RM                                                      ;* Shift
                                    ncrParms := '':@RM                                                      ;* Shipment Signature
                                    ncrParms := '':@RM                                                      ;* Reject Signature
                                    ncrParms := '':@RM                                                      ;* Sent to SPC Datetime
                                    ncrParms := '':@RM                                                      ;* Shipment Signature Datetime
                                    ncrParms := 'Production'                                                ;* Department Handled
                                    
                                    Set_Status(0)
                                    NCRNo   = obj_NCR('Create',ncrParms)		;* Create new NCR for this wafer/group of wafers
                                    Msg(@window, MsgUp)         ;* take down the processing message
                                    
                                    ErrCode = ''
                                    If Not(Get_Status(ErrCode)) then
                                        
                                        WMORec = Database_Services('ReadDataRow', 'WM_OUT', WMOKey)
                                        
                                        RejDTM = OCONV(Date(),'D4/'):' ':OCONV(Time(),'MTS')
                                        
                                        RejWfrIDs	= ''
                                        
                                        FOR N = 1 TO COUNT(NCROutSlotNos,@VM) + (NCROutSlotNos NE '')
                                            
                                            * * * *   Added 4/23/2016  JCH - wafer history   * * * * 
                                            
                                            CurrSlotID = WONo:'*':NCROutCassNos<1,N>:'*':NCROutSlotNos<1,N>
                                            
                                            IF NCRMUWONos<1,N> = '' THEN
                                                RejWfrID = WONo:'*':NCRInCassNos<1,N>:'*':NCRInSlotNos<1,N>
                                            END ELSE
                                                RejWfrID = NCRMUWONos<1,N>:'*':NCRMUCassIDs<1,N>:'*':NCRMUSlotNos<1,N>
                                            END
                                            
                                            RejWfrIDs<1,-1> = RejWfrID
                                            
                                            Parms  = RejWfrID:@RM			;* WfrID
                                            Parms := RejDTM:@RM				;* EventDtm
                                            Parms := @USER4:@RM				;* EventBy
                                            Parms := 'NCR':@RM				;* Event
                                            Parms := '':@RM					;* NewSlotID
                                            Parms := '':@RM					;* RunLoc
                                            Parms := NCRNo:@RM				;* NCRNo
                                            Parms := '':@RM					;* TWUse
                                            Parms := CurrSlotID:@RM			;* CurrSlotID
                                            Parms := '':@RM					;* NewToolID
                                            Parms := '':@RM					;* CurrToolID
                                            Parms := '':@RM					;* NewInvLoc
                                            Parms := '':@RM					;* CurrInvLoc
                                            Parms := 'O'					;* Wfr Side
                                            
                                            obj_WO_Wfr('AddEvent',Parms)
                                            
                                            // Add NCR details to WM_OUT record
                                            SlotNo                             = NCROutSlotNos<1,N>
                                            WMORec<WM_OUT_RDS$, SlotNo>        = ''
                                            WMORec<WM_OUT_POCKET$, SlotNo>     = ''
                                            WMORec<WM_OUT_ZONE$, SlotNo>       = ''
                                            WMORec<WM_OUT_IN_CASS_NO$, SlotNo> = ''
                                            WMORec<WM_OUT_IN_SLOT_NO$, SlotNo> = ''
                                            WMORec<WM_OUT_SLOT_NCR$, SlotNo>   = NCRNo
                                            WMORec<WM_OUT_MU_WO_NO$, SlotNo>   = ''
                                            WMORec<WM_OUT_MU_WO_STEP$, SlotNo> = ''
                                            WMORec<WM_OUT_MU_CASS_NO$, SlotNo> = ''
                                            WMORec<WM_OUT_MU_SLOT_NO$, SlotNo> = ''
                                            
                                        NEXT N
                                        
                                        Database_Services('WriteDataRow', 'WM_OUT', WMOKey, WMORec)
                                        
                                        Dialog_Box('NCR', @Window, NCRNo)
                                        
                                    end else
                                        // Bail to force user to contact FI to correct issue.
                                        ErrMsg('Error creating NCR. Error message: ':ErrCode:'. Please contact FI for assistance.')
                                        return
                                    end
                                end else
                                    // User cancelled the hold operation.
                                    ErrMsg('The lot must be placed on hold. Signature operation cancelled.')
                                    return
                                end
                            end else
                                // Bail to force user to contact FI to correct issue.
                                ErrMsg('Error placing lot on hold. Error message: ':ErrCode:'. Please contact FI for assistance.')
                                return
                            end
                        end
                    Until Not(ErrFlag)
                    Repeat
                end
            end
        end
        
        
        IF MemberOf(@USER4, 'OI_SUPERUSER') THEN 
            Valid = 1
        END ELSE	
            Valid = Dialog_Box('NDW_VERIFY_USER', @Window, @User4)
            Valid = Valid<1>
        END
        
        IF Valid = 1 THEN
            
            Def         = ""
            Def<MTEXT$> = "Updating material log and saving clean && inspection record..."
            Def<MTYPE$> = "U"
            MsgUp       = Msg(@window, Def)   ;* display the processing message
            
            CurrDate = OCONV(Date(),'D4/')
            CurrTime = OCONV(Time(),'MTHS')
            CurrDTM  = CurrDate:' ':CurrTime
            Signer   = @USER4
            
            ToolID		= CtrlList<SelectedRow,COL$INSP_TOOL>
            If ToolID EQ 'SCOPE' or ToolID EQ 'SCOPE/FF EDGE INSP' then
                ToolWHCd = 'CR' 
                ToolLoc  = 'QA' 
            end else
                ToolRec  = XLATE('TOOL',ToolID,'','X')
                ToolWHCd = ToolRec<TOOL_TOOL_WH$>
                ToolLoc  = ToolRec<TOOL_TOOL_LOC$>                
            end

            Tag      = ''
            
            IF CassNo NE '' THEN
                
                owmParms = WONo:@RM:CassNo:@RM:WOStep:@RM:SigStage:@RM:Signer:@RM:CurrDTM:@RM:ToolID:@RM:ToolWHCd:@RM:ToolLoc:@RM:Tag		;* Sets PSTI signature
                
                IF Get_Status(errCode) THEN
                    CALL ErrMsg(ErrCode)
                    RETURN 0
                END
                
                LogFile	= 'WO_MAT'			; WOMLParms  = LogFile:@RM
                LogDTM	= CurrDTM			; WOMLParms := LogDTM:@RM
                Action	= SigAction			; WOMLParms := Action:@RM
                WhCd	= ToolWHCd			; WOMLParms := WhCd:@RM
                LocCd	= ToolLoc			; WOMLParms := LocCd:@RM
                WONos	= WONo				; WOMLParms := WONos:@RM
                CassNos	= CassNo			; WOMLParms := CassNos:@RM
                UserID	= @USER4			; WOMLParms := UserID:@RM
                Tags	= ''				; WOMLParms := Tags:@RM
                ToolID	= ToolID			; WOMLParms := ToolID
                
                obj_WO_Mat_Log('Create',WOMLParms)											;* Add WOStep:'PSTI' to WO_MAT Event Log
                
                IF Get_Status(errCode) THEN
                    ErrMsg(errCode)
                END
            END	;* End of check for null Cass No (EpiPro Reactor runs)
            
            Set_Property(CtrlID,'CELLPOS',Signer,COL$INSP_SIG:@FM:SelectedRow)
            Set_Property(CtrlID,'CELLPOS',CurrDTM,COL$INSP_SIG_DTM:@FM:SelectedRow)
            
            CINo = Get_Property(@WINDOW:'.CI_NO','DEFPROP')
            
            Set_Property(@WINDOW,'@DONT_CLOSE',1)
            
            Send_Event(@WINDOW,'WRITE')
            
            Msg(@window, MsgUp)         ;* take down the processing message
            
            obj_AppWindow('LUValReturn',CINo:@RM:@WINDOW:'.CI_NO')
            
        END
        
    END ELSE
        IF SigRow = '' THEN
            ErrMsg('Process Error':@SVM:'Must have some information in selected row to sign.')
            RETURN
        END
        
        IF CtrlList<SelectedRow,COL$INSP_SIG> NE '' THEN
            ErrMsg('Process Error':@SVM:'Row is already signed.')
            RETURN
        END
    END
    
RETURN


* * * * * * *
SignScan:
* * * * * * *
    
    CtrlID = @WINDOW:'.SCAN_RESULTS'
    
    CtrlList = Get_Property(CtrlID,'LIST')
    
    
    SlotSelection	= Get_Property(CtrlID,'SELPOS')
    SelectedRows	= SlotSelection<2>
    
    SlotSelection	= Get_Property(CtrlID,'SELPOS')
    SelectedRow		= SlotSelection<2>
    
    SigRow = CtrlList<SelectedRow>
    
    IF SigRow<1,COL$SCAN_TOOL>  = '' THEN
        ErrMsg('Process Error':@SVM:'Scan Tool column is required.')
        Set_Property(CtrlID,'SELPOS',COL$SCAN_TOOL:@FM:SelectedRow)
        RETURN
    END
    
    
    CONVERT @VM TO '' IN SigRow
    
    ***
    
    Ctrls  = @WINDOW:'.WO_NO':@RM		; Props  = 'DEFPROP':@RM
    Ctrls := @WINDOW:'.WO_STEP':@RM		; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.CASS_NO':@RM		; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.STAGE':@RM		; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.RDS_NO'			; Props := 'DEFPROP'
    
    Vals = Get_Property(Ctrls,Props)
    
    WONo	= Vals[1,@RM]
    WOStep	= Vals[COL2()+1,@RM]
    CassNo	= Vals[COL2()+1,@RM]
    Stage	= Vals[COL2()+1,@RM]
    RDSNo	= Vals[COL2()+1,@RM]
    
    WOLogRow   = Database_Services('ReadDataRow', 'WO_LOG', WONo)
    ReactType  = WOLogRow<WO_LOG_REACT_TYPE$>
    
    IF Stage = 'POST' THEN
        IF RDSNo = '' THEN
            * Epi Pro wafers
            SigAction = WOStep:'MO_PSTS'
            SigStage = 'MO_PSTS'
        END ELSE
            SigAction	= WOStep:'PSTS'
            SigStage	= 'PSTS'
        END
        
    END ELSE
        SigAction	= WOStep:Stage:'S'
        SigStage	= Stage:'S'
    END
    
    IF SigRow NE '' AND CtrlList<SelectedRow,COL$SCAN_SIG> = '' AND CtrlList<SelectedRow,COL$SCAN_SIG_DTM> = '' THEN
        
        If SelectedRow EQ 1 then
            WOMatKey = WONo:'*':CassNo
            Signature_Services('CheckSigOrder', WOMatKey, SigStage, False$, RDSNo)
            If Error_Services('HasError') then
                ErrMsg(Error_Services('GetMessage'))
                return
            end    	    
        end
        
        // Add check for supplement signatures
        ValidStages = Supplement_Services('GetStagesForLot', 'RDS', RDSNo)
        If Count(ValidStages, SigStage) NE 0 then
            UnacknowledgedSupp = Supplement_Services('UnacknowledgedSupplementCheck', 'RDS', RDSNo, SigStage)
            If UnacknowledgedSupp NE FALSE$ then
                Response = Dialog_Box('NDW_RDS_SUPP_SIG', @Window, RDSNo :@FM: SigStage :@FM: FALSE$)
				If Response EQ False$ then return
            end
        End
        
        // This checks to see if manually entered data is authorized to be signed.
        IF (SigRow NE '') AND (CtrlList<SelectedRow,COL$SCAN_TEST_RUN_DTM> = '') AND (Stage NE 'POST') THEN
            Authorized  = MemberOf(@USER4, 'ENGINEERING') OR MemberOf(@USER4, 'LEAD') OR MemberOf(@USER4, 'SUPERVISOR') OR MemberOf(@USER4, 'ROTR_OVERRIDE')
            If Not(Authorized) then
                ErrorText   = 'Only Leads, Supervisors or Engineers can sign ROTR Tencor data manually entered.'
                ErrMsg('Process Error':@SVM:ErrorText)
                Return
            end
        end
        
        IF MemberOf(@USER4, 'OI_SUPERUSER') THEN 
            Valid = 1
        END ELSE
            Valid = Dialog_Box('NDW_VERIFY_USER', @Window, @User4)
            Valid = Valid<1>
        END
        
        IF Valid = 1 THEN
            
            CurrDate = OCONV(Date(),'D4/')
            CurrTime = OCONV(Time(),'MTHS')
            CurrDTM = CurrDate:' ':CurrTime
            Signer = @USER4
            
            ToolID		= CtrlList<SelectedRow,COL$SCAN_TOOL>
            ToolRec 	= XLATE('TOOL',ToolID,'','X')
            ToolWHCd	= ToolRec<TOOL_TOOL_WH$>
            ToolLoc		= ToolRec<TOOL_TOOL_LOC$>
            Tag			= ''
            
            
            // Only call if this is non-EpiPro. - 04/09/2018 - dmb
            If ReactType NE 'EPP' then
                owmParms = WONo:@RM:CassNo:@RM:WOStep:@RM:SigStage:@RM:Signer:@RM:CurrDTM:@RM:ToolID:@RM:ToolWHCd:@RM:ToolLoc:@RM:Tag		;* Sets PSTI signature
                
                IF Get_Status(errCode) THEN
                    CALL ErrMsg(ErrCode)
                    RETURN 0
                END
                
                LogFile	= 'WO_MAT'			; WOMLParms  = LogFile:@RM
                LogDTM	= CurrDTM			; WOMLParms := LogDTM:@RM
                Action	= SigAction			; WOMLParms := Action:@RM
                WhCd	= ToolWHCd			; WOMLParms := WhCd:@RM
                LocCd	= ToolLoc			; WOMLParms := LocCd:@RM
                WONos	= WONo				; WOMLParms := WONos:@RM
                CassNos	= CassNo			; WOMLParms := CassNos:@RM
                UserID	= @USER4			; WOMLParms := UserID:@RM
                Tags	= ''				; WOMLParms := Tags:@RM
                ToolID	= ToolID			; WOMLParms := ToolID
                
                obj_WO_Mat_Log('Create',WOMLParms)											;* Sets PSTI in WO_MAT Event Log
                
                IF Get_Status(errCode) THEN
                    ErrMsg(errCode)
                    
                END
            end		
            
            Set_Property(CtrlID,'CELLPOS',Signer,COL$SCAN_SIG:@FM:SelectedRow)
            Set_Property(CtrlID,'CELLPOS',CurrDTM,COL$SCAN_SIG_DTM:@FM:SelectedRow)
            
            
            CINo = Get_Property(@WINDOW:'.CI_NO','DEFPROP')
            
            Set_Property(@WINDOW,'@DONT_CLOSE',1)
            
            Send_Event(@WINDOW,'WRITE')
            
            obj_AppWindow('LUValReturn',CINo:@RM:@WINDOW:'.CI_NO')
        END
        
    END ELSE
        IF SigRow = '' THEN
            ErrMsg('Process Error':@SVM:'Must have some information in selected row to sign.')
            RETURN
        END
        
        IF CtrlList<SelectedRow,COL$SCAN_SIG> NE '' OR CtrlList<SelectedRow,COL$SCAN_SIG_DTM> NE '' THEN
            ErrMsg('Process Error':@SVM:'Row is already signed.')
            RETURN
        END
        
    END
    
RETURN


SIGN_ROTR_ACCEPTANCE.CLICK:
    
    Valid = Dialog_Box('NDW_VERIFY_USER', @Window, @User4)
    Valid = Valid<1>
    If Valid EQ True$ then
        OrigReason  = Get_Property(@Window : '.SIGN_ROTR_REASON', 'DEFPROP')
        Reason      = Msg(@Window, '', 'MESSAGE_INPUT', '', 'ROTR Acceptance' : @FM : 'ROTR Acceptance Reason' : @FM : OrigReason)
        If Reason NE '' then
            Set_Property(@Window : '.SIGN_ROTR_SIGNATURE', 'INVALUE', @USER4)
            Set_Property(@Window : '.SIGN_ROTR_DATE_TIME', 'DEFPROP', Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTHS'))
            Set_Property(@Window : '.SIGN_ROTR_REASON', 'DEFPROP', Reason)
            Send_Event(@Window : '.SIGN_ROTR_SIGNATURE_NAME', 'CALCULATE')
        end
    end
    
return


SCAN_RESULTS.CHAR:
    
    Stage = Get_Property(@Window : '.STAGE', 'TEXT')
    If Stage EQ 'LWI' then
        CtrlEntID   = 'SCAN_RESULTS'
        CIKey       = Get_Property(@Window : '.CI_NO', 'TEXT')
        ReactorNo   = Xlate('CLEAN_INSP', CIKey, 'REACT_NO', 'X')
        CanEdit = Get_Property(@Window, '@CAN_EDIT')    
        If Not(CanEdit) then
            PrevFocusID = Get_Property (@Window, "PREVFOCUS")
            Message = 'Only a member of lead, supervisor, final_qa,':@SVM:'engineering, or rotr_override can manually enter data.'
            Response = Msg(@Window, '', 'OVERRIDE', '', Message)
            
            Begin Case
                Case Response EQ 1
                    Response = True$        ; // User Clicked Override
                Case Response EQ 2
                    Response = False$       ; // User Clicked Cancel
                Case Response EQ char(27)
                    Response = False$       ; // User Pressed Escape Key
            End Case            
            
            If Response EQ True$ then
                OverrideGroups  = 'LEAD' : @VM : 'SUPERVISOR' : @VM : 'ENGINEERING' :@VM: 'FINAL_QA' :@VM: 'ROTR_OVERRIDE'
                Response        = Dialog_Box('NDW_VERIFY_USER', @WINDOW, @USER4 : @FM : OverrideGroups)
                Valid           = Response<1>
                Username        = Response<2>
                If NOT(Valid) then
                    Set_Property(@Window, 'FOCUS', PrevFocusID)
                    Set_Property(CtrlEntID, 'SELPOS', -1:@FM:-1)             
                end else
                    Set_Property(@Window, '@CAN_EDIT', True$)
                    CanEdit = True$
                end
            end else
                Set_Property(@Window, 'FOCUS', PrevFocusID)
                Set_Property(CtrlEntID, 'SELPOS', -1:@FM:-1) 
            end
        end
        
        If (CanEdit EQ True$) then
            // Enable manual entry of data.
            ScanStyles	= Send_Message(@Window : '.SCAN_RESULTS', 'COLSTYLE', 0, '')
            For column = 1 to 7
                ScanStyles<column> = BitAnd( ScanStyles<column>, BitNot(PROTECTED$) )
            Next column
            // Enable dropdown menus for recipe and tool columns.
            ScanStyles<COL$SCAN_RECIPE>		= BitOr(ScanStyles<COL$SCAN_RECIPE>, DTCS_DROPDOWN$ )
            ScanStyles<COL$SCAN_TOOL>		= BitOr(ScanStyles<COL$SCAN_TOOL>, DTCS_DROPDOWN$ )
            ScanStyles	= Send_Message(@Window : '.SCAN_RESULTS', 'COLSTYLE', 0, ScanStyles)
        end
    end
    ****************Logging Manual Data Entry********************
    TableContents = Get_Property(@Window:'.SCAN_RESULTS', 'ARRAY')
    ToolID = TableContents<COL$SCAN_TOOL, 1>
    IF ToolID NE '' then
        Date        = SRP_DateTime('Now')
        EpochStart  = 00732
        EpochTime   = SRP_DateTime('SecondSpan',EpochStart, Date)
        RDSNo       = Get_Property(@Window:'.RDS_NO', 'DEFPROP')
        PSNo        = Get_Property(@Window:'.PS_NO', 'DEFPROP')
        User        = @User4
        Description = 'Manual SurfScan Data Entry detected for RDS #: ':RDSNo
        Reactor     = XLATE('RDS', RDSNo, 2, 'X')
        
        FileName = Environment_Services('GetApplicationRootPath'): '\LogFiles\ManualDataEntry\PollPath\' : EpochTime :'.json'
        
        OSWrite '' to FileName
        JSON = '{"Equipment":"':ToolID:'", "Reactor":"':Reactor:'", "PSN":"':PSNo:'", "RDS":"':RDSNo:'", "User": "':User:'", "Description":"':Description:'"}'
        
        OSWrite JSON to FileName
    end
    
return


SCAN_RESULTS.POSCHANGED:
    
    ScanCtrl = @Window : '.SCAN_RESULTS'
    ScanCtrlList = Get_Property(ScanCtrl, 'LIST')
    SelPos       = Get_Property(ScanCtrl, 'SELPOS')
    RowPos       = SelPos<2>
    TestDTM      = ScanCtrlList<RowPos,COL$SCAN_TEST_RUN_DTM>
    If TestDTM EQ '' then
        Set_Property(@Window:'.BTN_WAFER_DETAILS', 'ENABLED', False$)
    end else
        Set_Property(@Window:'.BTN_WAFER_DETAILS', 'ENABLED', True$)
    end
    
return


BTN_WAFER_DETAILS.CLICK:
    
    PrevCursor   = Set_Property('SYSTEM', 'CURSOR', 'H')
    Yield()
    CleanInspKey = Get_Property(@Window : '.CI_NO', 'TEXT')
    SelPos       = Get_Property(@Window : '.SCAN_RESULTS', 'SELPOS')
    RowPos       = SelPos<2>
    If RowPos EQ '' then RowPos = 1
    CreateParam  = CleanInspKey : @FM : RowPos
    WindowName   = Create_Dialog('NDW_ROTR_WAFER_DETAILS', @Window, True$, CreateParam)
    PrevCursor   = Set_Property('SYSTEM', 'CURSOR', PrevCursor)
    
return


* * * * * * *
RefreshSpec:
* * * * * * *
    
    CINo = Get_Property(@WINDOW:'.CI_NO','TEXT')
    
    PSStageKey = Get_Property(@WINDOW:'.PS_STAGE_KEY','TEXT')
    
    IF CINo NE '' AND PSStageKey NE '' THEN
        Send_Event(@WINDOW,'WRITE')
        obj_Clean_Insp('SpecDelta',CINo:@RM:PSStageKey)
        IF Get_Status(errCode) THEN
            ErrMsg(errCode)
        END
        
        obj_Appwindow('LUValReturn',CINo:@RM:@WINDOW:'.CI_NO')
        
    END
    
RETURN


* * * * * * *
InspPC:
* * * * * * *
    
    CurrInspPos		= Get_Property(@WINDOW:'.INSP_RESULTS','SELPOS')
    CurrBSInspPos	= Get_Property(@WINDOW:'.INSP_RESULTS_BSIDE','SELPOS')
    
    CurrInspCol = CurrInspPos<1>
    CurrInspRow = CurrInspPos<2>
    
    CurrBSInspCol	= CurrBSInspPos<1>
    CurrBSInspRow	= CurrBSInspPos<2>
    
    Set_Property(@WINDOW:'.INSP_RESULTS_BSIDE','SELPOS',CurrBSInspCol:@FM:CurrInspRow)
    
    GOSUB Refresh
    
RETURN


* * * * * * *
BSideInspPC:
* * * * * * *
    
    CurrInspPos		= Get_Property(@WINDOW:'.INSP_RESULTS','SELPOS')
    CurrBSInspPos	= Get_Property(@WINDOW:'.INSP_RESULTS_BSIDE','SELPOS')
    
    CurrInspCol = CurrInspPos<1>
    CurrInspRow = CurrInspPos<2>
    
    CurrBSInspCol	= CurrBSInspPos<1>
    CurrBSInspRow	= CurrBSInspPos<2>
    
    Set_Property(@WINDOW:'.INSP_RESULTS','SELPOS',CurrInspCol:@FM:CurrBSInspRow)
    
    GOSUB Refresh
    
RETURN


* * * * * * *
SendSPC:
* * * * * * *
    
    Ctrls  = @WINDOW:'.RDS_NO':@RM			; Props  = 'DEFPROP':@RM
    Ctrls := @WINDOW:'.STAGE':@RM			; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.SS_SCAN_TOOL':@RM	; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.SUM_OF_DEF_MIN':@RM	; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.SUM_OF_DEF_MAX':@RM	; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.SUM_OF_DEF_AVG':@RM	; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.HAZE_AVG_AVG':@RM	; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.SPOTS':@RM			; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.FOV':@RM				; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.SCRATCHES':@RM		; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.SCRATCH_LEN':@RM		; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.REACT_NO':@RM		; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.WAFER_SIZE':@RM		; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.SS_SCRATCH_MAX':@RM	; Props := 'DEFPROP':@RM
    Ctrls := @WINDOW:'.SS_SCRATCH_AVG'		; Props := 'DEFPROP'
    
    Vals = Get_Property(Ctrls,Props)
    
    RDSNo			= Vals[1,@RM]
    Stage			= Vals[COL2()+1,@RM]
    ScanTool		= Vals[COL2()+1,@RM]
    SumOfDefMin		= Vals[COL2()+1,@RM]
    SumOfDefMax		= Vals[COL2()+1,@RM]
    SumOfDefAvg		= Vals[COL2()+1,@RM]
    HazeAvgAvg		= Vals[COL2()+1,@RM]
    Spots			= Vals[COL2()+1,@RM]
    FOV				= Vals[COL2()+1,@RM]
    Scratches		= Vals[COL2()+1,@RM]
    ScratchLen		= Vals[COL2()+1,@RM]
    ReactNo			= Vals[COL2()+1,@RM]
    WaferSize		= Vals[COL2()+1,@RM]
    SSScratchMax	= Vals[COL2()+1,@RM]
    SSScratchAvg	= Vals[COL2()+1,@RM]
    
    
    WaferSize = WaferSize[1,' ']		;* Data looks like "125 mm 6 in"
    
    UserName = OCONV(@USER4,'[XLATE_CONV,LSL_USERS*FIRST_LAST]')
    
    DataLine  = QUOTE(ReactNo):TAB$
    DataLine := QUOTE(RDSNo):TAB$
    DataLine := QUOTE(Stage):TAB$
    DataLine := QUOTE(ScanTool):TAB$
    DataLine := QUOTE(SumOfDefMin):TAB$
    DataLine := QUOTE(SumOfDefMax):TAB$
    DataLine := QUOTE(SumOfDefAvg):TAB$
    DataLine := QUOTE(HazeAvgAvg):TAB$
    DataLine := QUOTE(Spots):TAB$
    DataLine := QUOTE(FOV):TAB$
    DataLine := QUOTE(Scratches):TAB$
    DataLine := QUOTE(ScratchLen):TAB$
    DataLine := QUOTE(UserName):TAB$
    DataLine := QUOTE(SSScratchAvg):TAB$
    DataLine := QUOTE(SSScratchMax):TAB$
    DataLine := QUOTE(WaferSize)
    
    DOSFile = Environment_Services('GetSPCDataPath') : '\SPC_Surf.txt'
    
* * * * * * *
DosRead:
* * * * * * *
    
    // SPC Server has been migrated to the EC domain. SPC Queue must be utilized to transfer SPC files.
    Filename    = 'SPC_Surf.txt'
    SPCQueueKey = Date():'*':Time():'*':@USER4
    SPCQueueRec = ''
    SPCQueueRec<SPC_QUEUE.SPC_FILENAME$> = Filename
    SPCQueueRec<SPC_QUEUE.SPC_DOC$>      = DataLine:CRLF$
    Database_Services('WriteDataRow', 'SPC_QUEUE', SPCQueueKey, SPCQueueRec, True$, False$, False$)
    
    CurrDTM = OCONV(Date(),'D4/'):' ':OCONV(Time(),'MTS')
    
    Set_Property(@WINDOW:'.SPC_DTM','DEFPROP',CurrDTM)
    
RETURN 


* * * * * * *
SetGroupBackground:
* * * * * * *

