Compile function DBW_PROD_SPEC_GAN_EVENTS(CtrlEntId, Event, @PARAMS)
/***********************************************************************************************************************

    Name        :   DBW_PROD_SPEC_GAN_EVENTS

    Description :   Commuter module for the DBW_PROD_SPEC_GAN form.

    Notes       :   Application errors should be logged using the Error Services module. There are a few methodological
                    assumptions built into way errors are managed which are important to understand in order to properly
                    work with Error Services:

                    - The term 'top' refers to the originating procedure of a call stack and the term 'bottom' refers to
                      the last routine (or the current routine) within a call stack. Within the OpenInsight Debugger
                      this will appear backwards since the originating procedure always appears at the bottom of the
                      list and the current routine appears at the top of the list. We are using this orientation because
                      it is common to refer to the process of calling other procedures as 'drilling down'.

                    - The reason for defining the orientation of the call stack is because Error_Services allows for
                      multiple error conditions to be appended to an original error. In most cases this will happen when
                      a procedure at the bottom of the stack generates an error condition and then returns to its
                      calling procedure. This higher level procedure can optionally add more information relevant to
                      itself. This continues as the call stack 'bubbles' its way back to the top to where the
                      originating procedure is waiting.

                    - Native OpenInsight commands that handle errors (e.g., Set_Status, Set_FSError, Set_EventStatus)
                      preserve their error state until explicitly cleared. This can hinder the normal execution of code
                      since subsequent procedures (usually SSPs) will fail if a pre-existing error condition exists.
                      Our philosophy is that error conditions should automatically be cleared before a new procedure
                      is executed to avoid this problem. However, the nature of Basic+ does not make this easy to
                      automate for any given stored procedure. Therefore, if a stored procedure wants to conform to our
                      philosophy then it should include a call into the 'Clear' service request at the top of the
                      program. Alternatively this can be done through a common insert (see SERVICE_SETUP for example.)

                    - Service modules will use the SERVICE_SETUP insert and therefore automatically clear out any
                      error conditions that were set before.

    Parameters  :
        Service         [in] -- Name of the service being requested
        Param1-10   [in/out] -- Additional request parameter holders
        Response       [out] -- Response to be sent back to the Controller (MCP) or requesting procedure

    Metadata    :

    History     :   (Date, Initials, Notes)
        06/06/20    djs     Cutover to CR-004 and CR-005

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

#pragma precomp SRP_PreCompiler
#window DBW_PROD_SPEC_GAN

$INSERT APP_INSERTS
$INSERT QUOTE_SPEC_EQU
$INSERT LSL_COMMON
$INSERT PS_EQUATES
$INSERT MSG_EQUATES
$INSERT SECURITY_RIGHTS_EQU
$INSERT RDS_EQU
$INSERT REACT_RUN_EQUATES
$INSERT GAN_PARAMS_EQUATES
$INSERT PROD_SPEC_EQUATES
$INSERT GAN_PARAM_CONFIG_EQUATES
$INSERT PRS_STAGE_EQUATES
$INSERT PROD_SPEC_REV_HIST_EQUATES

EQU COL$MODE_CODE		TO 1
EQU COL$MODE_SIG		TO 2
EQU COL$MODE_SIG_DTM	TO 3

EQU    TOP$ROW to 9
EQU BOTTOM$ROW to 21

Declare subroutine Set_Property, Database_Services, Dialog_Box, ErrMsg, GaN_Services, Unlock, SQL_Services
Declare subroutine Start_Window, Comm_Prod_Spec, Create_Dialog, PSN_Services
Declare function   Get_Property, Form_Services, Database_Services, Datetime, SQL_Services, SRP_Array, GaN_Services
Declare function   NextKey, SQL_Services

SubclassInfo    = Form_Services('FindSubclassControl')
Subclass        = SubclassInfo<1>

If Assigned(Param8) else Param8 = ''

// Update the arguments so that the OpenInsight OLE event will treate the ActiveX event as a native event handler.
If Event EQ 'OLE' then
    Transfer Event to OIEvent
    Transfer Param1 to Event
    Transfer Param2 to Param1
    Transfer Param3 to Param2
    Transfer Param4 to Param3
    Transfer Param5 to Param4
    Transfer Param6 to Param5
    Transfer Param7 to Param6
    Transfer Param8 to Param7
end

// Convert ' ' to '_' for proper RADIO control event handling
Convert ' ' to '_' in CtrlEntId

GoToEvent Event for CtrlEntId else
    
    If Event EQ 'CHANGED' then
        GoSub EnableSaveButton
    end
    If Event EQ 'UpdateRevHist' then
        GoSub UpdateRevHist
    end
    Ctrl = CtrlEntID[-1, 'B.']
    If ( (Ctrl[1, 8] EQ 'CHK_WFR_') or (Ctrl[1, 9] EQ 'CHK_CHAR_') ) then
        GoSub UpdateANKOGroups
        GoSub EnableSaveButton
    end
end

Return EventFlow or 1

//-----------------------------------------------------------------------------
// EVENT HANDLERS
//-----------------------------------------------------------------------------

Event WINDOW.CREATE(CreateParam)
    
    SiliconFormVisible = Get_Property('PROD_SPEC', 'VISIBLE')
    If SiliconFormVisible EQ True$ then
        Utility('DESTROY', 'PROD_SPEC')
    end
    // Do not clear on write
    IOOptions = Get_Property(@Window, "IOOPTIONS")
    IOOptions<6> = True$
    Set_Property(@Window, 'IOOPTIONS', IOOptions)

    SRP_Show_Window(@Window, 'SYSTEM', 'C', 'C', 1, '', False$, False$, '', 1)
    
    PSNo = CreateParam
    If RowExists('PROD_SPEC', PSNo) then
        Set_Property(@Window:'.PROD_SPEC_ID', 'TEXT', PSNo)
        Post_Event(@Window, 'READ')
    end
    
End Event


Event WINDOW.READ()

    PSNo      = Get_Property(@Window:'.PROD_SPEC_ID', 'TEXT')
    NewPSN    = ( RowExists('PROD_SPEC', PSNo) EQ False$ )
    Set_Property(@Window, '@NEW_PSN', NewPSN)
    ReactType = Xlate('PROD_SPEC', PSNo, 'REACTOR_TYPE', 'X')
    
    If ( (ReactType EQ 'GAN') or (NewPSN EQ True$) ) then

        If NewPSN EQ True$ then
            Set_Property(@Window:'.STATUS', 'DEFPROP', 'I')
            PSN_Services('InitializeCritParams', PSNo)
        end else
            Comm_Prod_Spec('Refresh')
        end
        Set_Property(@Window, 'REDRAW', False$)
        GoSub SetupOLEControls   
        CharInterval = Get_Property(@Window:'.EDL_CHAR_INTERVAL', 'TEXT')
        CharInterval = Trim(CharInterval)
        If Num(CharInterval) then
            If ( (CharInterval NE '') and (CharInterval GE 1) ) then
                CurrInterval   = 1
                IntervalString = 1
                For Interval = 1 to 3
                    IntervalString := ',':(CurrInterval + CharInterval)
                    CurrInterval += CharInterval
                Next Interval
                IntervalString := '...'
                Set_Property(@Window:'.LBL_INTERVAL', 'TEXT', IntervalString)
            end else
                Set_Property(@Window:'.LBL_INTERVAL', 'TEXT', 'None')
            end
        end else
            Set_Property(@Window:'.LBL_INTERVAL', 'TEXT', 'None')
        end
        Set_Property(@Window, 'REDRAW', True$)
        
        GoSub FillRevHistEDT
        
        OrigRecord = Get_Property(@Window, 'ATRECORD')
        Set_Property(@Window, '@ORIG_RECORD', OrigRecord)
        
    end else

        RecLocked = Database_Services('IsKeyIDLocked', 'PROD_SPEC', PSNo)
        If RecLocked then Database_Services('ReleaseKeyIDLock', 'PROD_SPEC', PSNo)
        ParentWindow = Get_Property(@Window, "PARENT")
        Start_Window('PROD_SPEC', ParentWindow, PSNo)
        
    end
    
end event


Event WINDOW.WRITE()

    PSNo       = Get_Property(@Window:'.PROD_SPEC_ID', 'TEXT')
    OrigRecord = Get_Property(@Window, 'ATRECORD')
    Set_Property(@Window, '@ORIG_RECORD', OrigRecord)
    
    NewPSN = Get_Property(@Window, '@NEW_PSN')
    If NewPSN EQ True$ then
        // Mark PSN type as GaN
        PSRec = Database_Services('ReadDataRow', 'PROD_SPEC', PSNo)
        PSRec<PROD_SPEC_REACTOR_TYPE$> = 'GAN'
        PSRec<PROD_SPEC_MODE_CODE$> = 'Q':@VM:'P'
        Database_Services('WriteDataRow', 'PROD_SPEC', PSNo, PSRec, True$, False$, True$)
        // Create PRS_STAGE records and add PRS_STAGE keys to the new PROD_SPEC record
        ReqStages = Gan_Services('GetReqStages')
        For each StageID in ReqStages using @VM
            Gan_Services('AddStageToPSN', PSNo, StageID)
        Next StageID
        Set_Property(@Window, '@NEW_PSN', False$)        
    end
     
    GoSub SaveAll
    
    // If PSN reactor type is "GAN", the tech type is "Production" (i.e. 'P'), and the status is "Active" (i.e. 'A'),
    // then ensure Candela Total Defects parameter is enabled in the GAN_PARAM_CONFIG record. Otherwise, force the
    // status to "Inactive" (i.e. 'I').
    Database_Services('ActivateRecord', 'PROD_SPEC', PSNo)
    If ( ({REACTOR_TYPE} EQ 'GAN') and ({TECH_TYPE} EQ 'P') and ({STATUS} EQ 'A') and ({CURR_PART_NO} NE '') ) then
        ReadyToActivate = False$
        // Need to ensure Candela Total Defects is enabled.
        GaNParamKeys    = {GAN_PARAM_KEYS}
        CanPreKey       = ''
        For each ParamKey in GaNParamKeys using @VM setting vPos
            Stage = Field(ParamKey, '*', 2)
            If Stage EQ 'CAN_PRE' then CanPreKey = ParamKey
        Until CanPreKey NE ''
        Next ParamKey
        If CanPreKey NE '' then
            CanPreParamRec = Database_Services('ReadDataRow', 'GAN_PARAMS', CanPreKey)
            If Error_Services('NoError') then
                MetNames = CanPreParamRec<GAN_PARAMS.MET_NAME$>
                Locate 'Candela Total Defects' in MetNames using @VM setting vPos then
                    ReadyToActivate = True$ 
                end else
                    ErrorMsg = 'Candela Total Defects not found in the Part & Parameters configuration record. PSN not eligible to be activated.'
                    ErrMsg(ErrorMsg)
                end
            end else
                ErrorMsg = 'Error reading CAN_PRE parameter configuration record. PSN not eligible to be activated.'
                ErrMsg(ErrorMsg)
            end
        end else
            ErrorMsg = 'CAN_PRE parameter record not found.'
            ErrMsg(ErrorMsg)
        end

        If ReadyToActivate EQ False$ then
            ErrMessage  = 'Candela Total Defects is required in order for the PSN to be active. Enable Candela '
            ErrMessage := 'Total Defects in the Part & Parameter manager in order to activate this PSN.'
            ErrMsg(ErrMessage)
            {STATUS} = 'I'
            Database_Services('WriteDataRow', 'PROD_SPEC', PSNo, @Record, True$, False$, True$)
        end
    end
    Post_Event(@Window, 'READ')
    
end event


Event CHK_ANKO.CLICK()
    
    GoSub EnableANKOGroups
    GoSub EnableSaveButton
    
end event


Event PUB_DUP_PSN.CLICK()

    PSNo       = Get_Property(@Window:'.PROD_SPEC_ID', 'TEXT')
    OrigRecord = Get_Property(@Window, 'ATRECORD')
    Set_Property(@Window, '@ORIG_RECORD', OrigRecord)
    NewRecord = OrigRecord
    // Clear GaN Param related columns as these are part number specific and the new PSN will not have
    // a part number associated with it until a PROD_VER record is created and associated with it.
    NewRecord<PROD_SPEC_GAN_PARAM_KEYS$> = ''
    NewRecord<PROD_SPEC_GAN_REV_CP_DTM$> = ''
    NewRecord<PROD_SPEC_GAN_REV_OI_DTM$> = ''
    NewRecord<PROD_SPEC_GAN_REV_USER$>   = ''
    NewKey    = NextKey('PROD_SPEC')
    Set_Property(@Window:'.PROD_SPEC_ID', 'TEXT', NewKey)
    Swap PSNo with NewKey in NewRecord
    NewRecord<PROD_SPEC_REACTOR_TYPE$> = 'GAN'
    NewRecord<PROD_SPEC_MODE_CODE$> = 'Q':@VM:'P'
    Database_Services('WriteDataRow', 'PROD_SPEC', NewKey, NewRecord, True$, False$, True$)
    // Create PRS_STAGE records and add PRS_STAGE keys to the new PROD_SPEC record
    ReqStages = Gan_Services('GetReqStages')
    For each StageID in ReqStages using @VM
        Gan_Services('AddStageToPSN', NewKey, StageID)
    Next StageID
    
    Set_Property(@Window, '@NEW_PSN', False$)        
     
    GoSub SaveAll
    Post_Event(@Window, 'READ')
    
end event


Event EDL_CHAR_INTERVAL.CHANGED(NewData)
    
    CharInterval = NewData
    CharInterval = Trim(CharInterval)
    If Num(CharInterval) then
        If ( (CharInterval NE '') and (CharInterval GE 1) ) then
            CurrInterval   = 1
            IntervalString = 1
            For Interval = 1 to 3
                IntervalString := ',':(CurrInterval + CharInterval)
                CurrInterval += CharInterval
            Next Interval
            IntervalString := '...'
            Set_Property(@Window:'.LBL_INTERVAL', 'TEXT', IntervalString)
        end else
            Set_Property(@Window:'.LBL_INTERVAL', 'TEXT', 'None')
        end
    end else
        Set_Property(@Window:'.LBL_INTERVAL', 'TEXT', 'None')
    end
    
    GoSub EnableSaveButton
        
end event


Event WINDOW.CLOSE(CancelFlag)

    Set_Property(@Window:'.OLE_TAB', "OLE.FlickerFree", False$)
    
end event


Event WINDOW.OMNIEVENT(Message, Param1, Param2, Param3, Param4)    

    If Message _EQC 'EnableImportButton' then        
        GoSub EnableImportButton
    end
    
end event


Event EXPORT_CONTROL.CLICK()
    
    GoSub EnableSaveButton
    
end event


Event STATUS.ACTIVE.CLICK()
    
    GoSub StatusClick
    GoSub EnableSaveButton
    
end event


Event STATUS.INACTIVE.CLICK()
    
    GoSub StatusClick
    GoSub EnableSaveButton
    
end event


Event STATUS.HOLD.CLICK()
    
    GoSub StatusClick
    GoSub EnableSaveButton
    
end event


Event RDO_TECH_TYPE.PRODUCTION.CLICK()
    
    GoSub EnableANKOGroups
    GoSub EnableAnkoCheckbox
    GoSub EnableSaveButton
    
end event


Event RDO_TECH_TYPE.ENGINEERING.CLICK()
    
    GoSub EnableANKOGroups
    GoSub EnableAnkoCheckbox
    GoSub EnableSaveButton
    
end event


Event PUB_PARAM_MANAGER.CLICK()

    PSNo = Get_Property(@Window:'.PROD_SPEC_ID', 'TEXT')
    Create_Dialog('NDW_GAN_PARAM_MANAGER', @Window, True$, PSNo)
    
end event


Event PUB_IMPORT_CP.CLICK()

    GoSub UpdateLimits
    GoSub HideTabs
    GoSub FillPartParamCtrl
    GoSub ColorTabs  
    GoSub EnableSaveButton
    
end event


Event PUB_SAVE.CLICK()

    Send_Event(@Window, 'WRITE')

end event


Event OLE_TAB.SelChanged(Index, PrevIndex)
    
    GoSub FillPartParamCtrl
    
end event


Event OLE_CHAR_STAGE_EDT.OnCheckChanged(Cell, OldValue, NewValue)

    Abort = False$
    If NewValue = False$ then
        Row     = Field(Cell, ';', 2)
        Col     = Field(Cell, ';', 1)
        StageID = Get_Property(CtrlEntID, 'OLE.CellText[1;':Row:']')
        PSNo    = Get_Property(@Window:'.PROD_SPEC_ID', 'TEXT')
        GaNParamKeys = Xlate('PROD_SPEC', PSNo, 'GAN_PARAM_KEYS', 'X')   
        GaNParamKeysPrime = SRP_Array('Rotate', GaNParamKeys, @VM, '*')
        GaNCritStages = GaNParamKeysPrime<1, 2>
        
        // Check if the StageID unchecked is configured in part parameters. 
        // If it is, then block the change and warn the user. 
        Locate StageID in GaNCritStages using '*' setting Dummy then
            Message  = 'This stage is configured as a critical stage. '
            Message := 'You must remove the parameters using the Parameter Manager before you can remove this stage.'
            ErrMsg(Message)
            Abort = True$
            Set_Property(CtrlEntID, 'OLE.CellCheck[':Cell:']', True$)
        end
    end

    If Abort EQ False$ then
        StageEnabledArray = Get_Property(CtrlEntID, 'OLE.CellCheck[3;All]')
        Convert @RM to @VM in StageEnabledArray
        Set_Property(@Window, '@STAGE_ENABLED_LIST', StageEnabledArray)
        GoSub EnableSaveButton
    end
     
end event


Event OLE_CHAR_STAGE_EDT.PosChanged(Cell, PrevCell, Button, RepeatCount)

    Focus          = Get_Property(CtrlEntID, 'OLE.Focus')
    StageOrderList = Get_Property(CtrlEntID, 'OLE.ColumnData[1]')
    Set_Property(@Window, '@STAGE_ORDER_LIST', StageOrderList)
    GoSub EnableArrowButtons
    
end event


Event TAB_MAIN.CLICK()
    
    TabIndex = Get_Property(@WINDOW:'.TAB_MAIN', 'VALUE')   
    Set_Property(@WINDOW, 'VPOSITION', TabIndex)
    
end event


Event PUB_TOP_ARROW.CLICK()
    
    StageEDTCtrl  = @Window:'.OLE_CHAR_STAGE_EDT'
    StageList     = Get_Property(StageEDTCtrl, 'OLE.LIST')
    SelList       = Get_Property(StageEDTCtrl, 'OLE.SelPos')
    SelRowIndex   = SelList<2, 1>
    SelRow        = StageList<SelRowIndex>
    StageList     = Delete(StageList, SelRowIndex, 0 ,0)
    StageList     = Insert(StageList, TOP$ROW, 0, 0, SelRow)
    Set_Property(StageEDTCtrl, 'LIST', StageList)
    SelList<2, 1> = TOP$ROW
    Set_Property(StageEDTCtrl, 'OLE.SelPos', SelList)
    GoSub EnableArrowButtons
    Set_Property(StageEDTCtrl, 'OLE.Focus', True$)
    GoSub ColorCharStages
    GoSub UpdateCharStageOrder
    GoSub EnableSaveButton
       
end event


Event PUB_UP_ARROW.CLICK()
    
    StageEDTCtrl  = @Window:'.OLE_CHAR_STAGE_EDT'
    StageList     = Get_Property(StageEDTCtrl, 'OLE.LIST')
    SelList       = Get_Property(StageEDTCtrl, 'OLE.SelPos')
    SelRowIndex   = SelList<2, 1>
    NewRowIndex   = SelRowIndex - 1  
    SelRow        = StageList<SelRowIndex>
    StageList     = Delete(StageList, SelRowIndex, 0 ,0)
    StageList     = Insert(StageList, NewRowIndex, 0, 0, SelRow)
    Set_Property(StageEDTCtrl, 'LIST', StageList)
    SelList<2, 1> = NewRowIndex
    Set_Property(StageEDTCtrl, 'OLE.SelPos', SelList)
    GoSub EnableArrowButtons
    Set_Property(StageEDTCtrl, 'OLE.Focus', True$)
    GoSub ColorCharStages
    GoSub UpdateCharStageOrder
    GoSub EnableSaveButton
        
end event


Event PUB_DOWN_ARROW.CLICK()
    
    StageEDTCtrl  = @Window:'.OLE_CHAR_STAGE_EDT'
    StageList     = Get_Property(StageEDTCtrl, 'OLE.LIST')
    SelList       = Get_Property(StageEDTCtrl, 'OLE.SelPos')
    SelRowIndex   = SelList<2, 1>
    NewRowIndex   = SelRowIndex + 1
    SelRow        = StageList<SelRowIndex>
    StageList     = Delete(StageList, SelRowIndex, 0 ,0)
    StageList     = Insert(StageList, NewRowIndex, 0, 0, SelRow)
    Set_Property(StageEDTCtrl, 'LIST', StageList)
    SelList<2, 1> = NewRowIndex
    Set_Property(StageEDTCtrl, 'OLE.SelPos', SelList)
    GoSub EnableArrowButtons
    Set_Property(StageEDTCtrl, 'OLE.Focus', 1)
    GoSub ColorCharStages
    GoSub UpdateCharStageOrder
    GoSub EnableSaveButton
        
end event


Event PUB_BOTTOM_ARROW.CLICK()
    
    StageEDTCtrl   = @Window:'.OLE_CHAR_STAGE_EDT'
    StageList      = Get_Property(StageEDTCtrl, 'OLE.LIST')
    SelList        = Get_Property(StageEDTCtrl, 'OLE.SelPos')
    SelRowIndex    = SelList<2, 1>
    SelRow         = StageList<SelRowIndex>
    StageList      = Delete(StageList, SelRowIndex, 0 ,0)
    StageList      = Insert(StageList, BOTTOM$ROW, 0, 0, SelRow)
    Set_Property(StageEDTCtrl, 'LIST', StageList)  
    // Return focus to the new row index.
    SelList<2, 1>  = BOTTOM$ROW
    Set_Property(StageEDTCtrl, 'OLE.SelPos', SelList)
    GoSub EnableArrowButtons
    Set_Property(StageEDTCtrl, 'OLE.Focus', 1)
    GoSub ColorCharStages
    GoSub UpdateCharStageOrder
    GoSub EnableSaveButton
    
end event


Event RDO_WAFER_SELECTION.PRESET_WAFER.CLICK()

    ANKOWaferSel = Get_Property(@Window:'.RDO_WAFER_SELECTION', 'VALUE')
    Set_Property(@Window, '@ANKO_WAFER_SELECTION', ANKOWaferSel)
    GoSub EnableSaveButton
    GoSub EnableANKOGroups
    
end event


Event RDO_WAFER_SELECTION.CANDELA_TOTAL_DEFECTS.CLICK()

    ANKOWaferSel = Get_Property(@Window:'.RDO_WAFER_SELECTION', 'VALUE')
    Set_Property(@Window, '@ANKO_WAFER_SELECTION', ANKOWaferSel)
    GoSub EnableANKOGroups
    GoSub EnableSaveButton
    
end event


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


SetupOLEControls:

    GoSub SetupTabCtrl
    GoSub SetupPartParamCtrl
    GoSub ReadCurrParams
    GoSub FillPartParamCtrl
    GoSub ColorTabs
    GoSub HideTabs
    GoSub EnableImportButton
    GoSub DisplayTimestamps
    GoSub SetupCharStageCtrl
    GoSub FillCharStageCtrl
    GoSub SetupReactorStageCtrl
    GoSub FillReactorStageCtrl
    GoSub SetupDispStageCtrl
    GoSub FillDispStageCtrl
	GoSub FillANKOGroups
	GoSub EnableAnkoCheckbox
	GoSub EnableANKOGroups
	GoSub EnableSaveButton
    
return


SaveAll:

    // If this is a new GaN PSN then we need to setup (i.e. create) mandatory RUN_STAGE
    // and PRS_STAGE records.
    PartParamOrigVals = Get_Property(@Window, '@ORIG_VALUE_LIST')
    PartParamCurrVals = Get_Property(@Window, '@VALUE_LIST')
    PartParamChange   = (PartParamOrigVals NE PartParamCurrVals)

    If PartParamChange EQ True$ then
        Response    = Dialog_Box('NDW_VERIFY_USER', @WINDOW, @USER4 : @FM : 'GAN_PARAMETERS')
        Valid       = Response<1>
        If (Valid EQ True$) then
            GoSub SavePartParams         
        end else
            ErrMsg('Part parameters not saved. User not authorized to save part parameters.')
        end
    end
                        
    GoSub FillDispStageCtrl
                
    StageOrigVals    = Get_Property(@Window, '@ORIG_STAGE_ENABLED_LIST')
    StageCurrVals    = Get_Property(@Window, '@STAGE_ENABLED_LIST')
    StageChange      = (StageOrigVals NE StageCurrVals)           
    If StageChange EQ True$ then GoSub SaveEnabledStageList
    
    OrigStageOrder   = Get_Property(@Window, '@ORIG_STAGE_ORDER_LIST')
    CurrStageOrder   = Get_Property(@Window, '@STAGE_ORDER_LIST')
    StageOrderChange = (OrigStageOrder NE CurrStageOrder)
*    If StageOrderChange EQ True$ then GoSub SaveStageOrder
    GoSub SaveStageOrder
    
    ANKOMetPocketsOrig   = Get_Property(@Window, '@ORIG_ANKO_MET_POCKETS')
    ANKOMetPockets       = Get_Property(@Window, '@ANKO_MET_POCKETS')
    ANKOMetPocketsChange = (ANKOMetPocketsOrig NE ANKOMetPockets)
    If ANKOMetPocketsChange EQ True$ then GoSub SaveANKOMetPockets
    
    ANKOFullCharPocketOrig = Get_Property(@Window, '@ORIG_ANKO_FULL_CHAR_POCKET')
    ANKOFullCharPocket     = Get_Property(@Window, '@ANKO_FULL_CHAR_POCKET')
    ANKOCharPocketChange   = Get_Property(ANKOFullCharPocketOrig NE ANKOFullCharPocket)
    If ANKOCharPocketChange EQ True$ then GoSub SaveANKOFullCharPocket
    
    GoSub EnableSaveButton
    
return


SavePartParams:
    
    GoSub SaveParameters
    GoSub ResetColorArrays
    GoSub FillPartParamCtrl
    GoSub ColorTabs
    GoSub DisplayTimestamps            
    ParameterList = Get_Property(@Window, '@VALUE_LIST')
    Set_Property(@Window, '@ORIG_VALUE_LIST', ParameterList)
    Set_Property(@Window, '@ORIG_MET_LIST', NewParamNameList)
    
return


SaveEnabledStageList:
    
    // Save enabled stage list
    PSNo           = Get_Property(@Window:'.PROD_SPEC_ID', 'TEXT')
    StageList      = Get_Property(@Window:'.OLE_CHAR_STAGE_EDT', 'OLE.LIST')
    
    For each Row in StageList using @FM setting RowIndex
        StageID       = Row<0, 1>
        Enabled       = Row<0, 3>
        PRSStageKey   = PSNo:'*':StageID
        If Enabled EQ True$ then
            // Create PRS_STAGE record if it does not already exist
            If ( RowExists('PRS_STAGE', PRSStageKey) EQ False$ ) then
                // Create PRS_STAGE record
                PRSStageRec = ''
                PRSStageRec<PRS_STAGE_PROC_TOOL_CLASS$> = Gan_Services('GetToolClassIDs', StageID)
                PRSStageRec<PRS_STAGE_PROC_INV_ACTION$> = 'START':@VM:'STOP'
                Database_Services('WriteDataRow', 'PRS_STAGE', PRSStageKey, PRSStageRec, True$, False$, True$)      
            end
        end else
            // Delete the PRS_STAGE record if it exists
            If ( RowExists('PRS_STAGE', PRSStageKey) EQ True$ ) then
                // Delete the PRS_STAGE record
                Database_Services('DeleteDataRow', 'PRS_STAGE', PRSStageKey)
            end
        end
    Next Row
    
    Set_Property(@Window, '@ORIG_STAGE_ENABLED_LIST', StageEnabledList)
    Set_Property(@Window, '@STAGE_ENABLED_LIST', StageEnabledList)
        
return


SetupReactorStageCtrl:
    
    ReactorStageCtrl     = @Window:'.OLE_REACTOR_STAGE_EDT'
    HeaderRowTitles   = 'Stage':@VM:'Description':@VM:''
    CharStageDimArray = 3:@FM:4
    Set_Property(ReactorStageCtrl, "OLE.Dimension", CharStageDimArray)
    Set_Property(ReactorStageCtrl, "OLE.TitleList", HeaderRowTitles)
    
    HeaderFontArray   = 'Segoe UI':@SVM:8:@SVM:700
    Set_Property(ReactorStageCtrl, "OLE.HeaderFont[All; All]", HeaderFontArray)
    HeaderColArray = 40:@FM:False$:@FM:False$:@FM:False$
    Set_Property(ReactorStageCtrl, "OLE.HeaderColumn[1]", HeaderColArray)
    
    // Disable resizing of columns as there is no need for this on this form
    StageColSize = Get_Property(ReactorStageCtrl, "OLE.DataColumn[1]")
    StageColSize<1> = 70
    StageColSize<3> = False$
    Set_Property(ReactorStageCtrl, "OLE.DataColumn[1]", StageColSize)
    StageColSize<1> = 180
    Set_Property(ReactorStageCtrl, "OLE.DataColumn[2]", StageColSize)
    StageColSize<1> = 36
    Set_Property(ReactorStageCtrl, "OLE.DataColumn[3]", StageColSize)
    Set_Property(ReactorStageCtrl, "OLE.CellProtection[All; All]", 'Read Only')
    Set_Property(ReactorStageCtrl, "OLE.HeaderAlignment[All; 1]", 'C':@FM:'C':@FM:'L')
    // Disable scrollbars
    Set_Property(ReactorStageCtrl, "OLE.ScrollBarsVisible", 'N':@FM:'N')
    // Setup checkbox column
    CheckBoxArray      = 'Check Box'
    CheckBoxArray<2,1> = True$
    Set_Property(ReactorStageCtrl, "OLE.CellType[3; All]", CheckBoxArray)
    Set_Property(ReactorStageCtrl, "OLE.CellCheckEnabled[3; All]", False$)
    Set_Property(ReactorStageCtrl, "OLE.CellAlignment[3; All]", 'C':@FM:'C':@FM:'L')
    Set_Property(ReactorStageCtrl, "OLE.AllowDeletions", False$)
    Set_Property(ReactorStageCtrl, "OLE.AllowInserts", False$)
    
    // Qualify OLE events that we want to intercept
    Qualifier = ''
    Qualifier<1> = 1
    Qualifier<4> = 0 ; * process synchronously (i.e. immediately)
    Send_Message(ReactorStageCtrl, 'QUALIFY_EVENT', 'OLE.OnCheckChanged', Qualifier)

return


SetupCharStageCtrl:
    
    CharStageCtrl     = @Window:'.OLE_CHAR_STAGE_EDT'
    HeaderRowTitles   = 'Stage':@VM:'Description':@VM:''
    CharStageDimArray = 3:@FM:17
    Set_Property(CharStageCtrl, "OLE.Dimension", CharStageDimArray)
    Set_Property(CharStageCtrl, "OLE.TitleList", HeaderRowTitles)
    
    HeaderFontArray   = 'Segoe UI':@SVM:8:@SVM:700
    Set_Property(CharStageCtrl, "OLE.HeaderFont[All; All]", HeaderFontArray)
    HeaderColArray = 40:@FM:False$:@FM:False$:@FM:False$
    Set_Property(CharStageCtrl, "OLE.HeaderColumn[1]", HeaderColArray)
    
    // Disable resizing of columns as there is no need for this on this form
    StageColSize = Get_Property(CharStageCtrl, "OLE.DataColumn[1]")
    StageColSize<1> = 70
    StageColSize<3> = False$
    Set_Property(CharStageCtrl, "OLE.DataColumn[1]", StageColSize)
    StageColSize<1> = 180
    Set_Property(CharStageCtrl, "OLE.DataColumn[2]", StageColSize)
    StageColSize<1> = 36
    Set_Property(CharStageCtrl, "OLE.DataColumn[3]", StageColSize)
    Set_Property(CharStageCtrl, "OLE.CellProtection[All; All]", 'Read Only')
    Set_Property(CharStageCtrl, "OLE.HeaderAlignment[All; 1]", 'C':@FM:'C':@FM:'L')
    // Disable scrollbars
    Set_Property(CharStageCtrl, "OLE.ScrollBarsVisible", 'N':@FM:'N')
    // Setup checkbox column
    CheckBoxArray      = 'Check Box'
    CheckBoxArray<2,1> = True$
    Set_Property(CharStageCtrl, "OLE.CellType[3; All]", CheckBoxArray)
    Set_Property(CharStageCtrl, "OLE.CellAlignment[3; All]", 'C':@FM:'C':@FM:'L')
    Set_Property(CharStageCtrl, "OLE.AllowDeletions", False$)
    Set_Property(CharStageCtrl, "OLE.AllowInserts", False$)
    Set_Property(CharStageCtrl, "OLE.ResetSelPos", False$)
    SelStyleArray    = Get_Property(CharStageCtrl, "OLE.SelectionStyle")
    SelStyleArray<8> = True$ ; // Always show selected row even when table loses focus
    Set_Property(CharStageCtrl, "OLE.SelectionStyle", SelStyleArray)
    
    // Qualify OLE events that we want to intercept
    Qualifier = ''
    Qualifier<1> = 1
    Qualifier<4> = 0 ; * process synchronously (i.e. immediately)
    Send_Message(CharStageCtrl, 'QUALIFY_EVENT', 'OLE.OnCheckChanged', Qualifier)
    Send_Message(CharStageCtrl, 'QUALIFY_EVENT', 'OLE.PosChanged', Qualifier)

return


SetupDispStageCtrl:
    
    DispStageCtrl     = @Window:'.OLE_DISP_STAGE_EDT'
    HeaderRowTitles   = 'Stage':@VM:'Description':@VM:''
    CharStageDimArray = 3:@FM:3
    Set_Property(DispStageCtrl, "OLE.Dimension", CharStageDimArray)
    Set_Property(DispStageCtrl, "OLE.TitleList", HeaderRowTitles)
    
    HeaderFontArray   = 'Segoe UI':@SVM:8:@SVM:700
    Set_Property(DispStageCtrl, "OLE.HeaderFont[All; All]", HeaderFontArray)
    HeaderColArray = 40:@FM:False$:@FM:False$:@FM:False$
    Set_Property(DispStageCtrl, "OLE.HeaderColumn[1]", HeaderColArray)
    
    // Disable resizing of columns as there is no need for this on this form
    StageColSize = Get_Property(DispStageCtrl, "OLE.DataColumn[1]")
    StageColSize<1> = 70
    StageColSize<3> = False$
    Set_Property(DispStageCtrl, "OLE.DataColumn[1]", StageColSize)
    StageColSize<1> = 180
    Set_Property(DispStageCtrl, "OLE.DataColumn[2]", StageColSize)
    StageColSize<1> = 36
    Set_Property(DispStageCtrl, "OLE.DataColumn[3]", StageColSize)
    Set_Property(DispStageCtrl, "OLE.CellProtection[All; All]", 'Read Only')
    Set_Property(DispStageCtrl, "OLE.HeaderAlignment[All; 1]", 'C':@FM:'C':@FM:'L')
    // Disable scrollbars
    Set_Property(DispStageCtrl, "OLE.ScrollBarsVisible", 'N':@FM:'N')
    // Setup checkbox column
    CheckBoxArray      = 'Check Box'
    CheckBoxArray<2,1> = True$
    Set_Property(DispStageCtrl, "OLE.CellType[3; All]", CheckBoxArray)
    Set_Property(DispStageCtrl, "OLE.CellCheckEnabled[3; All]", False$)
    Set_Property(DispStageCtrl, "OLE.CellAlignment[3; All]", 'C':@FM:'C':@FM:'L')
    Set_Property(DispStageCtrl, "OLE.AllowDeletions", False$)
    Set_Property(DispStageCtrl, "OLE.AllowInserts", False$)
    
    // Qualify OLE events that we want to intercept
    Qualifier = ''
    Qualifier<1> = 1
    Qualifier<4> = 0 ; * process synchronously (i.e. immediately)
    Send_Message(DispStageCtrl, 'QUALIFY_EVENT', 'OLE.OnCheckChanged', Qualifier)

return


FillReactorStageCtrl:

    ReactorStageCtrl     = @Window:'.OLE_REACTOR_STAGE_EDT'
    StageList            = Gan_Services('GetGaNStages', 'Reactor')
    ReactorStageCtrlList = ''
    For each StageID in StageList using @VM setting RowIndex
        ReactorStageCtrlList<RowIndex, 1> = StageID
        ReactorStageCtrlList<RowIndex, 2> = GaN_Services('GetStageDesc', StageID)
        ReactorStageCtrlList<RowIndex, 3> = True$      
    Next StageID
    Set_Property(ReactorStageCtrl, 'OLE.LIST', ReactorStageCtrlList)
    // Color headers
    Set_Property(ReactorStageCtrl, "OLE.HeaderColors[All; 1]", @FM:"{180, 180, 180}")
    CellColorArray = 'None':@FM:"{220, 220, 220}"
    Set_Property(ReactorStageCtrl, "OLE.CellColors[All; All]", CellColorArray)
    
return


FillCharStageCtrl:

    PSNo           = Get_Property(@Window:'.PROD_SPEC_ID', 'TEXT')
    PSRec          = Database_Services('ReadDataRow', 'PROD_SPEC', PSNo)
    PRSStageKeys   = PSRec<PROD_SPEC_PRS_STAGE_KEY$>
    CharStageCtrl  = @Window:'.OLE_CHAR_STAGE_EDT'
    ReqStages      = Gan_Services('GetReqStages')
    CharStages     = GaN_Services('GetGaNStages', 'Metrology', PSNo)
    CurrRecord     = Get_Property(@Window, 'ATRECORD')
    CharStageCtrlList = ''
    For each StageID in CharStages using @VM setting RowIndex
        ToolClassKey = 'G_':StageID
        Destructive  = GaN_Services('IsDestStage', StageID)
        CharStageCtrlList<RowIndex, 1> = StageID
        CharStageCtrlList<RowIndex, 2> = GaN_Services('GetStageDesc', StageID)
        PRSStageKey = PSNo:'*':StageID
        Locate PRSStageKey in PRSStageKeys using @VM setting Dummy then
            StageEnabled = True$
        end else
            StageEnabled = False$
        end
        Locate StageID in ReqStages using @VM setting Dummy then
            CellColorArray = 'None':@FM:"{220, 220, 220}"
            Set_Property(CharStageCtrl, "OLE.CellColors[All; ":RowIndex:"]", CellColorArray)
            Set_Property(CharStageCtrl, "OLE.CellCheckEnabled[3; ":RowIndex:"]", False$)
        end else
            Set_Property(CharStageCtrl, "OLE.CellCheckEnabled[3; ":RowIndex:"]", True$)
        end
        CharStageCtrlList<RowIndex, 3> = StageEnabled
    Next StageID
    Set_Property(CharStageCtrl, 'OLE.LIST', CharStageCtrlList)
    StageEnabledList = Get_Property(CharStageCtrl, 'OLE.ColumnData[3]')
    StageOrderList   = Get_Property(CharStageCtrl, 'OLE.ColumnData[1]')
    Set_Property(@Window, '@ORIG_STAGE_ORDER_LIST', StageOrderList)
    Set_Property(@Window, '@STAGE_ORDER_LIST', StageOrderList)
    Set_Property(@Window, '@ORIG_STAGE_ENABLED_LIST', StageEnabledList)
    Set_Property(@Window, '@STAGE_ENABLED_LIST', StageEnabledList)
    // Color headers
    Set_Property(CharStageCtrl, "OLE.HeaderColors[All; 1]", @FM:"{180, 180, 180}")
    GoSub ColorCharStages
    
return


FillDispStageCtrl:

    ANKO              = Get_Property(@Window:'.CHK_ANKO', 'DEFPROP')
    DispStageCtrl     = @Window:'.OLE_DISP_STAGE_EDT'
    StageList         = Gan_Services('GetGaNStages', 'Disposition')
    DispStageCtrlList = ''
    For each StageID in StageList using @VM setting RowIndex
        DispStageCtrlList<RowIndex, 1> = StageID
        DispStageCtrlList<RowIndex, 2> = GaN_Services('GetStageDesc', StageID)
        If ( (StageID EQ 'G_PACK') and (ANKO EQ True$) ) then
            DispStageCtrlList<RowIndex, 3> = False$          
        end else
            DispStageCtrlList<RowIndex, 3> = True$      
        end     
    Next StageID
    Set_Property(DispStageCtrl, 'OLE.LIST', DispStageCtrlList)    
    // Color headers
    Set_Property(DispStageCtrl, "OLE.HeaderColors[All; 1]", @FM:"{180, 180, 180}")
    CellColorArray = 'None':@FM:"{220, 220, 220}"
    Set_Property(DispStageCtrl, "OLE.CellColors[All; All]", CellColorArray)
    
return


FillANKOGroups:

    PSNo               = Get_Property(@Window:'.PROD_SPEC_ID', 'TEXT')
    PSRec              = Database_Services('ReadDataRow', 'PROD_SPEC', PSNo)
    ANKO               = PSRec<PROD_SPEC_ANKO$>
    ANKOMetPockets     = PSRec<PROD_SPEC_ANKO_MET_POCKETS$>
    ANKOFullCharPocket = PSRec<PROD_SPEC_ANKO_FULL_CHAR_POCKET$>
    ANKOWaferSel       = PSRec<PROD_SPEC_ANKO_WAFER_SELECTION$>
    If ( (ANKOWaferSel EQ '') or (ANKO and (ANKOWaferSel EQ 'PRESET') ) ) then
        If ANKO then
            ANKOWaferSel = 'CANDELA'
        end else
            ANKOWaferSel = 'PRESET'
        end
        PSRec<PROD_SPEC_ANKO_WAFER_SELECTION$> = ANKOWaferSel
        Database_Services('WriteDataRow', 'PROD_SPEC', PSNo, PSRec, True$, False$, True$)
    end
    If ANKOFullCharPocket EQ '' then
        ANKOFullCharPocket                      = 1
        PSRec<PROD_SPEC_ANKO_FULL_CHAR_POCKET$> = ANKOFullCharPocket
        Database_Services('WriteDataRow', 'PROD_SPEC', PSNo, PSRec, True$, False$, True$)
    end
    For Pocket = 1 to 8
        Check = ANKOMetPockets<0, Pocket>
        Set_Property(@Window:'.CHK_WFR_':Pocket, 'CHECK', Check)
        If Check EQ True$ then
            ANKOMetPockets<0, Pocket> = True$
            Set_Property(@Window:'.CHK_CHAR_':Pocket, 'ENABLED', True$)
        end else
            ANKOMetPockets<0, Pocket> = False$
            Set_Property(@Window:'.CHK_CHAR_':Pocket, 'ENABLED', False$)
        end
    Next Pocket
    Set_Property(@Window:'.CHK_CHAR_':ANKOFullCharPocket, 'CHECK', True$)
    Set_Property(@Window:'.RDO_WAFER_SELECTION', 'VALUE', ANKOWaferSel)
    Set_Property(@Window, '@ORIG_ANKO_MET_POCKETS', ANKOMetPockets)
    Set_Property(@Window, '@ANKO_MET_POCKETS', ANKOMetPockets)
    Set_Property(@Window, '@ORIG_ANKO_FULL_CHAR_POCKET', ANKOFullCharPocket)
    Set_Property(@Window, '@ANKO_FULL_CHAR_POCKET', ANKOFullCharPocket)
    Set_Property(@Window, '@ORIG_ANKO_WAFER_SELECTION', ANKOWaferSel)
    Set_Property(@Window, '@ANKO_WAFER_SELECTION', ANKOWaferSel)
    
return


UpdateANKOGroups:

    ANKO     = Get_Property(@Window:'.CHK_ANKO', 'CHECK')
    Pocket   = Ctrl[-1, 1]
    Begin Case
        Case (Ctrl[1, 8] EQ 'CHK_WFR_')
            ANKOMetPockets            = Get_Property(@Window, '@ANKO_MET_POCKETS')
            CheckVal                  = Get_Property(@Window:'.CHK_WFR_':Pocket, 'CHECK')
            ANKOMetPockets<0, Pocket> = CheckVal
            If ANKO then Set_Property(@Window:'.CHK_CHAR_':Pocket, 'ENABLED', CheckVal)
            Set_Property(@Window, '@ANKO_MET_POCKETS', ANKOMetPockets)
            
            If CheckVal EQ False$ then
                CharPocket = Get_Property(@Window:'.CHK_CHAR_':Pocket, 'CHECK')
                If CharPocket EQ True$ then
                    // Reset char pocket to 1
                    Set_Property(@Window:'.CHK_CHAR_1', 'CHECK', True$)
                    Set_Property(@Window:'.CHK_CHAR_':Pocket, 'CHECK', False$)
                end               
            end
                       
        Case (Ctrl[1, 9] EQ 'CHK_CHAR_')
            CheckVal = Get_Property(@Window:'.CHK_CHAR_':Pocket, 'CHECK')
            If CheckVal EQ True$ then
                ANKOCharPocket = Pocket
            end else
                ANKOCharPocket = 1
                Set_Property(@Window:'.CHK_CHAR_':ANKOCharPocket, 'CHECK', True$)
            end
            Set_Property(@Window, '@ANKO_FULL_CHAR_POCKET', ANKOCharPocket)
            // Ensure all other char check boxes are cleared
            For CharPocket = 1 to 8
                If CharPocket NE ANKOCharPocket then
                    Set_Property(@Window:'.CHK_CHAR_':CharPocket, 'CHECK', False$)
                end
            Next CharPocket
    End Case
    
return


ResetColorArrays:
    
    PSNo           = Get_Property(@Window:'.PROD_SPEC_ID', 'TEXT')
    PartNo         = Get_Property(@Window, '@CURR_PART_NO')
    GaNParamStages = Get_Property(@Window, '@GAN_PARAM_STAGES')
    CellColorArray = ''
    For each Stage in GaNParamStages using @VM setting TabIndex       
        GaNParamConfigKey = PSNo:'*':PartNo:'*':Stage
        GaNParamConfigRec = Database_Services('ReadDataRow', 'GAN_PARAM_CONFIG', GaNParamConfigKey)
        ParamNames        = GaNParamConfigRec<GAN_PARAM_CONFIG.PARAM_NAME$>
        For each ParamName in ParamNames using @VM setting RowPos                             
            CellColorArray<TabIndex, RowPos, 1> = 'None'
            CellColorArray<TabIndex, RowPos, 2> = 'None'
            CellColorArray<TabIndex, RowPos, 3> = 'None'
            CellColorArray<TabIndex, RowPos, 4> = 'None'
            CellColorArray<TabIndex, RowPos, 5> = 'None'            
        Next ParamName                               
    Next Stage
    Set_Property(@Window, '@COLOR_ARRAY', CellColorArray)
    
return


DisplayTimestamps:
    
    PSNo = Get_Property(@Window:'.PROD_SPEC_ID', 'TEXT')
    If PSNo NE '' then
        ProdSpecRec = Database_Services('ReadDataRow', 'PROD_SPEC', PSNo)
        RevCPDTM = ProdSpecRec<PROD_SPEC_GAN_REV_CP_DTM$>
        RevOIDTM = ProdSpecRec<PROD_SPEC_GAN_REV_OI_DTM$>
        RevUser  = ProdSpecRec<PROD_SPEC_GAN_REV_USER$>
        RevCPDTM = OConv(RevCPDTM, 'DT2/^H')
        RevOIDTM = OConv(RevOIDTM, 'DT2/^H')
        Set_Property(@Window:'.TXT_OI_DTM', 'TEXT', RevOIDTM)
        Set_Property(@Window:'.TXT_CP_DTM', 'TEXT', RevCPDTM)
        Set_Property(@Window:'.TXT_USER', 'TEXT', OConv(RevUser, '[XLATE_CONV,LSL_USERS*FIRST_LAST]'))
    end
    
return


SetupTabCtrl:
    
    PSNo = Get_Property(@Window:'.PROD_SPEC_ID', 'TEXT')
    PartNos = Xlate('PROD_SPEC', PSNo, 'PROD_VER_EPI_PART_NO', 'X')
    NumPartNos = DCount(PartNos, @VM)
    CurrPartNo = Field(PartNos, @VM, NumPartNos)
    Set_Property(@Window, '@CURR_PART_NO', CurrPartNo)
    GaNParamStages = Xlate('APP_INFO', 'GAN_PARAM_STAGES', '', 'X')
    TabCtrl = @Window:'.OLE_TAB'
    NumTabs = DCount(GaNParamStages, @VM)
    Set_Property(TabCtrl, "OLE.TabCount", NumTabs)
    Convert @VM to ',' in GaNParamStages
    Convert '_' to ' ' in GaNParamStages
    Set_Property(TabCtrl, "OLE.CaptionList", GaNParamStages)
    FontArray = 'Segoe UI':@SVM:9:@SVM:700
    Set_Property(TabCtrl, "OLE.Font", FontArray)
    Set_Property(TabCtrl, "OLE.SelectFont", FontArray)
    
    // Qualify OLE events that we want to intercept
    Qualifier = ''
    Qualifier<1> = 1
    Qualifier<4> = 0 ; * process synchronously (i.e. immediately)
    Send_Message(TabCtrl, 'QUALIFY_EVENT', 'OLE.SelChanged', Qualifier)
    
    Set_Property(TabCtrl, "OLE.FlickerFree", True$)
    
return


UpdateLimits:

    PSNo = Get_Property(@Window:'.PROD_SPEC_ID', 'TEXT')
    If PSNo NE '' then
        CurrDTM = DateTime()
        PartNos = Xlate('PROD_SPEC', PSNo, 'PROD_VER_EPI_PART_NO', 'X')
        NumPartNos = DCount(PartNos, @VM)
        CurrPartNo = Field(PartNos, @VM, NumPartNos)
        If CurrPartNo EQ 'U014' then CurrPartNo = 'G5HTMV675AA'

        Response          = GaN_Services('GetCurrLimits', CurrPartNo)
        ResponseParamList = Response<1>
      
        // Get Control Plan data
        GaNParamKeys = Xlate('PROD_SPEC', PSNo, 'GAN_PARAM_KEYS', 'X')
        Stages = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_PARAM_STAGES', 'X')
        ParameterList = ''
        ParamNameList = ''
        CellColorArray = ''

        For each Stage in Stages using @VM setting TabIndex

            MetType = Stage
            GaNParamConfigKey = PSNo:'*':CurrPartNo:'*':MetType
            GaNParamConfigRec = Database_Services('ReadDataRow', 'GAN_PARAM_CONFIG', GaNParamConfigKey)
            If Error_Services('NoError') then
                ConfigMetNames    = GaNParamConfigRec<GAN_PARAM_CONFIG.MET_NAME$>
                ConfigParams      = GaNParamConfigRec<GAN_PARAM_CONFIG.PARAM_NAME$>
                EnabledArray      = GaNParamConfigRec<GAN_PARAM_CONFIG.ENABLED$>
                CurrVals = Get_Property(@Window, '@ORIG_VALUE_LIST')<TabIndex>
                CurrNames = Get_Property(@Window, '@ORIG_MET_LIST')<TabIndex>
                For each ParamName in ConfigParams using @VM setting RowPos
                    ParamEnabled = EnabledArray<0, RowPos>
                    If ParamEnabled EQ True$ then
                        NextRow = DCount(ParamNameList<TabIndex>, @VM) + 1
                        ParamNameList<TabIndex, NextRow> = ConfigMetNames<0, RowPos>
                        Locate ParamName in CurrNames using @VM setting CurrRow then
                            Locate ParamName in ResponseParamList using @VM setting vPos then      
                                NewLSL     = Response<2, vPos>
                                NewTarget  = Response<3, vPos>
                                NewUSL     = Response<4, vPos>
                                PrevLSL    = CurrVals<0, CurrRow, 1>
                                PrevTarget = CurrVals<0, CurrRow, 2>
                                PrevUSL    = CurrVals<0, CurrRow, 3>
                                
                                If (PrevLSL EQ NewLSL) then
                                    CellColorArray<TabIndex, NextRow, 1> = 'None'
                                end else
                                    CellColorArray<TabIndex, NextRow, 1> = 'Yellow'
                                end
                                If (PrevTarget EQ NewTarget) then
                                    CellColorArray<TabIndex, NextRow, 2> = 'None'
                                end else
                                    CellColorArray<TabIndex, NextRow, 2> = 'Yellow'
                                end
                                If (PrevUSL EQ NewUSL) then
                                    CellColorArray<TabIndex, NextRow, 3> = 'None'
                                end else
                                    CellColorArray<TabIndex, NextRow, 3> = 'Yellow'
                                end
                                
                                ParameterList<TabIndex, NextRow, 1> = NewLSL
                                ParameterList<TabIndex, NextRow, 2> = NewTarget
                                ParameterList<TabIndex, NextRow, 3> = NewUSL
                            end else                                
                                ParameterList<TabIndex, NextRow, 1> = 'None'
                                ParameterList<TabIndex, NextRow, 2> = 'None'
                                ParameterList<TabIndex, NextRow, 3> = 'None'
                            end   
                        end else
                            // New parameter being added
                            Locate ParamName in ResponseParamList using @VM setting vPos then
                                NewLSL     = Response<2, vPos>
                                NewTarget  = Response<3, vPos>
                                NewUSL     = Response<4, vPos>
                                ParameterList<TabIndex, NextRow, 1> = NewLSL
                                ParameterList<TabIndex, NextRow, 2> = NewTarget
                                ParameterList<TabIndex, NextRow, 3> = NewUSL
                                CellColorArray<TabIndex, NextRow, 1> = 'Yellow'
                                CellColorArray<TabIndex, NextRow, 2> = 'Yellow'
                                CellColorArray<TabIndex, NextRow, 3> = 'Yellow'
                            end
                        end
                    end
                                   
                Next ParamName
            end
        Next Stage     
    end
           
    Set_Property(@Window, '@NAME_LIST', ParamNameList)
    Set_Property(@Window, '@VALUE_LIST', ParameterList)
    Set_Property(@Window, '@COLOR_ARRAY', CellColorArray)
       
return


SetupPartParamCtrl:
    
    PartParamCtrl     = @Window:'.OLE_PART_PARAM_EDT'
    HeaderRowTitles   = 'LSL':@VM:'Target':@VM:'USL'
    DispStageDimArray = 5:@FM:1
    Set_Property(PartParamCtrl, "OLE.Dimension", DispStageDimArray)
    Set_Property(PartParamCtrl, "OLE.TitleList", HeaderRowTitles)
    HeaderFontArray   = 'Segoe UI':@SVM:8:@SVM:700
    Set_Property(PartParamCtrl, "OLE.HeaderFont[All; All]", HeaderFontArray)
    HeaderColArray = 180:@FM:True$:@FM:False$:@FM:False$
    Set_Property(PartParamCtrl, "OLE.HeaderColumn[1]", HeaderColArray)
    Set_Property(PartParamCtrl, "OLE.HeaderText[1; 1]", "Metrology Limits")
    // Disable resizing of columns as there is no need for this on this form
    StageColSize = Get_Property(PartParamCtrl, "OLE.DataColumn[1]")
    StageColSize<1> = 100
    StageColSize<3> = False$
    Set_Property(PartParamCtrl, "OLE.DataColumn[All]", StageColSize)
    Set_Property(PartParamCtrl, "OLE.CellProtection[All; All]", 'Read Only')

return


ReadCurrParams:
    
    PSNo = Get_Property(@Window:'.PROD_SPEC_ID', 'TEXT')
    If PSNo NE '' then
        GaNParamStages = Xlate('APP_INFO', 'GAN_PARAM_STAGES', '', 'X')
        Set_Property(@Window, '@GAN_PARAM_STAGES', GaNParamStages)
        GaNParamKeys = Xlate('PROD_SPEC', PSNo, 'GAN_PARAM_KEYS', 'X')
        ParameterList = ''
        ParamNameList = ''
        MetNameList   = ''
        For each GaNParamKey in GaNParamKeys using @VM
            MetType = Field(GaNParamKey, '*', 2)
            Locate MetType in GaNParamStages using @VM setting TabPos then
                GaNParamRec = Database_Services('ReadDataRow', 'GAN_PARAMS', GaNParamKey)
                PartNo  = Field(GaNParamKey, '*', 1)
                ParamNames = GaNParamRec<GAN_PARAMS.PARAM_NAME$>
                MetNames   = GaNParamRec<GAN_PARAMS.MET_NAME$>
                For each ParamName in ParamNames using @VM setting RowPos
                    MetNameList<TabPos, RowPos> = ParamName
                    ParamNameList<TabPos, RowPos> = MetNames<0, RowPos>
                    ParameterList<TabPos, RowPos, 1> = GaNParamRec<GAN_PARAMS.LSL$, RowPos>
                    ParameterList<TabPos, RowPos, 2> = GaNParamRec<GAN_PARAMS.TARGET$, RowPos>
                    ParameterList<TabPos, RowPos, 3> = GaNParamRec<GAN_PARAMS.USL$, RowPos>
                Next ParamName
            end        
        Next GaNParamKey
        Set_Property(@Window, '@NAME_LIST', ParamNameList)
        Set_Property(@Window, '@VALUE_LIST', ParameterList)
        Set_Property(@Window, '@ORIG_VALUE_LIST', ParameterList)
        Set_Property(@Window, '@ORIG_MET_LIST', MetNameList)
    end
    
return


FillPartParamCtrl:
    
    PartParamCtrl     = @Window:'.OLE_PART_PARAM_EDT'
    TabCtrl           = @Window:'.OLE_TAB'
    TabIndex          = Get_Property(TabCtrl, 'OLE.SelectedTab')
    HeaderTitles      = Get_Property(@Window, '@NAME_LIST')<TabIndex>
    ParameterList     = Get_Property(@Window, '@VALUE_LIST')<TabIndex>
    CellColorArray    = Get_Property(@Window, '@COLOR_ARRAY')<TabIndex>   
    NumCols           = 3   
    NumRows           = DCount(ParameterList, @VM)
    DispStageDimArray = NumCols:@FM:NumRows
    Set_Property(PartParamCtrl, "OLE.Dimension", DispStageDimArray)
    Convert @VM to @FM in ParameterList
    Convert @SVM to @VM in ParameterList
    Set_Property(@Window:'.OLE_PART_PARAM_EDT', 'OLE.LIST', ParameterList)
    
    Convert @VM to @FM in HeaderTitles
    Convert @SVM to @VM in HeaderTitles
    For each HeaderTitle in HeaderTitles using @FM setting RowIndex
        Set_Property(PartParamCtrl, "OLE.HeaderText[1; ":RowIndex + 1:"]", HeaderTitle)
    Next HeaderTitle
        
    Set_Property(PartParamCtrl, "OLE.HeaderAlignment[1; 2-":NumRows + 1:"]", 'C':@FM:'L':@FM:'L')
    Set_Property(PartParamCtrl, "OLE.CellAlignment[All; All]", 'C':@FM:'R':@FM:'L')
    Set_Property(PartParamCtrl, "OLE.HeaderAlignment[All; 1]", 'C':@FM:'C':@FM:'L')
    
    GoSub ColorCells
       
return


EnableSaveButton:

    ChangeDetected       = False$
    PartParamOrigVals    = Get_Property(@Window, '@ORIG_VALUE_LIST')
    PartParamCurrVals    = Get_Property(@Window, '@VALUE_LIST')
    StageOrigVals        = Get_Property(@Window, '@ORIG_STAGE_ENABLED_LIST')
    StageCurrVals        = Get_Property(@Window, '@STAGE_ENABLED_LIST')
    StageOrderOrigVals   = Get_Property(@Window, '@ORIG_STAGE_ORDER_LIST')
    StageOrderCurrVals   = Get_Property(@Window, '@STAGE_ORDER_LIST')
    ANKOMetPocketsOrig   = Get_Property(@Window, '@ORIG_ANKO_MET_POCKETS')
    ANKOMetPockets       = Get_Property(@Window, '@ANKO_MET_POCKETS')
    ANKOCharPocketOrig   = Get_Property(@Window, '@ORIG_ANKO_FULL_CHAR_POCKET')
    ANKOCharPocket       = Get_Property(@Window, '@ANKO_FULL_CHAR_POCKET')
    ANKOWaferSelOrig     = Get_Property(@Window, '@ORIG_ANKO_WAFER_SELECTION')
    ANKOWaferSel         = Get_Property(@Window, '@ANKO_WAFER_SELECTION')
    FormOrigVals         = Get_Property(@Window, '@ORIG_RECORD')
    FormCurrVals         = Get_Property(@Window, 'ATRECORD')
    PartParamChange      = (PartParamOrigVals NE PartParamCurrVals)
    DataboundChange      = (FormOrigVals NE FormCurrVals)
    StageChange          = (StageOrigVals NE StageCurrVals)
    StageOrderChange     = (StageOrderOrigVals NE StageOrderCurrVals)
    ANKOMetPocketsChange = (ANKOMetPocketsOrig NE ANKOMetPockets)
    ANKOCharPocketChange = (ANKOCharPocketOrig NE ANKOCharPocket)
    ANKOWaferSelChange   = (ANKOWaferSelOrig NE ANKOWaferSel)
    ChangeDetected       = (PartParamChange or DataboundChange or StageChange or StageOrderChange or ANKOMetPocketsChange or ANKOCharPocketChange or ANKOWaferSelChange)
    NewPSN               = Get_Property(@Window, '@NEW_PSN')
    SaveEnabled          = (ChangeDetected or NewPSN)
    Set_Property(@Window:'.PUB_SAVE', 'ENABLED', SaveEnabled)
    Set_Property(@Window, 'SAVEWARN', ChangeDetected)
    
return


EnableImportButton:

    NameList = Get_Property(@Window, '@NAME_LIST')
    ChangeDetected = False$
    PSNo         = Get_Property(@Window:'.PROD_SPEC_ID', 'TEXT')
    CurrPartNo   = Get_Property(@Window, '@CURR_PART_NO')
    Stages       = Get_Property(@Window, '@GAN_PARAM_STAGES')
    DataToImport = False$
    For each Stage in Stages using @VM setting TabIndex
        ThisNameList = NameList<TabIndex>
        GaNParamConfigKey = PSNo:'*':CurrPartNo:'*':Stage
        GaNParamConfigRec = Database_Services('ReadDataRow', 'GAN_PARAM_CONFIG', GaNParamConfigKey)
        If Error_Services('NoError') then
            MetNames     = GaNParamConfigRec<GAN_PARAMS.MET_NAME$>
            EnabledArray = GaNParamConfigRec<GAN_PARAM_CONFIG.ENABLED$>
            If MetNames NE '' then
                For each MetName in MetNames using @VM setting vPos
                    Enabled = EnabledArray<0, vPos>
                    If Enabled EQ True$ then
                        Locate MetName in ThisNameList using @VM setting nPos else
                            ChangeDetected = True$
                        end
                    end else
                        Locate MetName in ThisNameList using @VM setting nPos then
                            ChangeDetected = True$
                        end
                    end
                Until ChangeDetected EQ True$
                Next MetName
            end
        end
    Until ChangeDetected EQ True$
    Next Stage
    Set_Property(@Window:'.PUB_IMPORT_CP', 'ENABLED', ChangeDetected)
        
return


EnableAnkoCheckbox:
    
    TechType = Get_Property(@Window:'.RDO_TECH_TYPE', 'DEFPROP')
    If TechType EQ 'P' then
        Set_Property(@Window:'.CHK_ANKO', 'ENABLED', True$)
    end else
        Set_Property(@Window:'.CHK_ANKO', 'ENABLED', False$)
    end
    
return


ColorCells:

    PartParamCtrl = @Window:'.OLE_PART_PARAM_EDT'
    DimArray      = Get_Property(PartParamCtrl, "OLE.Dimension")
    NumCols       = DimArray<1>
    NumRows       = DimArray<2>
    For Row = 1 to NumRows
         For Col = 1 to NumCols
             CellColor = CellColorArray<0, Row, Col> 
             Set_Property(PartParamCtrl, 'OLE.CellColors[':Col:';':Row:']', @FM:CellColor)
         Next Col
    Next Row
    
return


ColorTabs:

    GaNParamStages = Get_Property(@Window, '@GAN_PARAM_STAGES')
    CellColorArray = Get_Property(@Window, '@COLOR_ARRAY')
    For each Stage in GaNParamStages using @VM setting TabIndex
        ThisCellColorArray = CellColorArray<TabIndex>
        GoSub ColorTab
    Next Stage
    
return


HideTabs:

    SelTabIndex    = Get_Property(@Window:".OLE_TAB", "OLE.SelectedTab")
    GaNParamStages = Get_Property(@Window, '@GAN_PARAM_STAGES')
    NumTabs        = DCount(GaNParamStages, @VM)
    NameArray      = Get_Property(@Window, '@NAME_LIST')
    For each Stage in GaNParamStages using @VM setting TabIndex
        ThisNameArray = NameArray<TabIndex>
        GoSub HideTab
    Next Stage
    
    SelTabVisible = Get_Property(@Window:'.OLE_TAB', 'OLE.TabVisible[':SelTabIndex:']')
    If SelTabVisible EQ False$ then
        For TabIndex = 1 to NumTabs
            TabVisible = Get_Property(@Window:'.OLE_TAB', 'OLE.TabVisible[':TabIndex:']')        
        Until TabVisible EQ True$
        Next TabIndex
        If TabVisible EQ True$ then Set_Property(@Window:".OLE_TAB", "OLE.SelectedTab", TabIndex)
    end
    
return


HideTab:

    If ThisNameArray EQ '' then
        Set_Property(@Window:'.OLE_TAB', 'OLE.TabVisible[':TabIndex:']', False$)
    end else
        Set_Property(@Window:'.OLE_TAB', 'OLE.TabVisible[':TabIndex:']', True$) 
    end
    
return


ColorTab:

    NumRows        = DCount(ThisCellColorArray, @VM)
    NumCols        = DCount(ThisCellColorArray, @SVM)
    
    ChangeDetected = False$
    For Row = 1 to NumRows        
         For Col = 1 to NumCols
             CellColor = ThisCellColorArray<0, Row, Col> 
             If CellColor EQ 'Yellow' then
                ChangeDetected = True$
             end
         Until ChangeDetected EQ True$
         Next Col
    Until ChangeDetected EQ True$
    Next Row
    If ChangeDetected EQ False$ then
        Colors = ""
        Colors<1, 2> = "None"
        Colors<2, 2> = "None"
        Colors<3, 2> = "None"
        Colors<4, 1> = "None"
        Colors<4, 2> = "None"
        Colors<5>    = "None"
        Set_Property(TabCtrl, "OLE.TabColors[":TabIndex:"]", Colors)
    end else
        Colors = ""
        Colors<1, 2> = "Vertical(Gradient(Yellow L=80, Yellow L=90), Border(Yellow))"
        Colors<2, 2> = "Vertical(Gradient(Yellow L=90, Yellow L=95), Border(Yellow))"
        Colors<3, 2> = "Vertical(Gradient(Yellow L=85, Yellow L=95), Border(Yellow))"
        Colors<4, 1> = "Gray"
        Colors<4, 2> = "Vertical(Gradient(Gray L=80, Gray L=90), Border(Gray))"
        Colors<5>    = "Vertical(Gradient(Yellow L=95, Yellow L=80), Border(Yellow))"
        Set_Property(TabCtrl, "OLE.TabColors[":TabIndex:"]", Colors)
    end
    
return


SaveParameters:
    
    PSNo   = Get_Property(@Window:'.PROD_SPEC_ID', 'TEXT')        
    PartNo = Get_Property(@Window, '@CURR_PART_NO')
    If ( (PSNo NE '') and (PartNo NE '') ) then
        CurrDTM = DateTime()      
        // Get Control Plan data
        NewGaNParamKeys = ''
        ProdSpecRec     = Database_Services('ReadDataRow', 'PROD_SPEC', PSNo)
        GaNParamKeys    = ProdSpecRec<PROD_SPEC_GAN_PARAM_KEYS$>
        GaNParamStages  = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_PARAM_STAGES')
        NewParamNameList = ''
        
        For each GaNParamStage in GaNParamStages using @VM setting TabIndex
            MetType           = GaNParamStage
            GaNParamConfigKey = PSNo:'*':PartNo:'*':MetType
            GaNParamConfigRec = Database_Services('ReadDataRow', 'GAN_PARAM_CONFIG', GaNParamConfigKey)
            MetNames          = GaNParamConfigRec<GAN_PARAM_CONFIG.MET_NAME$>
            ParamNames        = GaNParamConfigRec<GAN_PARAM_CONFIG.PARAM_NAME$>
            HeaderTitles      = Get_Property(@Window, '@NAME_LIST')<TabIndex>
            ParameterList     = Get_Property(@Window, '@VALUE_LIST')<TabIndex>

            If ParameterList NE '' then                   
                // Create new GaN Param record.
                GaNParamRec = ''
                For each ParamName in HeaderTitles using @VM setting RowPos
                    Locate ParamName in MetNames using @VM setting vPos then
                        NewParamNameList<TabIndex, RowPos>          = ParamNames<0, vPos>
                        GaNParamRec<GAN_PARAMS.MET_NAME$, RowPos>   = MetNames<0, vPos>
                        GaNParamRec<GAN_PARAMS.PARAM_NAME$, RowPos> = ParamNames<0, vPos>
                        GaNParamRec<GAN_PARAMS.LSL$, RowPos>        = ParameterList<0, RowPos, 1>
                        GaNParamRec<GAN_PARAMS.TARGET$, RowPos>     = ParameterList<0, RowPos, 2>
                        GaNParamRec<GAN_PARAMS.USL$, RowPos>        = ParameterList<0, RowPos, 3>
                    end
                Next ParamName
                
                NewGaNParamKey = PartNo:'*':MetType:'*':CurrDTM
                NewGaNParamKeys<0, -1> = NewGaNParamKey
                Database_Services('WriteDataRow', 'GAN_PARAMS', NewGaNParamKey, GaNParamRec, True$, False$, True$)
            end
        
        Next GaNParamStage    
        
        Query = "SELECT [Stamp] "                               |
              : "FROM [ControlPlans].[dbo].[Part_Parameter] "   |
              : "WHERE [Part] = 'U012' "                        |
              : "GROUP BY [Stamp]"

        ControlPlanDTM = SQL_Services('PostSQLRequest', 'IQSDMS1', Query)
        ControlPlanDTM[-3, 1] = ''
        ControlPlanDTM = IConv(ControlPlanDTM, "DT")
        
        ProdSpecRec<PROD_SPEC_GAN_PARAM_KEYS$> = NewGaNParamKeys
        ProdSpecRec<PROD_SPEC_GAN_REV_CP_DTM$> = ControlPlanDTM
        ProdSpecRec<PROD_SPEC_GAN_REV_OI_DTM$> = CurrDTM
        ProdSpecRec<PROD_SPEC_GAN_REV_USER$>   = @User4 
        Database_Services('WriteDataRow', 'PROD_SPEC', PSNo, ProdSpecRec, True$, False$, True$)
        
        GaNParamKeysPrime = SRP_Array('Rotate', NewGaNParamKeys, @VM, '*')
        GaNCritStages = GaNParamKeysPrime<1, 2>
        // Cross reference the PRS_STAGE records.
        MetStages = GaN_Services('GetGaNStages', 'Metrology')
        For each StageID in MetStages using @VM setting vPos
            Locate StageID in GaNCritStages using '*' setting Dummy then
                // Check if a PRS_STAGE record exists. If it does not, then create one.
                PRSStageKey = PSNo:'*':StageID
                If (RowExists('PRS_STAGE', PRSStageKey) EQ False$) then
                    // Create PRS_STAGE record
                    PRSStageRec = ''
                    PRSStageRec<PRS_STAGE_PROC_TOOL_CLASS$> = Gan_Services('GetToolClassIDs', StageID)
                    PRSStageRec<PRS_STAGE_PROC_INV_ACTION$> = 'START':@VM:'STOP'
                    Database_Services('WriteDataRow', 'PRS_STAGE', PRSStageKey, PRSStageRec, True$, False$, True$)
                end
            end 
        Next Stage
    end
    
return


StatusClick:

    /* DPC 1/28/19 - when PSN is statused (any status), want to add entry to PROD_SPEC_REV_HIST (history) table */

    ReactorType	= Get_Property(@WINDOW:'.RTYPE','DEFPROP')
    PSNo		= Get_Property(@WINDOW:'.PROD_SPEC_ID','DEFPROP')
    NewStatus	= Get_Property(@WINDOW:'.STATUS','DEFPROP')
    PSRec       = Get_Property(@WINDOW, 'ATRECORD')
    
    IF PSNo = '' THEN RETURN
    
    Begin Case
         
        Case NewStatus EQ 'A'
            // Need to check if this PSN is eligible to be activated.            
            ReadyToActivate = True$
            TechType = Get_Property(@Window:'.RDO_TECH_TYPE', 'DEFPROP')
            If TechType EQ 'P' then
                ReadyToActivate = False$
                PSNo       = Get_Property(@Window:'.PROD_SPEC_ID', 'TEXT')
                CurrPartNo = Get_Property(@Window:'.EDL_PART_NO', 'TEXT')
                If CurrPartNo NE '' then
                    // Need to ensure Candela Total Defects is enabled.
                    GaNParamKeys = PSRec<PROD_SPEC_GAN_PARAM_KEYS$>
                    CanPreKey    = ''
                    For each ParamKey in GaNParamKeys using @VM setting vPos
                        Stage = Field(ParamKey, '*', 2)
                        If Stage EQ 'CAN_PRE' then CanPreKey = ParamKey
                    Until CanPreKey NE ''
                    Next ParamKey
                    If CanPreKey NE '' then
                        CanPreParamRec = Database_Services('ReadDataRow', 'GAN_PARAMS', CanPreKey)
                        If Error_Services('NoError') then
                            MetNames = CanPreParamRec<GAN_PARAMS.MET_NAME$>
                            Locate 'Candela Total Defects' in MetNames using @VM setting vPos then
                                ReadyToActivate = True$ 
                            end else
                                ErrorMsg = 'Candela Total Defects not found in the Part & Parameters configuration record. PSN not eligible to be activated.'
                                ErrMsg(ErrorMsg)
                            end
                        end else
                            ErrorMsg = 'Error reading CAN_PRE parameter configuration record. PSN not eligible to be activated.'
                            ErrMsg(ErrorMsg)
                        end
                    end else
                        ErrorMsg = 'CAN_PRE parameter record not found.'
                        ErrMsg(ErrorMsg)
                    end
                end else
                    ErrorMsg = 'A part number (i.e. PROD_VER) is required in order for the PSN to be activated.'
                    ErrMsg(ErrorMsg)
                end
            end
            If ReadyToActivate EQ False$ then
                Set_Property(@Window:'.STATUS', 'DEFPROP', 'I')
            end
                        
        Case Otherwise$
            Null
            
    End Case
    
return


FillRevHistEDT:
    
    // Fill Revision History Edit Table
    PSNo        = Get_Property(@Window : '.PROD_SPEC_ID', 'DEFPROP')
    RevHistRec  = Database_Services('ReadDataRow', 'PROD_SPEC_REV_HIST', PSNo)
    List = ''
    
    RevisionCol = 1
    UsernameCol = 2
    DateCol     = 3
    TimeCol     = 4
    
    For each Field in RevHistRec using @FM setting fPos
        For Each Value in Field using @VM setting vPos
            Begin Case
                Case fPos EQ 1
                    List<vPos, UsernameCol> = Value
                Case fPos EQ 2
                    List<vPos, DateCol> = OConv(Value, 'D2/HS')
                Case fPos EQ 3
                    List<vPos, TimeCol> = OConv(Value, 'MTH')
                Case fPos EQ 4
                    List<vPos, RevisionCol> = Value
            End Case
        Next Value
    Next Field
    Set_Property(@Window : '.EDT_REV_HIST', 'LIST', List)
    
return


UpdateRevHist:
	
	// Gather one line revision detail
	Result              = False$
	Response            = Dialog_Box('NDW_ADD_PSN_REVISION', @WINDOW)
	Valid               = Response<1>
	RevisionDetail      = Response<2>
	If Valid then
		// Update PROD_SPEC_REV_HIST record
        CtrlName = @Window : '.PROD_SPEC_ID'
		PSNo     = Get_Property(CtrlName,'DEFPROP')
		If RowExists('PROD_SPEC_REV_HIST', PSNo) then
			PSRevHistRec = Database_Services('ReadDataRow', 'PROD_SPEC_REV_HIST', PSNo)
		end else
			PSRevHistRec = ''
			Database_Services('WriteDataRow', 'PROD_SPEC_REV_HIST', PSNo, PSRevHistRec, True$)
			If Error_Services('NoError') then
				// Rev Hist record created successfully
			end else
				Errmsg('Error creating PROD_SPEC_REV_HIST record: ' : PSNo : @SVM : 'Please notify OpenInsight administrator')
			end
		end
		If Error_Services('NoError') then
			Usernames   = PSRevHistRec<PROD_SPEC_REV_HIST_MOD_USERNAME$>
			Dates       = PSRevHistRec<PROD_SPEC_REV_HIST_MOD_DATE$>
			Times       = PSRevHistRec<PROD_SPEC_REV_HIST_MOD_TIME$>
			Revisions   = PSRevHistRec<PROD_SPEC_REV_HIST_REVISION_DETAIL$>
			ModUser     = OConv( @user4, '[XLATE_CONV,LSL_USERS*FIRST_LAST]' )
			ModDate     = Date()
			ModTime     = Time()
			ModRevision = RevisionDetail
			PSRevHistRec<PROD_SPEC_REV_HIST_MOD_USERNAME$>      = Insert(Usernames, 0, 1, 0, ModUser)
			PSRevHistRec<PROD_SPEC_REV_HIST_MOD_DATE$>          = Insert(Dates, 0, 1, 0, ModDate)
			PSRevHistRec<PROD_SPEC_REV_HIST_MOD_TIME$>          = Insert(Times, 0, 1, 0, ModTime)
			PSRevHistRec<PROD_SPEC_REV_HIST_REVISION_DETAIL$>   = Insert(Revisions, 0, 1, 0, ModRevision)
			
			Database_Services('WriteDataRow', 'PROD_SPEC_REV_HIST', PSNo, PSRevHistRec, True$)
			If Error_Services('NoError') then
				Result = True$
			end else
				Errmsg('Error writing PROD_SPEC_REV_HIST record: ' : PSNo : @SVM : 'Please notify OpenInsight administrator')
			end
		end else
			Errmsg('Error reading PROD_SPEC_REV_HIST record: ' : PSNo : @SVM : 'Please notify OpenInsight administrator')
		end
	end else
		Errmsg('You must enter revision details in order to save changes to product specifications')
	end
	
Return Result


EnableArrowButtons:
        
    PSNo        = Get_Property(@Window:'.PROD_SPEC_ID', 'TEXT')
    TechType    = Get_Property(@Window:'.RDO_TECH_TYPE', 'VALUE')

    TopArrow     = @Window:'.PUB_TOP_ARROW'
    UpArrow      = @Window:'.PUB_UP_ARROW'
    DownArrow    = @Window:'.PUB_DOWN_ARROW'
    BottomArrow  = @Window:'.PUB_BOTTOM_ARROW'
    StageEDTCtrl = @Window:'.OLE_CHAR_STAGE_EDT'
    SelRow       = ''
    
    SelList    = Get_Property(StageEDTCtrl, 'OLE.SelPos')
    SelRows    = SelList<2>
    NumSelRows = DCount(SelRows, @VM)
    SelRow     = SelRows<0, 1>
    
    If TechType EQ 'E' then
        Set_Property(TopArrow,      'ENABLED', False$)
        Set_Property(UpArrow ,      'ENABLED', False$)
        Set_Property(DownArrow,     'ENABLED', False$)
        Set_Property(BottomArrow,   'ENABLED', False$) 
    end else
        Begin Case
            Case SelRow EQ TOP$ROW
                Set_Property(TopArrow,      'ENABLED', False$)
                Set_Property(UpArrow ,      'ENABLED', False$)
                Set_Property(DownArrow,     'ENABLED', True$)
                Set_Property(BottomArrow,   'ENABLED', True$)               
            Case (SelRow EQ BOTTOM$ROW)
                Set_Property(TopArrow,      'ENABLED', True$)
                Set_Property(UpArrow ,      'ENABLED', True$)
                Set_Property(DownArrow,     'ENABLED', False$)
                Set_Property(BottomArrow,   'ENABLED', False$)
            Case ( (SelRow GT TOP$ROW) and (SelRow LT BOTTOM$ROW) )
                Set_Property(TopArrow,      'ENABLED', True$)
                Set_Property(UpArrow ,      'ENABLED', True$)
                Set_Property(DownArrow,     'ENABLED', True$)
                Set_Property(BottomArrow,   'ENABLED', True$)
            Case Otherwise$
                Set_Property(TopArrow,      'ENABLED', False$)
                Set_Property(UpArrow ,      'ENABLED', False$)
                Set_Property(DownArrow,     'ENABLED', False$)
                Set_Property(BottomArrow,   'ENABLED', False$)                                     
        End Case  
    end
    
return


ColorCharStages:
    
    CharStageCtrl  = @Window:'.OLE_CHAR_STAGE_EDT'
    StageList      = Get_Property(CharStageCtrl, 'OLE.List')
    DestColorArray = 'Red'
    DefColorArray  = 'None'
    For RowIndex = TOP$ROW to BOTTOM$ROW
        Row         = StageList<RowIndex>
        StageID     = Row<0, 1>
        Destructive = GaN_Services('IsDestStage', StageID)
        If Destructive EQ True$ then
            Set_Property(CharStageCtrl, "OLE.CellColors[All; ":RowIndex:"]", DestColorArray)
        end else
            Set_Property(CharStageCtrl, "OLE.CellColors[All; ":RowIndex:"]", DefColorArray)
        end
    Next RowIndex

return


SaveStageOrder:

    PSNo           = Get_Property(@Window:'.PROD_SPEC_ID', 'TEXT')
    If PSNo NE '' then
        StageOrderList   = ''
        
        ReactorStageList = Get_Property(@Window:'.OLE_REACTOR_STAGE_EDT', 'OLE.LIST')
        For each Row in ReactorStageList using @FM setting RowIndex
            StageID               = Row<0, 1>
            StageOrderList<0, -1> = StageID
        Next Row
        
        CharStageList = Get_Property(@Window:'.OLE_CHAR_STAGE_EDT', 'OLE.LIST')
        For each Row in CharStageList using @FM setting RowIndex
            StageID               = Row<0, 1>
            StageOrderList<0, -1> = StageID
        Next Row
        
        DispStageList = Get_Property(@Window:'.OLE_DISP_STAGE_EDT', 'OLE.LIST')
        For each Row in DispStageList using @FM setting RowIndex
            StageID               = Row<0, 1>
            StageOrderList<0, -1> = StageID
        Next Row
        
        PSRec                             = Database_Services('ReadDataRow', 'PROD_SPEC', PSNo)
        PSRec<PROD_SPEC_PRS_STAGE_ROUTE$> = StageOrderList
        Database_Services('WriteDataRow', 'PROD_SPEC', PSNo, PSRec, True$, False$, True$)
        Set_Property(@Window, '@ORIG_STAGE_ORDER_LIST', StageOrderList)
        Set_Property(@Window, '@STAGE_ORDER_LIST', StageOrderList)
    end
    
return


UpdateCharStageOrder:
    
    CharStageCtrl  = @Window:'.OLE_CHAR_STAGE_EDT'
    StageOrderList = Get_Property(CharStageCtrl, 'OLE.ColumnData[1]')
    Set_Property(@Window, '@STAGE_ORDER_LIST', StageOrderList)

return


EnableANKOGroups:
    
    TechType      = Get_Property(@Window:'.RDO_TECH_TYPE', 'VALUE') 
    ANKOFlag      = Get_Property(@Window:'.CHK_ANKO', 'CHECK')
    GroupsEnabled = ( (ANKOFlag EQ True$) or (TechType EQ 'P') )
    Set_Property(@Window:'.GRP_ANKO_MET_POCKETS', 'ENABLED', GroupsEnabled)
    Set_Property(@Window:'.GRP_ANKO_WAFER_SELECTION', 'ENABLED', GroupsEnabled)
    If GroupsEnabled EQ True$ then
        ANKOWaferSel = Get_Property(@Window:'.RDO_WAFER_SELECTION', 'VALUE')
        If ANKOWaferSel EQ 'PRESET' then
            Set_Property(@Window:'.GRP_ANKO_FULL_CHAR', 'ENABLED', True$)
            ANKOMetPockets = Get_Property(@Window, '@ANKO_MET_POCKETS')
            For Pocket = 1 to 8
                Check = ANKOMetPockets<0, Pocket>
                If ( (Check EQ True$) and ANKOFlag ) then
                    Set_Property(@Window:'.CHK_CHAR_':Pocket, 'ENABLED', True$)
                end else
                    Set_Property(@Window:'.CHK_CHAR_':Pocket, 'ENABLED', False$)
                end
            Next Pocket
        end else
            Set_Property(@Window:'.GRP_ANKO_FULL_CHAR', 'ENABLED', False$)
        end
    end else
        Set_Property(@Window:'.GRP_ANKO_FULL_CHAR', 'ENABLED', ANKOFlag)
    end
    
    Begin Case
        Case ANKOFlag EQ True$
            Set_Property(@Window:'.RDO_WAFER_SELECTION', 'ENABLED', True$)
        Case TechType EQ 'P'
            Set_Property(@Window:'.RDO_WAFER_SELECTION', 'VALUE', 'CANDELA')
            Set_Property(@Window:'.RDO_WAFER_SELECTION', 'ENABLED', -1)
        Case TechType EQ 'E'
            Set_Property(@Window:'.RDO_WAFER_SELECTION', 'ENABLED', False$)
    End Case

    
return


SaveANKOMetPockets:

    ANKOMetPockets                     = Get_Property(@Window, '@ANKO_MET_POCKETS')
    PSNo                               = Get_Property(@Window:'.PROD_SPEC_ID', 'TEXT')
    PSRec                              = Database_Services('ReadDataRow', 'PROD_SPEC', PSNo)
    PSRec<PROD_SPEC_ANKO_MET_POCKETS$> = ANKOMetPockets
    Database_Services('WriteDataRow', 'PROD_SPEC', PSNo, PSRec, True$, False$, True$)
    Set_Property(@Window, '@ORIG_ANKO_MET_POCKETS', ANKOMetPockets)
    
return


SaveANKOFullCharPocket:
    
    ANKOFullCharPocket                      = Get_Property(@Window, '@ANKO_FULL_CHAR_POCKET')
    PSNo                                    = Get_Property(@Window:'.PROD_SPEC_ID', 'TEXT')
    PSRec<PROD_SPEC_ANKO_FULL_CHAR_POCKET$> = ANKOFullCharPocket
    Database_Services('WriteDataRow', 'PROD_SPEC', PSNo, PSRec, True$, False$, True$)
    Set_Property(@Window, '@ORIG_ANKO_FULL_CHAR_POCKET', ANKOFullCharPocket)
    
return

