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

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

    Name        :   NDW_TOOL_PARMS_EVENTS

    Description :   This function acts as a commuter module for all events related to this window.

    Notes       :   Commuter Modules are automatically called from the Promoted_Events function which is called by the
                    application-specific promoted event handler. This makes it possible to add QuickEvents that need to
                    execute Basic+ logic without having use the Form Designer to make the association, although this is
                    limited to the events which are currently promoted.

                    If the form needs to call the commuter module directly then the QuickEvent parameters should be
                    formatted like this:

                        '@SELF','@EVENT',['@PARAM1','@PARAMx']

    Parameters  :
        CtrlEntId   [in] -- The fully qualified name of the control calling the promoted event
        Event       [in] -- The event being executed. See the Notes section regarding "PRE" events
        Param1-15   [in] -- Additional event parameter holders
        EventFlow  [out] -- Set to 1 or 0 so the calling event knows whether or not to chain forward. See comments in
                            EVENT_SETUP insert

    History     :   (Date, Initials, Notes)
        08/31/18    djs     Created initial commuter module.
        09/11/18    djs     Form and commuter module ready for UAT.

***********************************************************************************************************************/
#pragma precomp SRP_PreCompiler
#window NDW_TOOL_PARMS

$Insert RDS_EQUATES
$Insert LOGICAL
$Insert EVENT_SETUP
$Insert RLIST_EQUATES
$Insert RECIPE_EQUATES
$Insert RDS_LAYER_EQUATES
$Insert TOOL_PARMS_EQUATES
$Insert RECIPE_PARMS_EQU
$Insert DICT_EQUATES
$Insert MSG_EQUATES
$Insert SCHED_DET_EQUATES
$Insert WO_DAILY_SCHED_EQU

EQU HIDDEN$	TO 32

Equ COL.LAYER_ID    To   1
Equ COL.DEPOSIT     To   2
Equ COL.DILUENT     To   3
Equ COL.DOPANT_FLOW To   4
Equ COL.HCL_FLOW    To   5
Equ COL.BAKE_TIME   To   6
Equ COL.H2_FLOW     To   7
Equ COL.TCS_FLOW    To   8
Equ COL.DCS_FLOW    To   9
Equ COL.AUX_1_FLOW  To   10
Equ COL.AUX_2_FLOW  To   11
Equ COL.F_OFFSET    To   12
Equ COL.S_OFFSET    To   13
Equ COL.R_OFFSET    To   14
Equ COL.SUSC_ETCH   To   15
Equ COL.ETCH_1      To   16
Equ COL.ETCH_2      To   17
Equ COL.ETCH_3      To   18
Equ COL.UNLOAD_TEMP To   19

Declare Subroutine Set_Property, End_Dialog, Send_Event, Set_Status, obj_WO_Mat, Btree.Extract, Send_Message
Declare Subroutine ErrMsg, Set_Property, obj_AppWindow, Send_Event, obj_WO_Mat_QA, obj_Tables, Msg, Tool_Parms_Services
Declare Subroutine Start_Window, End_Window, Database_Services
Declare Subroutine  SRP_EditTable_Manager, SRP_Show_Window, Rds_Services, Form_Services, Error_Services

Declare Function Get_Property, Get_Status, Dialog_Box, obj_WM_Out, set_WinMsgVal, Form_Services, Error_Services
Declare Function Msg, obj_WO_Mat, Send_Message, obj_Tables, Start_Window, End_Window, QA_Services, Tool_Parms_Services
Declare Function SRP_EditTable_Manager, Database_Services, Material_Services, Rds_Services, RGB, Obj_Recipe
Declare Function Schedule_Services, SRP_Sort_Array

ErrTitle = 'Error in NDW_QA_Met_Result_Events'
ErrorMsg = ''

Result = ''

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

// 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

GoToEvent Event for CtrlEntId else
    // Event not implemented
end

Return EventFlow else EVENT_CONTINUE$

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

Event WINDOW.CREATE(CreateParam)
    
    // Fill Reactor Combo Box
    Query = 'SELECT REACTOR WITH REACT_NO GT 0 AND WITH REACT_NO LT 100 BY REACT_NO'
    RList(Query, TARGET_SAVELIST$, 'REACTOR_LIST', 'Current List of Reactors', False$)
    ReactorList = Database_Services('ReadDataRow', 'SYSLISTS', 'REACTOR_LIST')
    // Remove field containing list description
    ReactorList = Delete(ReactorList, 1, 0, 0)
    Set_Property(@Window : '.COMBO_REACTOR', 'LIST', ReactorList)
    Set_Property(@Window, '@PARMS_CHANGED', False$)
     
    GoSub Setup_OLE_Controls

    SRP_Show_Window(@Window, 'SYSTEM', 'C', 'C', 1, '', False$, False$, FormSize)   
    
End Event


Event COMBO_REACTOR.CHANGED(NewData)
  
    Set_Property(@Window : '.COMBO_PSN', 'ENABLED', True$)
    Set_Property(@Window : '.COMBO_PARM_DTM', 'ENABLED', True$)
    Set_Property(@Window : '.EDT_RECIPE_PARMS', 'ENABLED', True$)
    GoSub FillForm
    Set_Property(CtrlEntId, 'MODIFIED', False$)
    
end event


Event COMBO_REACTOR.CHAR(VirtCode, ScanCode, CtrlKey, ShiftKey, AltKey)
    
    Set_Property(CtrlEntId, 'MODIFIED', True$)
    
end event


Event COMBO_REACTOR.LOSTFOCUS(Flag, FocusID)
    
    ModifiedFlag = Get_Property(CtrlEntID, 'MODIFIED')
    If ModifiedFlag EQ True$ then      
        Set_Property(@Window : '.COMBO_PSN', 'ENABLED', True$)
        Set_Property(@Window : '.COMBO_PARM_DTM', 'ENABLED', True$)
        Set_Property(@Window : '.EDT_RECIPE_PARMS', 'ENABLED', True$)
        GoSub FillForm
        Set_Property(CtrlEntId, 'MODIFIED', False$)

    end
    
end event


Event COMBO_PSN.CHANGED(NewData)

    NewPSN = NewData
    NewRecipeID = Xlate('PROD_SPEC', NewPSN, 'RECIPE_NO', 'X')
    Set_Property(@Window : '.COMBO_PARM_DTM', 'LIST', '')
    Set_Property(@Window : '.COMBO_PARM_DTM', 'TEXT', '')
    Set_Property(@Window : '.EDT_RECIPE_PARMS', 'ARRAY', '')
    Set_Property(@Window : '.EDT_RECIPE_LIMITS', 'ARRAY', '')
    Set_Property(@Window : '.EDL_RECIPE_NAME', 'TEXT', '')
    Set_Property(@Window : '.EDL_DOPANT', 'TEXT', '')
    Set_Property(@Window : '.EDL_DILUENT', 'TEXT', '')
    Set_Property(@Window : '.EDL_RECIPE', 'TEXT', NewRecipeID)
    
    GoSub FillRecipeInfo
    GoSub FillDatetimeInfo
    GoSub FillRecipeParms
    GoSub FillRecipeLimits
    GoSub FormatEditTableColumns
    
end event


Event EDT_RECIPE_PARMS.INSERTROW(RowNum)
    
    Array = Get_Property(CtrlEntID, 'ARRAY')
    Layers = Array<COL.LAYER_ID>
    NumRows = DCount(Layers, @VM)
    Begin Case
        Case NumRows EQ 0
            LayerID = 'L1'
            NewRowNum = 1
        Case NumRows EQ 1
            If Index(Layers, 'L1', 1) then
                LayerID = 'L2'
                NewRowNum = 2
            end else
                LayerID = 'L1'
                NewRowNum = 1
            end
        Case NumRows EQ 2
            Begin Case
                Case Index(Layers, 'L1', 1) and Index(Layers, 'L2', 1)
                    LayerID = '2'
                    NewRowNum = 3
                Case Index(Layers, 'L1', 1) and Index(Layers, '2', 1)
                    LayerID = 'L2'
                    NewRowNum = 2
                Case Index(Layers, 'L2', 1) and Index(Layers, '2', 1)
                    LayerId = 'L1'
                    NewRowNum = 1
            End Case
        Case Otherwise$
            LayerID = -1
    End Case
    If LayerID NE -1 then
        Array = Insert(Array, COL.LAYER_ID, NewRowNum, 0, LayerID)
        Set_Property(CtrlEntID, 'ARRAY', Array)
        Set_Property(@Window, '@PARMS_CHANGED', True$)
    end
    
end event


Event EDT_RECIPE_PARMS.CHANGED(NewData)

    OrigArray = Get_Property(@Window, '@ORIGPARMSARRAY', RecipeParmsArray)
    NewArray  = Get_Property(CtrlEntID, 'ARRAY')
    If OrigArray NE NewArray then
        Set_Property(@Window, '@PARMS_CHANGED', True$)
    end else
        Set_Property(@Window, '@PARMS_CHANGED', False$)
    end
    
end event


Event EDT_RECIPE_PARMS.DELETEROW(RowNum, RowData)
    
    Set_Property(@Window, '@PARMS_CHANGED', True$)
    
end event


Event BTN_SET_CURR_RUN_PARMS.CLICK()

    ReactorNo        = Get_Property(@Window : '.COMBO_REACTOR', 'TEXT')
    PSN              = Get_Property(@Window : '.COMBO_PSN', 'TEXT')
    NewParms         = Get_Property(@Window, '@PARMS_CHANGED')
    
    If ReactorNo NE '' and PSN NE '' then
        
        If NewParms EQ True$ then
            CurrentTime      = OConv(Time(), 'MT')
            CurrentDate      = OConv(Date(), 'D')
            CurrentDTM       = CurrentDate:' ':CurrentTime
            InternalDTM      = IConv(CurrentDTM, 'DT')
            ExternalDTM      = OConv(InternalDTM, 'DT/^3HS')
            Set_Property(@Window : '.COMBO_PARM_DTM', 'TEXT', ExternalDTM)
            InternalDTMList  = Get_Property(@Window, '@INTERNALDTMS', InternalDTMList)
            ExternalDTMList  = Get_Property(@Window, '@EXTERNALDTMS', ExternalDTMList)
            InternalDTMList  = Insert(InternalDTMList, 1, 0, 0, InternalDTM)
            ExternalDTMList  = Insert(ExternalDTMList, 1, 0, 0, ExternalDTM)
            Set_Property(@Window : '.COMBO_PARM_DTM', 'LIST', ExternalDTMList)
            Set_Property(@Window, '@INTERNALDTMS', InternalDTMList)
            Set_Property(@Window, '@EXTERNALDTMS', ExternalDTMList)
            NewToolParmKey   = PSN:'*':ReactorNo:'*':InternalDTM
            NewToolParmRec   = ''
            RecipeParmsArray = Get_Property(@Window : '.EDT_RECIPE_PARMS', 'ARRAY')
            LayerIDs         = RecipeParmsArray<COL.LAYER_ID>
            Dopant           = Get_Property(@Window : '.EDL_DOPANT', 'TEXT')
            EpiDiluent       = Get_Property(@Window : '.EDL_DILUENT', 'TEXT')
            EpiDiluent       = IConv(EpiDiluent, 'MD2')
            
            // Format Data to save parameters in internal format
            ColNames	 = 'LS_ID':@FM:'EPI_TIME':@FM:'DILUENT_ADJ_PARAM':@FM:'DOPANT_FLOW':@FM:'HCL_FLOW':@FM
            ColNames     := 'BAKE_TIME':@FM:'EPI_H2_FLOW':@FM:'TCS_FLOW':@FM:'DCS_FLOW':@FM:'AUX1':@FM:'AUX2':@FM:'F_OFFSET'
            ColNames     := @FM:'S_OFFSET':@FM:'R_OFFSET':@FM:'SUSC_ETCH':@FM:'ETCH1':@FM:'ETCH2':@FM:'ETCH3':@FM:'UNLOAD_TEMP'
            
            For each ColName in ColNames using @FM Setting Col           
                ParamData	= RecipeParmsArray<Col>
                Conversion	= Xlate('DICT.TOOL_PARMS', ColName, DICT_CONV$, 'X')            
                If Conversion NE '' then
                    ParamData = IConv(ParamData, Conversion)
                    RecipeParmsArray<Col> = ParamData
                end           
            next ColName
            
            For each LayerID in LayerIDs using @VM setting vPos
                
                NewToolParmRec<TOOL_PARMS.LS_ID$,               vPos> = LayerID
                NewToolParmRec<TOOL_PARMS.DOPANT$,              vPos> = Dopant
                NewToolParmRec<TOOL_PARMS.EPI_DILUENT$,         vPos> = EpiDiluent
                NewToolParmRec<TOOL_PARMS.EPI_TIME$,            vPos> = RecipeParmsArray<COL.DEPOSIT>
                NewToolParmRec<TOOL_PARMS.DILUENT_ADJ_PARAM$,   vPos> = RecipeParmsArray<COL.DILUENT>
                NewToolParmRec<TOOL_PARMS.DOPANT_FLOW$,         vPos> = RecipeParmsArray<COL.DOPANT_FLOW>
                NewToolParmRec<TOOL_PARMS.HCL_FLOW$,            vPos> = RecipeParmsArray<COL.HCL_FLOW>
                NewToolParmRec<TOOL_PARMS.BAKE_TIME$,           vPos> = RecipeParmsArray<COL.BAKE_TIME>
                NewToolParmRec<TOOL_PARMS.EPI_H2_FLOW$,         vPos> = RecipeParmsArray<COL.H2_FLOW>
                NewToolParmRec<TOOL_PARMS.TCS_FLOW$,            vPos> = RecipeParmsArray<COL.TCS_FLOW>
                NewToolParmRec<TOOL_PARMS.DCS_FLOW$,            vPos> = RecipeParmsArray<COL.DCS_FLOW>
                NewToolParmRec<TOOL_PARMS.AUX1$,                vPos> = RecipeParmsArray<COL.AUX_1_FLOW>
                NewToolParmRec<TOOL_PARMS.AUX2$,                vPos> = RecipeParmsArray<COL.AUX_2_FLOW>
                NewToolParmRec<TOOL_PARMS.F_OFFSET$,            vPos> = RecipeParmsArray<COL.F_OFFSET>
                NewToolParmRec<TOOL_PARMS.S_OFFSET$,            vPos> = RecipeParmsArray<COL.S_OFFSET>
                NewToolParmRec<TOOL_PARMS.R_OFFSET$,            vPos> = RecipeParmsArray<COL.R_OFFSET>
                NewToolParmRec<TOOL_PARMS.ETCH1$,               vPos> = RecipeParmsArray<COL.ETCH_1>
                NewToolParmRec<TOOL_PARMS.ETCH2$,               vPos> = RecipeParmsArray<COL.ETCH_2>
                NewToolParmRec<TOOL_PARMS.ETCH3$,               vPos> = RecipeParmsArray<COL.ETCH_3>
                NewToolParmRec<TOOL_PARMS.OVERGROW_REQ$,        vPos> = False$
                NewToolParmRec<TOOL_PARMS.ENTRY_USERNAME$,      vPos> = @USER4
                NewToolParmRec<TOOL_PARMS.SUSC_ETCH$,           vPos> = RecipeParmsArray<COL.SUSC_ETCH>
                NewToolParmRec<TOOL_PARMS.UNLOAD_TEMP$,         vPos> = RecipeParmsArray<COL.UNLOAD_TEMP>
                
            Next LayerID
            
            Database_Services('WriteDataRow', 'TOOL_PARMS', NewToolParmKey, NewToolParmRec, True$)
        end
        
        Tool_Parms_Services('ApplyCurrentRunParms', PSN, ReactorNo)
        
        If Error_Services('NoError') then
            Msg(@Window, '', 'SUCCESS', '', 'Run parameters have been set for reactor ':ReactorNo)
        end else
            Errmsg('Error setting run parameters. Error message: ':Error_Services('GetMessage'))
        end
    end
    
end event


Event COMBO_PARM_DTM.CHANGED(NewData)
    
    GoSub FillRecipeParms
    GoSub FormatEditTableColumns
    
end event


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


Setup_OLE_Controls:

    Qualify     = ''
    Qualify<1>  = 1
    Qualify<4>  = 0

return


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


FillRecipeInfo:
    
    RecipeID = Get_Property(@Window : '.EDL_RECIPE', 'TEXT')
    If RecipeID NE '' then
        RecipeRec     = Database_Services('ReadDataRow', 'RECIPE', RecipeID)
        RecipeName    = RecipeRec<RECIPE_RECIPE_NAME$>
        RecipeDopant  = RecipeRec<RECIPE_EPI_DOPANT$>
        RecipeDiluent = OConv(RecipeRec<RECIPE_EPI_DILUENT$>, 'MD2')
        Set_Property(@Window : '.EDL_RECIPE_NAME', 'TEXT', RecipeName)
        Set_Property(@Window : '.EDL_DOPANT', 'TEXT', RecipeDopant)
        Set_Property(@Window : '.EDL_DILUENT', 'TEXT', RecipeDiluent)
    end
    
return


FillDatetimeInfo:    

    ReactorNo     = Get_Property(@Window : '.COMBO_REACTOR', 'TEXT')
    PSN           = Get_Property(@Window : '.COMBO_PSN', 'TEXT')
    InternalDTMList = ''
    ExternalDTMList = ''
    Set_Property(@Window : '.COMBO_PARM_DTM', 'TEXT', '')
    Set_Property(@Window : '.COMBO_PARM_DTM', 'LIST', '')
    Set_Property(@Window, '@INTERNALDTMS', '')
    Set_Property(@Window, '@EXTERNALDTMS', '')
    
    
    If ReactorNo NE '' and PSN NE '' then
        
        // Lookup associated TOOL_PARMS records
        Query  = 'SELECT TOOL_PARMS WITH REACTOR EQ ':ReactorNo:' AND WITH PSN EQ ':PSN:' BY-DSND DATETIME'
        GoSub ClearCursors
        Set_Status(0)
        ErrorCode = ''
        RList(Query, TARGET_ACTIVELIST$, '', '' '')
        If Get_Status(ErrorCode) then
            ErrorMsg = 'Error calling RList(): error code ':ErrorCode
            Error_Services('Add', ErrorMsg)
            return
        end
        Done            = False$
        InternalDTMList = ''
        ExternalDTMList = ''
        Loop
            Readnext ToolParmKey Else Done = True$
        Until Done
            ThisDTM             = ToolParmKey[-1, 'B*']
            InternalDTMList<-1> = ThisDTM
            ExternalDTMList<-1> = OConv(ThisDTM,'DT/^3HS')
        Repeat
        
        If ExternalDTMList NE '' then
            // TOOL_PARM records found -> Populate form with the latest configuration.
            Set_Property(@Window : '.COMBO_PARM_DTM', 'LIST', ExternalDTMList)
            MostRecentInternalDTM = InternalDTMList<1>
            MostRecentExternalDTM = ExternalDTMList<1>
            Set_Property(@Window : '.COMBO_PARM_DTM', 'TEXT', MostRecentExternalDTM)
                   
            // Read most recent Tool Parameter record
            ToolParmKey = PSN:'*':ReactorNo:'*':MostRecentInternalDTM
            ToolParmRec = Database_Services('ReadDataRow', 'TOOL_PARMS', ToolParmKey)
        end else
            // Datetime query returned zero records, therefore there are no configuration records for this
            // reactor, recipe, and PSN combination. Query RDS table for the most recent RDS that matches this 
            // criteria to reference as the last known configuration. Then create and save the configuration
            // record to the TOOL_PARMS database table.
            MsgDef = ''
            MsgDef<MTEXT$> = 'Building tool parameter record.' :@SVM: 'Please wait...'
            MsgDef<MTYPE$> = 'U'
            MsgDef<MJUST$> = 'C'
            MsgUp = Msg(@Window, MsgDef)
            NewToolParmKey = Tool_Parms_Services('CreateToolParmsRec', PSN, ReactorNo)
            Msg(@Window, MsgUp)
            NewToolParmDTM  = Field(NewToolParmKey, '*', 3)
            ExternalDTM     = OConv(NewToolParmDTM, 'DT/^3HS')   
            InternalDTMList = NewToolParmDTM
            ExternalDTMList = ExternalDTM
            Set_Property(@Window : '.COMBO_PARM_DTM', 'TEXT', ExternalDTM)
            Set_Property(@Window : '.COMBO_PARM_DTM', 'LIST', ExternalDTM)  
        end
        // Save internal and external Datetime lists for use elsewhere. This is necessary to correctly
        // identify records due to floating point rounding errors associated with Datetime types.
        Set_Property(@Window, '@INTERNALDTMS', InternalDTMList)
        Set_Property(@Window, '@EXTERNALDTMS', ExternalDTMList)
        
    end
    
return


FillPSNInfo:
    
    StartDate     = Date() - 30
    SelReactor    = Get_Property(@Window : '.COMBO_REACTOR', 'TEXT')
    WorkOrderList = ''
    PSNList       = ''
    SchedDetKeys = Schedule_Services('GetScheduleDetailKeys', StartDate, '', SelReactor, '', '')
    For each SchedDetKey in SchedDetKeys
        SchedDet = Schedule_Services('GetScheduleDetail', SchedDetKey)
        ThisWorkOrder = SchedDet<SCHED_DET_WO_NO$>
        Locate ThisWorkOrder in WorkOrderList using @FM setting fPos else
            WorkOrderList<-1> = ThisWorkOrder
            ThisProdVer       = Xlate('WO_LOG', ThisWorkOrder, 'PROD_VER_NO', 'X')
            ThisPSN           = Xlate('PROD_VER', ThisProdVer, 'PROC_STEP_PSN', 'X')
            Locate ThisPSN in PSNList using @FM Setting pPos else
                PSNList<-1>       = ThisPSN
            end
        end
    Next SchedDetKey
    // Add most recent RDS' PSN in case it was not found in the schedule.
    // This would occur if the user manually entered a PSN that is not on the schedule.
    MostRecentPSN = Get_Property(@Window : '.COMBO_PSN', 'TEXT')
    Locate MostRecentPSN in PSNList using @FM setting pPos else
        PSNList<-1> = MostRecentPSN
    end
    SortedPSNList = SRP_Sort_Array(PSNList, 'DR1', 1)   
    Set_Property(@Window : '.COMBO_PSN', 'LIST', SortedPSNList)
    
return


FillForm:

    ReactorNo     = Get_Property(@Window : '.COMBO_REACTOR', 'TEXT')
    DailySchedKey = 'WO_DAILY_SCHED':ReactorNo
	DailySchedRec = Database_Services('ReadDataRow', 'CONFIG', DailySchedKey)
	WorkOrderCust = DailySchedRec<WOCust$>
	WorkOrderNo   = FIELD(WorkOrderCust, ' ', 1)
    PSN           = Xlate('WO_LOG', WorkOrderNo, 'PS_NO', 'X')
    PRSLayerKey   = Xlate('PROD_SPEC', PSN, 'PRS_LAYER_KEY', 'X')
    FirstLayerKey = PRSLayerKey<1,1>
    RecipeID      = Xlate('PRS_LAYER', FirstLayerKey, 'RECIPE_ID', 'X')
      
    If ReactorNo NE '' and PSN NE '' and RecipeID NE '' then
        
        // Fill most recent PSN, Recipe, and DateTime associated with the selected reactor
        Set_Property(@Window : '.COMBO_PSN', 'TEXT', PSN)
        Set_Property(@Window : '.EDL_RECIPE', 'TEXT', RecipeID)
        
        GoSub FillPSNInfo
        GoSub FillRecipeInfo       
        GoSub FillDatetimeInfo       
        GoSub FillRecipeParms       
        GoSub FillRecipeLimits       
        GoSub FormatEditTableColumns
             
    end
    
return


FillRecipeParms:

    ReactorNo           = Get_Property(@Window : '.COMBO_REACTOR', 'TEXT')
    PSN                 = Get_Property(@Window : '.COMBO_PSN', 'TEXT')
    ExternalDTM         = Get_Property(@Window : '.COMBO_PARM_DTM', 'TEXT')
    InternalDTMList     = Get_Property(@Window, '@INTERNALDTMS')
    ExternalDTMList     = Get_Property(@Window, '@EXTERNALDTMS')
    InternalDTM         = ''
    Locate ExternalDTM in ExternalDTMList using @FM setting fPos then
        InternalDTM = InternalDTMList<fPos>
    end
    
    ToolParmKey   = PSN:'*':ReactorNo:'*':InternalDTM
    ToolParmRec   = Database_Services('ReadDataRow', 'TOOL_PARMS', ToolParmKey)
    If ToolParmRec NE '' then
        
        RecipeParmsArray = ''
        RecipeLayerKeys = ToolParmRec<TOOL_PARMS.LS_ID$>
        
        For each LayerKey in RecipeLayerKeys using @VM setting vPos
                        
            RecipeParmsArray<COL.LAYER_ID   , vPos> = LayerKey
            RecipeParmsArray<COL.DEPOSIT    , vPos> = ToolParmRec<TOOL_PARMS.EPI_TIME$, vPos>
            RecipeParmsArray<COL.DILUENT    , vPos> = ToolParmRec<TOOL_PARMS.DILUENT_ADJ_PARAM$, vPos> 
            RecipeParmsArray<COL.DOPANT_FLOW, vPos> = ToolParmRec<TOOL_PARMS.DOPANT_FLOW$, vPos>
            RecipeParmsArray<COL.HCL_FLOW   , vPos> = ToolParmRec<TOOL_PARMS.HCL_FLOW$, vPos>
            RecipeParmsArray<COL.BAKE_TIME  , vPos> = ToolParmRec<TOOL_PARMS.BAKE_TIME$, vPos>
            RecipeParmsArray<COL.H2_FLOW    , vPos> = ToolParmRec<TOOL_PARMS.EPI_H2_FLOW$, vPos>
            RecipeParmsArray<COL.TCS_FLOW   , vPos> = ToolParmRec<TOOL_PARMS.TCS_FLOW$, vPos>
            RecipeParmsArray<COL.DCS_FLOW   , vPos> = ToolParmRec<TOOL_PARMS.DCS_FLOW$, vPos>
            RecipeParmsArray<COL.AUX_1_FLOW , vPos> = ToolParmRec<TOOL_PARMS.AUX1$, vPos>
            RecipeParmsArray<COL.AUX_2_FLOW , vPos> = ToolParmRec<TOOL_PARMS.AUX2$, vPos>
            RecipeParmsArray<COL.F_OFFSET   , vPos> = ToolParmRec<TOOL_PARMS.F_OFFSET$, vPos>
            RecipeParmsArray<COL.S_OFFSET   , vPos> = ToolParmRec<TOOL_PARMS.S_OFFSET$, vPos>
            RecipeParmsArray<COL.R_OFFSET   , vPos> = ToolParmRec<TOOL_PARMS.R_OFFSET$, vPos>
            RecipeParmsArray<COL.SUSC_ETCH  , vPos> = ToolParmRec<TOOL_PARMS.SUSC_ETCH$, vPos>
            RecipeParmsArray<COL.ETCH_1     , vPos> = ToolParmRec<TOOL_PARMS.ETCH1$, vPos>
            RecipeParmsArray<COL.ETCH_2     , vPos> = ToolParmRec<TOOL_PARMS.ETCH2$, vPos>
            RecipeParmsArray<COL.ETCH_3     , vPos> = ToolParmRec<TOOL_PARMS.ETCH3$, vPos>
            RecipeParmsArray<COL.UNLOAD_TEMP, vPos> = ToolParmRec<TOOL_PARMS.UNLOAD_TEMP$, vPos>
            
        Next LayerKey
        
        Set_Property(@Window : '.EDT_RECIPE_PARMS', 'ARRAY', RecipeParmsArray)
    end
    
return


FillRecipeLimits:

    PSN         = Get_Property(@Window : '.COMBO_PSN', 'TEXT')
    RecipeID    = Get_Property(@Window : '.EDL_RECIPE', 'TEXT')
    RecipeRec   = Database_Services('ReadDataRow', 'RECIPE', RecipeID)
    RecipeParms = Get_Property(@Window : '.EDT_RECIPE_PARMS', 'ARRAY')
    LayerIDs    = ''
    If RecipeParms NE '' then
        LayerIDs    = RecipeParms<COL.LAYER_ID>
    end else
        // New Tool Parms record -> fetch recipe layer ids
        PRSLayerNos = Xlate('PROD_SPEC', PSN, 'LAYER_NO', 'X')
        For each LayerNo in PRSLayerNos using @VM setting vPos
            PRSLayerKey = PSN:'*':LayerNo
            LSID = Xlate('PRS_LAYER', PRSLayerKey, 'LS_ID', 'X')
            LayerIDs<1,-1> = LSID
        Next LayerNo
        // Fill Recipe Parms edit table layer IDs for user
        Set_Property(@Window : '.EDT_RECIPE_PARMS', 'ARRAY', LayerIDs)
    end
    
    LimitsArray = ''
    
    For each LayerID in LayerIDs using @VM setting LayerIndex
        
        RecipeLimits = Obj_Recipe('GetLimits', RecipeID:@RM:PSN:@RM:LayerID)
        
        LimitsArray<COL.LAYER_ID   , LayerIndex> = LayerID
        
        If RecipeLimits<RP_DEPOSIT_TIME_MIN$> NE '' or RecipeLimits<RP_DEPOSIT_TIME_MAX$> NE '' then
            Deposit = OCONV(RecipeLimits<RP_DEPOSIT_TIME_MIN$>:@SVM:RecipeLimits<RP_DEPOSIT_TIME_MAX$>,'MD1')
            Swap @SVM with ' ~ ' in Deposit
        end else
            Deposit = ''
        end
        
        If RecipeLimits<RP_DILUENT_FLOW_MIN$> NE '' or RecipeLimits<RP_DILUENT_FLOW_MAX$> NE '' then
            Diluent = OCONV(RecipeLimits<RP_DILUENT_FLOW_MIN$>:@SVM:RecipeLimits<RP_DILUENT_FLOW_MAX$>,'MD2')
            Swap @SVM with ' ~ ' in Diluent
        end else
            Diluent = ''
        end
        
        If RecipeLimits<RP_DOPANT_FLOW_MAX$> NE '' or RecipeLimits<RP_DOPANT_FLOW_MAX$> NE '' then
            DopantFlow = OCONV(RecipeLimits<RP_DOPANT_FLOW_MIN$>:@SVM:RecipeLimits<RP_DOPANT_FLOW_MAX$>,'MD2')
            Swap @SVM with ' ~ ' in DopantFlow
        end else
            DopantFlow = ''
        end
        
        If RecipeLimits<RP_HCL_FLOW_MIN$> NE '' or RecipeLimits<RP_HCL_FLOW_MAX$> NE '' then
            HCLFlow = OCONV(RecipeLimits<RP_HCL_FLOW_MIN$>:@SVM:RecipeLimits<RP_HCL_FLOW_MAX$>,'MD2')
            Swap @SVM with ' ~ ' in HCLFlow
        end else
            HCLFlow = ''
        end
        
        If RecipeLimits<RP_BAKE_TIME_MIN$> NE '' or RecipeLimits<RP_BAKE_TIME_MAX$> NE '' then
            BakeTime = OCONV(RecipeLimits<RP_BAKE_TIME_MIN$>:@SVM:RecipeLimits<RP_BAKE_TIME_MAX$>,'[SECONDS_CONV]')
            Swap @SVM with ' ~ ' in BakeTime
        end else
            BakeTime = ''
        end
        
        If RecipeLimits<RP_H2_FLOW_MIN$> NE '' or RecipeLimits<RP_H2_FLOW_MAX$> NE '' then
            H2Flow = OCONV(RecipeLimits<RP_H2_FLOW_MIN$>:@SVM:RecipeLimits<RP_H2_FLOW_MAX$>,'MD0')
            Swap @SVM with ' ~ ' in H2Flow
        end else
            H2Flow = ''
        end
        
        If RecipeLimits<RP_TCS_FLOW_MIN$> NE '' or RecipeLimits<RP_TCS_FLOW_MAX$> NE '' then
            TCSFlow = OCONV(RecipeLimits<RP_TCS_FLOW_MIN$>:@SVM:RecipeLimits<RP_TCS_FLOW_MAX$>,'MD1')
            Swap @SVM with ' ~ ' in TCSFlow
        end else
            TCSFlow = ''
        end
        
        If RecipeLimits<RP_DCS_FLOW_MIN$> NE '' or RecipeLimits<RP_DCS_FLOW_MAX$> NE '' then
            DCSFlow = OCONV(RecipeLimits<RP_DCS_FLOW_MIN$>:@SVM:RecipeLimits<RP_DCS_FLOW_MAX$>,'MD0')
            Swap @SVM with ' ~ ' in DCSFlow
        end else
            DCSFlow = ''
        end
        
        If RecipeLimits<RP_AUX1_FLOW_MIN$> NE '' or RecipeLimits<RP_AUX1_FLOW_MAX$> NE '' then
            AUX1Flow = OCONV(RecipeLimits<RP_AUX1_FLOW_MIN$>:@SVM:RecipeLimits<RP_AUX1_FLOW_MAX$>,'MD2')
            Swap @SVM with ' ~ ' in AUX1Flow
        end else
            AUX1Flow = ''
        end
        
        If RecipeLimits<RP_AUX2_FLOW_MIN$> NE '' or RecipeLimits<RP_AUX2_FLOW_MAX$> NE '' then
            AUX2Flow = OCONV(RecipeLimits<RP_AUX2_FLOW_MIN$>:@SVM:RecipeLimits<RP_AUX2_FLOW_MAX$>,'MD2')
            Swap @SVM with ' ~ ' in AUX2Flow
        end else
            AUX2Flow = ''
        end
        
        If RecipeLimits<RP_FOFFSET_MIN$> NE '' or RecipeLimits<RP_FOFFSET_MAX$> NE '' then
            FOffset = OCONV(RecipeLimits<RP_FOFFSET_MIN$>:@SVM:RecipeLimits<RP_FOFFSET_MAX$>,'MD0')
            Swap @SVM with ' ~ ' in FOffset
        end else
            FOffset = ''
        end
        
        If RecipeLimits<RP_SOFFSET_MIN$> NE '' or RecipeLimits<RP_SOFFSET_MAX$> NE '' then
            SOffset = OCONV(RecipeLimits<RP_SOFFSET_MIN$>:@SVM:RecipeLimits<RP_SOFFSET_MAX$>,'MD0')
            Swap @SVM with ' ~ ' in SOffset
        end else
            SOffset = ''
        end
        
        If RecipeLimits<RP_ROFFSET_MIN$> NE '' or RecipeLimits<RP_ROFFSET_MAX$> NE '' then
            ROffset = OCONV(RecipeLimits<RP_ROFFSET_MIN$>:@SVM:RecipeLimits<RP_ROFFSET_MAX$>,'MD0')
            Swap @SVM with ' ~ ' in ROffset
        end else
            ROffset = ''
        end
        
        If RecipeLimits<RP_SUSC_ETCH_MIN$> NE '' or RecipeLimits<RP_SUSC_ETCH_MAX$> NE '' then
            SuscEtch = OCONV(RecipeLimits<RP_SUSC_ETCH_MIN$>:@SVM:RecipeLimits<RP_SUSC_ETCH_MAX$>,'MD1')
            Swap @SVM with ' ~ ' in SuscEtch
        end else
            SuscEtch = ''
        end
        
        If RecipeLimits<RP_ETCH1_MIN$> NE '' or RecipeLimits<RP_ETCH1_MAX$> NE '' then
            Etch1 = OCONV(RecipeLimits<RP_ETCH1_MIN$>:@SVM:RecipeLimits<RP_ETCH1_MAX$>,'[SECONDS_CONV]')
            Swap @SVM with ' ~ ' in Etch1
        end else
            Etch1 = ''
        end
        
        If RecipeLimits<RP_ETCH2_MIN$> NE '' or RecipeLimits<RP_ETCH2_MAX$> NE '' then
            Etch2 = OCONV(RecipeLimits<RP_ETCH2_MIN$>:@SVM:RecipeLimits<RP_ETCH2_MAX$>,'[SECONDS_CONV]')
            Swap @SVM with ' ~ ' in Etch2
        end else
            Etch2 = ''
        end
        
        If RecipeLimits<RP_ETCH3_MIN$> NE '' or RecipeLimits<RP_ETCH3_MAX$> NE '' then
            Etch3 = OCONV(RecipeLimits<RP_ETCH3_MIN$>:@SVM:RecipeLimits<RP_ETCH3_MAX$>,'[SECONDS_CONV]')
            Swap @SVM with ' ~ ' in Etch3
        end else
            Etch3 = ''
        end
        
        If RecipeLimits<RP_UL_TEMP_MIN$> NE '' or RecipeLimits<RP_UL_TEMP_MAX$> NE '' then
            UnloadTemp = OCONV(RecipeLimits<RP_UL_TEMP_MIN$>:@SVM:RecipeLimits<RP_UL_TEMP_MAX$>,'MD0')
            Swap @SVM with ' ~ ' in UnloadTemp
        end else
            UnloadTemp = ''
        end
        
        LimitsArray<COL.DEPOSIT    , LayerIndex> = Deposit
        LimitsArray<COL.DILUENT    , LayerIndex> = Diluent 
        LimitsArray<COL.DOPANT_FLOW, LayerIndex> = DopantFlow
        LimitsArray<COL.HCL_FLOW   , LayerIndex> = HCLFlow
        LimitsArray<COL.BAKE_TIME  , LayerIndex> = BakeTime
        LimitsArray<COL.H2_FLOW    , LayerIndex> = H2Flow
        LimitsArray<COL.TCS_FLOW   , LayerIndex> = TCSFlow
        LimitsArray<COL.DCS_FLOW   , LayerIndex> = DCSFlow
        LimitsArray<COL.AUX_1_FLOW , LayerIndex> = AUX1Flow
        LimitsArray<COL.AUX_2_FLOW , LayerIndex> = AUX2Flow
        LimitsArray<COL.F_OFFSET   , LayerIndex> = FOffset
        LimitsArray<COL.S_OFFSET   , LayerIndex> = SOffset
        LimitsArray<COL.R_OFFSET   , LayerIndex> = ROffset
        LimitsArray<COL.SUSC_ETCH  , LayerIndex> = SuscEtch
        LimitsArray<COL.ETCH_1     , LayerIndex> = Etch1
        LimitsArray<COL.ETCH_2     , LayerIndex> = Etch2
        LimitsArray<COL.ETCH_3     , LayerIndex> = Etch3
        LimitsArray<COL.UNLOAD_TEMP, LayerIndex> = UnloadTemp
            
    Next LayerID
    
    Set_Property(@Window : '.EDT_RECIPE_LIMITS', 'ARRAY', LimitsArray)
      
return


FormatEditTableColumns:
    
    RecipeParms     = Get_Property(@Window : '.EDT_RECIPE_PARMS', 'ARRAY')
    RecipeLimits    = Get_Property(@Window : '.EDT_RECIPE_LIMITS', 'ARRAY')
    ParameterStyles	= Send_Message(@Window : '.EDT_RECIPE_PARMS', 'COLSTYLE', 0, '')
    LimitStyles		= Send_Message(@Window : '.EDT_RECIPE_LIMITS', 'COLSTYLE', 0, '')
    ColNames	    = 'LS_ID':@FM:'EPI_TIME':@FM:'DILUENT_ADJ_PARAM':@FM:'DOPANT_FLOW':@FM:'HCL_FLOW':@FM
    ColNames       := 'BAKE_TIME':@FM:'EPI_H2_FLOW':@FM:'TCS_FLOW':@FM:'DCS_FLOW':@FM:'AUX1':@FM:'AUX2':@FM:'F_OFFSET'
    ColNames       := @FM:'S_OFFSET':@FM:'R_OFFSET':@FM:'SUSC_ETCH':@FM:'ETCH1':@FM:'ETCH2':@FM:'ETCH3':@FM:'UNLOAD_TEMP'

    For each ColName in ColNames using @FM Setting Col
        RecipeLimitsColData = RecipeLimits<Col>
        RecipeParmsColData  = RecipeParms<Col>
        Convert @VM to '' in RecipeLimitsColData
        Convert @VM to '' in RecipeParmsColData
        If RecipeLimitsColData = '' and RecipeParmsColData = '' then
            ParameterStyles<Col>	= BitOr( ParameterStyles<Col>, HIDDEN$ )				;* Column not used -> Hide
            LimitStyles<Col>		= BitOr( LimitStyles<Col>, HIDDEN$ )
        end else
            ParameterStyles<Col>	= BitAnd( ParameterStyles<Col>, BitNot(HIDDEN$) )		;* Column used -> Show
            LimitStyles<Col>		= BitAnd( LimitStyles<Col>, BitNot(HIDDEN$) )            
            ParamData	= RecipeParms<Col>
            Conversion	= Xlate('DICT.TOOL_PARMS', ColName, DICT_CONV$, 'X')            
            If Conversion NE '' then
                ParamData = OConv(ParamData, Conversion)
                RecipeParms<Col> = ParamData
            end           
        end
    next ColName
      
    ParameterStyles	= Send_Message(@WINDOW : '.EDT_RECIPE_PARMS', 'COLSTYLE', 0, ParameterStyles)
    LimitStyles		= Send_Message(@WINDOW : '.EDT_RECIPE_LIMITS', 'COLSTYLE', 0, LimitStyles)	   
    Set_Property(@Window : '.EDT_RECIPE_PARMS', 'ARRAY', RecipeParms)
*    Set_Property(@Window : '.EDT_RECIPE_PARMS', 'AUTOSIZECOL', 16 )
*    Set_Property(@Window : '.EDT_RECIPE_LIMITS', 'AUTOSIZECOL', 16 )
    Set_Property(@Window, '@ORIGPARMSARRAY', RecipeParms)
    Set_Property(@Window : '.EDT_RECIPE_PARMS', 'MODIFIED', False$)
    
return
