Function WO_Scheduler_Events(CtrlEntId, Event, Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15)
/***********************************************************************************************************************

    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        :   WO_Scheduler_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)
        06/01/17    dmb     Created initial commuter module.

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

#pragma precomp SRP_PreCompiler
#Window WO_SCHEDULER

$insert APP_INSERTS
$insert EVENT_SETUP
$insert MSG_EQUATES
$insert SCHED_DET_EQUATES
$insert WO_LOG_EQUATES
$insert PRS_LAYER_EQU
$insert POPUP_EQUATES
$insert SECURITY_RIGHTS_EQU
$insert REACTOR_EQUATES
$insert WO_STEP_EQUATES
$insert SCHEDULE_EVENT_SUMMMARY_EQUATES
Equ LightGrey$  TO 239 + (239*256) + (239*65536)

Declare function    SRP_CodeCombo, SRP_Array, Schedule_Services, Epi_Part_Services, MemberOf, Reactor_Services, SRP_JSON
Declare function    EntId, MemberOf, Repository, Security_Check, Security_Err_Msg, Obj_Prod_Spec, Rds_Supplement_Maint
Declare function    Scheduling_Services
Declare subroutine  SRP_CodeCombo, obj_Appwindow, Schedule_Services, Epi_Part_Services, SRP_Stopwatch, SRP_JSON
Declare subroutine  Security_Err_Msg, Start_Window

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

Return EventFlow else EVENT_CONTINUE$


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Events
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Event WINDOW.CREATE(CreateParam)

    // Update UI based on security membership rights.
    Begin Case
        Case MemberOf(@USER4, 'SCHEDULER_ADMIN')
            // Allowed to access everything.

        Case MemberOf(@USER4, 'SCHEDULER_MASTER')
            // Reactor utilization is view only.

            Set_Property(@Window : '.EDL_ASM_UTILIZATION', 'ENABLED', False$)
            Set_Property(@Window : '.EDL_ASM_UTILIZATION', 'BACKCOLOR', LightGrey$)
            Size    = Get_Property(@Window : '.EDL_ASM_UTILIZATION', 'SIZE')
            Size<3> = Size<3> + 48
            Set_Property(@Window : '.EDL_ASM_UTILIZATION', 'SIZE', Size)
            Set_Property(@Window : '.OLE_PUB_UPDATE_ASM_UTILIZATION', 'VISIBLE', False$)
            Set_Property(@Window : '.EDL_ASM_PLUS_UTILIZATION', 'ENABLED', False$)
            Set_Property(@Window : '.EDL_ASM_PLUS_UTILIZATION', 'BACKCOLOR', LightGrey$)
            Size    = Get_Property(@Window : '.EDL_ASM_PLUS_UTILIZATION', 'SIZE')
            Size<3> = Size<3> + 48
            Set_Property(@Window : '.EDL_ASM_PLUS_UTILIZATION', 'SIZE', Size)
            Set_Property(@Window : '.OLE_PUB_UPDATE_ASM_PLUS_UTILIZATION', 'VISIBLE', False$)
            Set_Property(@Window : '.EDL_HTR_UTILIZATION', 'ENABLED', False$)
            Set_Property(@Window : '.EDL_HTR_UTILIZATION', 'BACKCOLOR', LightGrey$)
            Size    = Get_Property(@Window : '.EDL_HTR_UTILIZATION', 'SIZE')
            Size<3> = Size<3> + 48
            Set_Property(@Window : '.EDL_HTR_UTILIZATION', 'SIZE', Size)
            Set_Property(@Window : '.OLE_PUB_UPDATE_HTR_UTILIZATION', 'VISIBLE', False$)
            Set_Property(@Window : '.EDL_EPIPRO_UTILIZATION', 'ENABLED', False$)
            Set_Property(@Window : '.EDL_EPIPRO_UTILIZATION', 'BACKCOLOR', LightGrey$)
            Size    = Get_Property(@Window : '.EDL_EPIPRO_UTILIZATION', 'SIZE')
            Size<3> = Size<3> + 48
            Set_Property(@Window : '.EDL_EPIPRO_UTILIZATION', 'SIZE', Size)
            Set_Property(@Window : '.OLE_PUB_UPDATE_EPIPRO_UTILIZATION', 'VISIBLE', False$)
            Set_Property(@Window : '.EDL_GAN_UTILIZATION', 'ENABLED', False$)
            Set_Property(@Window : '.EDL_GAN_UTILIZATION', 'BACKCOLOR', LightGrey$)
            Size    = Get_Property(@Window : '.EDL_GAN_UTILIZATION', 'SIZE')
            Size<3> = Size<3> + 48
            Set_Property(@Window : '.EDL_GAN_UTILIZATION', 'SIZE', Size)
            Set_Property(@Window : '.OLE_PUB_UPDATE_GAN_UTILIZATION', 'VISIBLE', False$)

        Case Otherwise$
            // Reactor utilization is not visible.

            Set_Property(@Window : '.OLE_DIV_REACTOR_TYPE_UTILIZATION', 'VISIBLE', False$)
            Set_Property(@Window : '.STA_ASM_UTILIZATION', 'VISIBLE', False$)
            Set_Property(@Window : '.EDL_ASM_UTILIZATION', 'VISIBLE', False$)
            Set_Property(@Window : '.OLE_PUB_UPDATE_ASM_UTILIZATION', 'VISIBLE', False$)
            Set_Property(@Window : '.STA_ASM_PLUS_UTILIZATION', 'VISIBLE', False$)
            Set_Property(@Window : '.EDL_ASM_PLUS_UTILIZATION', 'VISIBLE', False$)
            Set_Property(@Window : '.OLE_PUB_UPDATE_ASM_PLUS_UTILIZATION', 'VISIBLE', False$)
            Set_Property(@Window : '.STA_HTR_UTILIZATION', 'VISIBLE', False$)
            Set_Property(@Window : '.EDL_HTR_UTILIZATION', 'VISIBLE', False$)
            Set_Property(@Window : '.OLE_PUB_UPDATE_HTR_UTILIZATION', 'VISIBLE', False$)
            Set_Property(@Window : '.STA_EPIPRO_UTILIZATION', 'VISIBLE', False$)
            Set_Property(@Window : '.EDL_EPIPRO_UTILIZATION', 'VISIBLE', False$)
            Set_Property(@Window : '.OLE_PUB_UPDATE_EPIPRO_UTILIZATION', 'VISIBLE', False$)
            Set_Property(@Window : '.STA_GAN_UTILIZATION', 'VISIBLE', False$)
            Set_Property(@Window : '.EDL_GAN_UTILIZATION', 'VISIBLE', False$)
            Set_Property(@Window : '.OLE_PUB_UPDATE_GAN_UTILIZATION', 'VISIBLE', False$)
            Size    = Get_Property(@Window : '.OLE_DIV_BOTTOM', 'SIZE')
            Size<2> = Size<2> - 162
            Set_Property(@Window : '.OLE_DIV_BOTTOM', 'SIZE', Size)
    End Case

    Set_Property(@Window, 'VISIBLE', 3)

 	GoSub Setup_OLE_Controls

    Set_Property('SYSTEM', 'BLOCK_EVENTS', True$)
    ASMUtil     = Epi_Part_Services('GetReactorUtilization', 'ASM')
    ASMPlusUtil = Epi_Part_Services('GetReactorUtilization', 'ASM+')
    HTRUtil     = Epi_Part_Services('GetReactorUtilization', 'HTR')
    EpiProUtil  = Epi_Part_Services('GetReactorUtilization', 'EpiPro')
    GaNUtil     = Epi_Part_Services('GetReactorUtilization', 'GaN')
    Set_Property(@Window : '.EDL_ASM_UTILIZATION', 'INVALUE', ASMUtil)
    Set_Property(@Window : '.EDL_ASM_PLUS_UTILIZATION', 'INVALUE', ASMPlusUtil)
    Set_Property(@Window : '.EDL_HTR_UTILIZATION', 'INVALUE', HTRUtil)
    Set_Property(@Window : '.EDL_EPIPRO_UTILIZATION', 'INVALUE', EpiProUtil)
    Set_Property(@Window : '.EDL_GAN_UTILIZATION', 'INVALUE', GaNUtil)
    Set_Property('SYSTEM', 'BLOCK_EVENTS', False$)

end event


Event EDL_REACTOR_FILTER.LOSTFOCUS(Flag, FocusID)

    PrevFilterType  = Get_Property(CtrlEntId, '@PREV_FILTER_TYPE')
    FilterType      = Get_Property(CtrlEntId, 'TEXT')
    If FilterType NE PrevFilterType then
        Begin Case
            Case FilterType _EQC 'Reactor Type'
                FilterOptions   = 'ASM'    : @FM
                FilterOptions  := 'ASM+'   : @FM
                FilterOptions  := 'HTR'    : @FM
                FilterOptions  := 'EpiPro' : @FM
                FilterOptions  := 'GaN'

            Case FilterType _EQC 'Reactor Assignment'
                FilterOptions   = 'Dedicated'      : @FM
                FilterOptions  := 'Non-Dedicated'  : @FM
                FilterOptions  := 'GaN'            : @FM
                FilterOptions  := 'Out of Service'

            Case FilterType _EQC 'Wafer Size'
                FilterOptions   = '125 mm 5 in' : @FM
                FilterOptions  := '150 mm 6 in' : @FM
                FilterOptions  := '200 mm 8 in' : @FM

            Case FilterType _EQC 'Cleanroom Area'
                FilterOptions   = 'Front-Evens'     : @FM
                FilterOptions  := 'Front-Odds'      : @FM
                FilterOptions  := 'Front-Evens-HTR' : @FM
                FilterOptions  := 'Front-Odds-HTR'  : @FM
                FilterOptions  := 'Tunnel'          : @FM
                FilterOptions  := 'EpiPro Room'     : @FM
                FilterOptions  := 'Back-Evens'      : @FM
                FilterOptions  := 'Back-Odds'       : @FM
                FilterOptions  := 'GaN'
        End Case
        Set_Property(CtrlEntId, '@PREV_FILTER_TYPE', FilterType)
        Ctrl        = @Window : '.OLE_TRE_REACTOR_FILTER_OPTIONS'
        ItemList    = ''
        For Each FilterOption in FilterOptions using @FM
            ItemList   := 1 : @VM : FilterOption : @VM : FilterOption : @VM : @VM : @VM : @VM : @VM : @VM : @VM : @VM : 'Left' : @FM
        Next FilterOption
        ItemList[-1, 1] = ''
        Set_Property(Ctrl, 'OLE.ItemList', ItemList)
        Set_Property(Ctrl, 'OLE.ItemChecked[All]', True$)
        Post_Event(Ctrl, 'OLE', 'OnItemCheck')
    end

end event


Event EDL_WORK_ORDER_SEARCH.LOSTFOCUS(Flag, FocusID)

    PrevWorkOrderNo     = Get_Property(CtrlEntId, '@PREV_WORK_ORDER_NO')
    SearchWorkOrderNo   = Get_Property(CtrlEntId, 'TEXT')
    If SearchWorkOrderNo NE PrevWorkOrderNo then
        // Restore already selected appointments to their normal backcolor.
        Set_Property(@Window, 'REDRAW', False$)
        SearchApptIDs   = Get_Property(@Window : '.OLE_SCHEDULE', '@SELECTED_KEYIDS')
        If SearchApptIDs NE '' then
            For Each ApptID in SearchApptIDs using @FM
                Appt            = Get_Property(@Window : '.OLE_SCHEDULE', 'OLE.Appt[' : ApptID : ']')
                ScheduleEvent   = Appt<18>
                GoSub ParseScheduleEvent
                Appt<4>         = BackColor
                Appt<5>         = 'Black'
                Set_Property(@Window : '.OLE_SCHEDULE', 'OLE.Appt[' : ApptID : ']', Appt)
                SearchApptIDs  := ApptID : @FM
            Next ApptID
        end
        SearchApptIDs       = ''
        AppointmentList     = Get_Property(@Window : '.OLE_SCHEDULE', 'OLE.AppointmentList')
        AppointmentArray    = SRP_Array('Rotate', AppointmentList, @FM, @VM)
        AllApptIDs          = AppointmentArray<2>
        For Each ApptID in AllApptIDs using @VM setting vPos
*            ScheduleEvent   = Get_Property(@Window : '.OLE_SCHEDULE', 'OLE.ApptClass[' : ApptID : ']')
            Appt            = Get_Property(@Window : '.OLE_SCHEDULE', 'OLE.Appt[' : ApptID : ']')
            ScheduleEvent   = Appt<18>
            GoSub ParseScheduleEvent
            If WorkOrderNo EQ SearchWorkOrderNo then
                Appt<4>     = BackColor : ' L=40'
                Appt<5>     = 'White'
                Set_Property(@Window : '.OLE_SCHEDULE', 'OLE.Appt[' : ApptID : ']', Appt)
                SearchApptIDs  := ApptID : @FM
            end
        Next ApptID
        SearchApptIDs[-1, 1]    = ''
        Set_Property(@Window : '.OLE_SCHEDULE', '@SELECTED_KEYIDS', SearchApptIDs)
        Send_Message(@Window : '.OLE_SCHEDULE', 'OLE.EnsureVisible', SearchApptIDs<1>)
        Set_Property(@Window : '.OLE_SCHEDULE', 'OLE.SelAppt[' : SearchApptIDs<1> : ']')
        Set_Property(CtrlEntId, '@PREV_WORK_ORDER_NO', SearchWorkOrderNo)
        Set_Property(@Window : '.EDL_EPI_PART_SEARCH', 'TEXT', '')
        Set_Property(@Window, 'REDRAW', True$)
    end

end event


Event EDL_EPI_PART_SEARCH.LOSTFOCUS(Flag, FocusID)

    PrevEpiPartNo   = Get_Property(CtrlEntId, '@PREV_EPI_PART_NO')
    SearchEpiPartNo = Get_Property(CtrlEntId, 'TEXT')
    If SearchEpiPartNo NE PrevEpiPartNo then
        // Restore already selected appointments to their normal backcolor.
        Set_Property(@Window, 'REDRAW', False$)
        SearchApptIDs   = Get_Property(@Window : '.OLE_SCHEDULE', '@SELECTED_KEYIDS')
        If SearchApptIDs NE '' then
            For Each ApptID in SearchApptIDs using @FM
                Appt            = Get_Property(@Window : '.OLE_SCHEDULE', 'OLE.Appt[' : ApptID : ']')
                ScheduleEvent   = Appt<18>
                GoSub ParseScheduleEvent
                Appt<4>     = BackColor
                Appt<5>     = 'Black'
                Set_Property(@Window : '.OLE_SCHEDULE', 'OLE.Appt[' : ApptID : ']', Appt)
                SearchApptIDs  := ApptID : @FM
            Next ApptID
        end
        SearchApptIDs       =''
        AppointmentList     = Get_Property(@Window : '.OLE_SCHEDULE', 'OLE.AppointmentList')
        AppointmentArray    = SRP_Array('Rotate', AppointmentList, @FM, @VM)
        AllApptIDs          = AppointmentArray<2>
        For Each ApptID in AllApptIDs using @VM setting vPos
*            ScheduleEvent   = Get_Property(@Window : '.OLE_SCHEDULE', 'OLE.ApptClass[' : ApptID : ']')
            Appt            = Get_Property(@Window : '.OLE_SCHEDULE', 'OLE.Appt[' : ApptID : ']')
            ScheduleEvent   = Appt<18>
            GoSub ParseScheduleEvent
            If EpiPartNo EQ SearchEpiPartNo then
                Appt<4>     = BackColor : ' L=40'
                Appt<5>     = 'White'
                Set_Property(@Window : '.OLE_SCHEDULE', 'OLE.Appt[' : ApptID : ']', Appt)
                SearchApptIDs  := ApptID : @FM
            end
        Next ApptID
        SearchApptIDs[-1, 1]    = ''
        Set_Property(@Window : '.OLE_SCHEDULE', '@SELECTED_KEYIDS', SearchApptIDs)
        Send_Message(@Window : '.OLE_SCHEDULE', 'OLE.EnsureVisible', SearchApptIDs<1>)
        Set_Property(@Window : '.OLE_SCHEDULE', 'OLE.SelAppt[' : SearchApptIDs<1> : ']')
        Set_Property(CtrlEntId, '@PREV_EPI_PART_NO', SearchEpiPartNo)
        Set_Property(@Window : '.EDL_WORK_ORDER_SEARCH', 'TEXT', '')
        Set_Property(@Window, 'REDRAW', True$)
    end

end event


Event OLE_SCHEDULE.OnApptDblClick(ApptID, Button, Shift, Ctrl)

    If Button EQ 'Left' then
        ReactorNo       = ApptID[1, '*']
        Date            = ApptID[Col2() + 1, '*']
        Sequence        = ApptID[Col2() + 1, '*']
        ScheduleEvent   = Scheduling_Services('GetScheduleEvent', ReactorNo, Date, Sequence, True$)
        GoSub ParseScheduleEvent

        WOStepKey = WorkOrderNo : '*1'

        PopupId = entid( @appid<1>, 'POPUP', '', 'DAILY_SCHED_OPTS' )
        OverRide = ''
        Display = xlate( 'SYSREPOSPOPUPS', 'LSL2**DAILY_SCHED_OPTS', pdisplay$, 'X' )
        if MemberOf(@USER4, 'ENGINEERING') OR MemberOf(@USER4, 'SUPERVISOR') OR MemberOf(@USER4, 'LEAD') then			;* Added LEAD security group to allow asign supplements -dkk 12/5/14
           * ADD OPTION TO ASSIGN SUPPLEMENTS
           Display := @vm:'Assign Supplements':@tm:'SUPPLEMENTS'
        end

        OverRide<Pdisplay$> = Display

        ChosenOpt = repository( 'EXECUTE', PopupId, @window, OverRide )

        RdsKeys = ''
        BEGIN CASE

            CASE ChosenOpt = 'QUOTE'
                IF security_check( 'Quote', Read$ ) THEN
                    WORec = XLATE('WO_LOG',WorkOrderNo,'','X')
                    OrderNo = WORec<WO_LOG_ORDER_NO$>
                    OrderItemNos = WORec<WO_LOG_ORDER_ITEM$>
                    QuoteNo = XLATE('ORDER_DET',OrderNo:'*':OrderItemNos<1,1>,1,'X')
                    Void = start_window( 'QUOTE2', @window, QuoteNo:'*CENTER', '', '' )
                END ELSE
                    security_err_msg( 'Quote', Read$ )
                END
                     
            CASE ChosenOpt = 'PSN'
                IF security_check( 'Prod Spec', Read$ ) THEN   

                    PSNId = XLATE('WO_STEP',WOStepKey,WO_STEP_PROD_SPEC_ID$,'X')
                    Void = start_window( 'PROD_SPEC', @window, PSNId:'*CENTER', '', '' )
                END ELSE
                    security_err_msg( 'Prod Spec', Read$ )      
                END
                      
            CASE ChosenOpt = 'RECIPE'
                if security_check( 'Recipe', Read$ ) then 
                       
                    PSN = XLATE('WO_STEP',WOStepKey,1,'X')

                    LayerSpecs = obj_Prod_Spec('GetLayerProp',PSN:@RM:@RM:1)	;* Returns specs for all layers in internal format

                    LayerSpec 	= FIELD(LayerSpecs,@RM,1)				;* Take the first Layer
                    LayerSet	= FIELD(LayerSpec,@FM,1)				;* Not used here but shown for clarity
                    LayerSpec	= FIELD(LayerSpec,@FM,2,99)				;* LayerSpec without the LayerSet 

                    RecipeNo = LayerSpec<PRS_LAYER_RECIPE$>
                    Void = start_window( 'RECIPE', @window, RecipeNo:'*CENTER', '', '' )
                end else
                    security_err_msg( 'Recipe', Read$ )            
                end 
                 
            CASE ChosenOpt = 'RDS'
                if security_check( 'RDS', Read$ ) then
                    SchedDetKeys    = Schedule_Services('GetScheduleDetailKeys', StartDate, StartDate, ReactorNo, '', False$)
                    WOStepKeys      = ''
                    For Each SchedDetKey in SchedDetKeys using @FM
                        SchedDet    = Schedule_Services('GetScheduleDetail', SchedDetKey)
                        WorkOrderNo = SchedDet<SCHED_DET_WO_NO$>
                        Locate WorkOrderNo : '*1' in WOStepKeys using @FM setting fPos else
                            WOStepKeys := WorkOrderNo : '*1' : @FM
                        end
                    Next SchedDetKey
                    WOStepKeys[-1, 1]   = ''

                    RDSKeys = XLATE('WO_STEP',WOStepKeys,WO_STEP_RDS_KEY$,'X')
                    Convert @FM to @VM in RDSKeys
                                    
                    TypeOver = ''
                    TypeOver<PMODE$> = 'K'
                    TypeOver<PDISPLAY$> = RDSKeys

                    RDSKeys = Popup(@WINDOW,TypeOver,'RDS_QUERY')
                    
                    IF RDSKeys NE '' THEN
                        Void = start_window( 'RDS', @window, RDSKeys:'*CENTER', '', '' )
                    END
                end else
                    security_err_msg( 'RDS', Read$ )                  
                end
                
            CASE ChosenOpt = 'WO'
                if security_check( 'WO Log', Read$ ) then
                    NewForm = Xlate('APP_INFO', 'NEW_WO_FORM', '', 'X')
                    If NewForm then
                        Start_Window('NDW_WO_LOG', @Window, WorkOrderNo)
                    end else
                        Start_window( 'WO_LOG2', @window, WorkOrderNo:'*CENTER', '', '' )
                    end
                end else
                    security_err_msg( 'WO Log', Read$ )
                end
                
            CASE ChosenOpt = 'WO_STAT'
            
                PSN			= XLATE('WO_STEP',WOStepKey,1,'X')
                ReactorType = XLATE('PROD_SPEC',PSN,80,'X')
                
                BEGIN CASE
                    CASE ReactorType = 'P' Or ReactorType = 'EPP'
                    
                        obj_Appwindow('ViewRelated','WO_PROD_EPI':@RM:WOStepKey)
                        
                    CASE ReactorType = 'GAN'
                        obj_Appwindow('ViewRelated','WO_PROD_GAN':@RM:WOStepKey)
                        
                    CASE 1
                        obj_Appwindow('ViewRelated','WO_PROD':@RM:WOStepKey)
                
                END CASE
                
            case ChosenOpt = 'SUPPLEMENTS'
                Void = rds_supplement_maint( WorkOrderNo )
            
            case 1
                Null
                
        end case
    end

end event


Event OLE_SCHEDULE.OnScheduleClick(EntityId, Button, Location, Point, Shift, Ctrl)

    If MemberOf(@USER4, 'SCHEDULER_ADMIN') OR MemberOf(@USER4, 'SCHEDULER_MASTER') then
        If Button EQ 'Right' AND Location EQ 'Entity' then
            ContextMenu     = 'ADD' : @VM : 'Add Work Order Events...' : @VM : 1 : @FM
            ContextMenu    := '' : @FM
            ContextMenu    := 'ADDBLOCK' : @VM : 'Add Block Out Events...' : @VM : 1
            X               = Field(Point, ',', 1)
            DateTime        = Send_Message(CtrlEntId, 'OLE.MapClientToTime', X, 1)
            StartDate       = DateTime[1, '.']
            Send_Message(CtrlEntId, 'OLE.ShowContextMenu', Point, ContextMenu, EntityId : '*' : StartDate)
        end
    end

end event


Event OLE_SCHEDULE.OnApptClick(ApptID, Button, Shift, Ctrl, Point)

    Begin Case
        Case Button EQ 'Left'

            PopupCtrl       = @Window : '.OLE_POPUP'
            PrevApptID      = Get_Property(CtrlEntId, '@PREVAPPTID')
            AllowPopup      = False$
            PopupVisible    = Get_Property(PopupCtrl, 'OLE.Visible')
            If PopupVisible EQ True$ then
                GoSub DismissPopup
            end
            GoSub DisplayPopup

        Case Button EQ 'Right'

            If MemberOf(@USER4, 'SCHEDULER_ADMIN') OR MemberOf(@USER4, 'SCHEDULER_MASTER') then
                Appt            = Get_Property(@Window : '.OLE_SCHEDULE', 'OLE.Appt[' : ApptID : ']')
                ScheduleEvent   = Appt<18>
                GoSub ParseScheduleEvent
                If BlockOut then
                    ContextMenu     = 'CANCELBLOCK' : @VM : 'Cancel Block Out Event...' : @VM : 1
                end else
                    ContextMenu     = 'ADD' : @VM : 'Add Work Order Events...' : @VM : 1 : @FM
                    ContextMenu    := '' : @FM
                    ContextMenu    := 'MODIFY' : @VM : 'Modify Work Order Event...' : @VM : 1 : @FM
                    // Only allow a schedule event to be cancelled if it is not already engaged.
                    If Iconv(FirstScheduleDate, 'D') GT Date() then
                        ContextMenu    := '' : @FM
                        ContextMenu    := 'CANCEL' : @VM : 'Cancel Work Order Event...' : @VM : 1 : @FM
                    end
                    ContextMenu    := '' : @FM
                    ContextMenu    := 'ADDBLOCK' : @VM : 'Add Block Out Events...' : @VM : 1 : @FM
                    ContextMenu    := '' : @FM
                    ContextMenu    := 'FORCEADJUST' : @VM : 'Force Auto-Adjustment' : @VM : 1
                end
                Send_Message(CtrlEntId, 'OLE.ShowContextMenu', Point, ContextMenu, ApptID)
            end

    End Case

end event


Event OLE_SCHEDULE.OnContextMenuClick(Item, OrigApptID)

    OrigReactorNo       = OrigApptID[1, '*']
    OrigScheduleDate    = OrigApptID[Col2() + 1, '*']
    OrigSequence        = OrigApptID[Col2() + 1, '*']
    If OrigSequence NE '' then
        Appt            = Get_Property(@Window : '.OLE_SCHEDULE', 'OLE.Appt[' : OrigApptID : ']')
        ScheduleEvent   = Appt<18>
        GoSub ParseScheduleEvent
        Transfer WorkOrderNo to OrigWorkOrderNo
        Transfer EpiPartNo to OrigEpiPartNo
        Transfer ReactorNo to OrigReactorNo
        Transfer ScheduleDate to OrigScheduleDate
        Transfer Sequence to OrigSequence
    end else
        OrigWorkOrderNo = ''
        OrigEpiPartNo   = ''
    end

    Begin Case
        Case Item EQ 'ADD'

            AddEventDetails = Dialog_Box('WO_SCHEDULER_ACTIONS', @Window, Item : @FM : OrigApptID)
            Debug
            If AddEventDetails NE '' then
                Caption     = 'Please wait...adding new events'
                GoSub ShowWaitMessage
                ReactorNo       = AddEventDetails[1, @FM]
                WorkOrderNo     = AddEventDetails[Col2() + 1, @FM]
                Days            = AddEventDetails[Col2() + 1, @FM]
                StartDate       = AddEventDetails[Col2() + 1, @FM]
                Description     = AddEventDetails[Col2() + 1, @FM]
                UpdatedEvents   = Scheduling_Services('AdjustScheduleEvents', ReactorNo, WorkOrderNo, Days, StartDate, Description)
                If Error_Services('NoError') then
                    RemoveEventKeyIDs   = UpdatedEvents[1, @RM]
                    AddEvents           = UpdatedEvents[Col2() + 1, @RM]
                    Send_Message(CtrlEntId, 'RemoveAppts', RemoveEventKeyIDs)
                    Send_Message(CtrlEntId, 'AddAppts', AddEvents)
                    AddEvents   = SRP_Array('Rotate', AddEvents, @FM, @VM)
                    ApptIDs     = AddEvents<2>
                    Convert @VM to @FM in ApptIDs
                    Flags       = AddEvents<19>
                    Convert @VM to @FM in Flags
                    Convert @SVM to @VM in Flags
                    For Each ApptID in ApptIDs using @FM setting fPos
                        FlagVals    = Flags<fPos>
                        If Sum(FlagVals) GT 0 then
                            Convert @VM to @FM in FlagVals
                            Set_Property(CtrlEntId, 'OLE.ApptFlags[' : ApptID : ']', FlagVals)
                        end
                    Next ApptID
                end
                GoSub HideWaitMessage
            end

        Case Item EQ 'MODIFY'

            NewEventDetails = Dialog_Box('WO_SCHEDULER_ACTIONS', @Window, Item : @FM : OrigApptID)
            If NewEventDetails NE '' then
                // User updated the schedule detail.
                Caption     = 'Please wait...updating events'
                GoSub ShowWaitMessage
                NewReactorNo        = NewEventDetails[1, @FM]
                NewWorkOrderNo      = NewEventDetails[Col2() + 1, @FM]
                NewStartDate        = NewEventDetails[Col2() + 1, @FM]
                NewDescription      = NewEventDetails[Col2() + 1, @FM]
                OrigAppt            = Get_Property(CtrlEntId, 'Appt[' : OrigApptID : ']')
                NewSchedulerKeyID   = OrigWorkOrderNo : '*' : OrigEpiPartNo : '*' : NewReactorNo : '*' : NewStartDate : '*' : OrigSequence
                OrigScheduleKeyID   = OrigReactorNo : '*' : OrigScheduleDate : '*' : OrigSequence
                ScheduleDetail      = Schedule_Services('GetScheduleDetail', OrigScheduleKeyID)
                OrigDescription     = ScheduleDetail<SCHED_DET_DESC$>
                If NewDescription EQ '' then NewDescription = ' '
                If (OrigReactorNo NE NewReactorNo) OR (OrigScheduleDate NE NewStartDate) then
                    // This work order event is being moved to another reactor or date. Assume all following work order events related to the
                    // same work order number will also be moved.
                    RemoveEventKeyIDs   = ''
                    AddEvents           = ''
                    OrigWorkOrderEvents = Schedule_Services('GetScheduleEvents', OrigScheduleDate, '', OrigReactorNo, OrigWorkOrderNo, False$)
                    NumberOfEvents      = DCount(OrigWorkOrderEvents, @FM)
                    UpdatedEvents       = Schedule_Services('AdjustScheduleEvents', OrigReactorNo, OrigWorkOrderNo, Neg(NumberOfEvents), OrigScheduleDate)
                    If Error_Services('NoError') then
                        // Remove the relevant appointments from the scheduler form.
                        RemoveEventKeyIDs  := UpdatedEvents[1, @RM] : @FM
                        AddEvents          := UpdatedEvents[Col2() + 1, @RM] : @FM
                        If Error_Services('NoError') then
                            // Add the work order events to the schedulers.
                            UpdatedEvents       = Schedule_Services('AdjustScheduleEvents', NewReactorNo, NewWorkOrderNo, NumberOfEvents, NewStartDate)
                            RemoveEventKeyIDs  := UpdatedEvents[1, @RM] : @FM
                            AddEvents          := UpdatedEvents[Col2() + 1, @RM] : @FM
                        end
                    end
                    RemoveEventKeyIDs[-1, 1]    = ''
                    AddEvents[-1, 1]            = ''
                    If RemoveEventKeyIDs NE '' then Send_Message(CtrlEntId, 'RemoveAppts', RemoveEventKeyIDs)
                    If AddEvents NE '' then Send_Message(CtrlEntId, 'AddAppts', AddEvents)
                end else
                    If OrigDescription NE NewDescription then
                        // This work order event is simply getting an updated description. Update the schedule detail in the database and
                        // refresh the scheduler display.
                        ScheduleDetail<SCHED_DET_DESC$> = NewDescription
                        Schedule_Services('SetScheduleDetail', OrigScheduleKeyID, ScheduleDetail)
                        OrigAppt<7> = NewDescription
                        Set_Property(CtrlEntId, 'Appt[' : OrigApptID : ']', OrigAppt)
                    end
                end
                GoSub HideWaitMessage
            end

        Case Item EQ 'CANCEL'

            CancelledWorkOrderNo    = Dialog_Box('WO_SCHEDULER_ACTIONS', @Window, Item : @FM : OrigApptID)

            If CancelledWorkOrderNo NE '' then
                UserConfirmed   = Msg(@Window, '', 'OK_CANCEL', '', 'Work Order Scheduler' : @FM : 'Are you sure you want to cancel events for work order ' : CancelledWorkOrderNo : '?')
                If UserConfirmed NE Esc$ then
                    Caption     = 'Please...cancelling events for work order ' : CancelledWorkOrderNo
                    GoSub ShowWaitMessage
                    RemovedApptIDs  = Scheduling_Services('CancelScheduleEvents', CancelledWorkOrderNo)
                    If Error_Services('NoError') then
                        Send_Message(CtrlEntId, 'RemoveAppts', RemovedApptIDs)
                    end
*                    SchedulerKeyIDs = SRP_Array('Rotate', CancelledScheduleEvents, @FM, @VM)
*                    SchedulerKeyIDs = SchedulerKeyIDs<2>
*                    Convert @VM to @FM in SchedulerKeyIDs
*                    ScheduleKeyIDs  = SRP_Array('Rotate', SchedulerKeyIDs, @FM, '*')
*                    ScheduleKeyIDs  = Delete(ScheduleKeyIDs, 1, 0, 0)
*                    ScheduleKeyIDs  = Delete(ScheduleKeyIDs, 1, 0, 0)
*                    ScheduleKeyIDs  = SRP_Array('Rotate', ScheduleKeyIDs, @FM, '*')
*                    // Remove the schedule detail records first.
*                    ReactorNo       = Field(OrigApptID, '*', 3)
*                    NumberOfEvents  = Neg(DCount(SchedulerKeyIDs, @FM))
*                    StartDate       = Field(SchedulerKeyIDs<1>, '*', 4, 1)
*                    UpdatedEvents   = Schedule_Services('AdjustScheduleEvents', ReactorNo, OrigWorkOrderNo, NumberOfEvents, StartDate)
*                    If Error_Services('NoError') then
*                        // Remove the relevant appointments from the scheduler form.
*                        RemoveEventKeyIDs   = UpdatedEvents[1, @RM]
*                        AddEvents           = UpdatedEvents[Col2() + 1, @RM]
*                        Send_Message(CtrlEntId, 'RemoveAppts', RemoveEventKeyIDs)
*                        Send_Message(CtrlEntId, 'AddAppts', AddEvents)
*                    end
                    GoSub HideWaitMessage
                end
            end

        Case Item EQ 'ADDBLOCK'

            AddEventDetails = Dialog_Box('WO_SCHEDULER_ACTIONS', @Window, Item : @FM : OrigApptID)
            If AddEventDetails NE '' then
                Caption     = 'Please wait...adding new events'
                GoSub ShowWaitMessage
                ReactorNo       = AddEventDetails[1, @FM]
                StartDate       = AddEventDetails[Col2() + 1, @FM]
                EndDate         = AddEventDetails[Col2() + 1, @FM]
                Description     = AddEventDetails[Col2() + 1, @FM]
                UpdatedEvents   = Schedule_Services('AddBlockOutEvents', ReactorNo, StartDate, EndDate, Description)
                If Error_Services('NoError') then
                    RemoveEventKeyIDs   = UpdatedEvents[1, @RM]
                    AddEvents           = UpdatedEvents[Col2() + 1, @RM]
                    Send_Message(CtrlEntId, 'RemoveAppts', RemoveEventKeyIDs)
                    Send_Message(CtrlEntId, 'AddAppts', AddEvents)
                end
                GoSub HideWaitMessage
            end

        Case Item EQ 'CANCELBLOCK'

            CancelledBlockOutEvent  = Dialog_Box('WO_SCHEDULER_ACTIONS', @Window, Item : @FM : OrigApptID)
            If CancelledBlockOutEvent NE '' then
                Caption     = 'Please wait...cancelling block out event'
                GoSub ShowWaitMessage
                BlockOutEventKeyID  = '**' : CancelledBlockOutEvent
                UpdatedEvents       = Schedule_Services('CancelBlockOutEvent', BlockOutEventKeyID)
                If Error_Services('NoError') then
                    // Remove the relevant appointments from the scheduler form.
                    RemoveEventKeyIDs   = UpdatedEvents[1, @RM]
                    AddEvents           = UpdatedEvents[Col2() + 1, @RM]
                    Send_Message(CtrlEntId, 'RemoveAppts', RemoveEventKeyIDs)
                    Send_Message(CtrlEntId, 'AddAppts', AddEvents)
                end
                GoSub HideWaitMessage
            end

        Case Item EQ 'FORCEADJUST'

            Caption     = 'Please wait...adjusting work order events'
            GoSub ShowWaitMessage

            AdjustedDays    = Schedule_Services('GetAdjustedDays', OrigWorkOrderNo)

            If Error_Services('NoError') then
                If AdjustedDays NE '' AND AdjustedDays NE 0 then
                    UpdatedEvents   = Schedule_Services('AdjustScheduleEvents', OrigReactorNo, OrigWorkOrderNo, AdjustedDays, OrigScheduleDate)
                    If Error_Services('NoError') then
                        RemoveEventKeyIDs   = UpdatedEvents[1, @RM]
                        AddEvents           = UpdatedEvents[Col2() + 1, @RM]
                        Send_Message(CtrlEntId, 'RemoveAppts', RemoveEventKeyIDs)
                        Send_Message(CtrlEntId, 'AddAppts', AddEvents)
                        AddEvents           = SRP_Array('Rotate', AddEvents, @FM, @VM)
                        ApptIDs             = AddEvents<2>
                        Convert @VM to @FM in ApptIDs
                        Flags   = AddEvents<19>
                        Convert @VM to @FM in Flags
                        Convert @SVM to @VM in Flags
                        For Each ApptID in ApptIDs using @FM setting fPos
                            FlagVals    = Flags<fPos>
                            If Sum(FlagVals) GT 0 then
                                Convert @VM to @FM in FlagVals
                                Set_Property(CtrlEntId, 'OLE.ApptFlags[' : ApptID : ']', FlagVals)
                            end
                        Next ApptID
                    end
                end
            end
            GoSub HideWaitMessage

    End Case

end event


Event OLE_SCHEDULE.OnDateChange(Date)

    DateList            = Get_Property(CtrlEntId, '@DATE_LIST')
    ReloadStartDate     = Date - 7
    ReloadEndDate       = Date + 7
    ReloadWorkOrders    = False$
    For Date = ReloadStartDate to ReloadEndDate
        Locate Date in DateList using @FM setting fPos else ReloadWorkOrders = True$
    Until ReloadWorkOrders EQ True$
    Next Date
    If ReloadWorkOrders then
        // The ShowWaitMessage gosub hides the schedule control and displays the picture contorl with the indicated caption.
        Caption     = 'Please wait...updating schedule'
        GoSub ShowWaitMessage

        // Update the work orders
        StartDate   = ReloadStartDate
        EndDate     = ReloadEndDate
        // The GetScheduleAppointments gosub populates the AppointmentList, ApptIDs, and AppointmentFlags variables.
        GoSub GetScheduleAppointments
        Send_Message(CtrlEntId, 'OLE.AddAppts', AppointmentList)
        // The SetScheduleFlags gosub loops through the ApptIDs array and parses the AppointmentFlags
        // array for the ApptFlags property.
        GoSub SetScheduleFlags

        For Date = ReloadStartDate to ReloadEndDate
            Locate Date in DateList using @FM setting fPos else
                DateList    = Insert(DateList, fPos, 0, 0, Date)
            end
        Next Date
        Set_Property(CtrlEntId, '@DATE_LIST', DateList)

        GoSub HideWaitMessage
    end

end event


Event OLE_DATEPICKER.OnSelChange(FirstDate)

    SelectedDate    = Get_Property(CtrlEntId, 'OLE.Selection')
    Set_Property(@Window : '.OLE_SCHEDULE', 'OLE.Date', SelectedDate)
    Send_Event(@Window : '.OLE_SCHEDULE', 'OLE', 'OnDateChange', SelectedDate)

end event


Event OLE_TRE_REACTOR_FILTER_OPTIONS.OnItemCheck(Item, Checked)

    Set_Property(@Window, 'REDRAW', False$)
    FilterType      = Get_Property(@Window : '.EDL_REACTOR_FILTER', 'TEXT')
    FilterOptions   = Get_Property(CtrlEntId, 'OLE.RootChildren')
    ItemsChecked    = ''
    For Each FilterOption in FilterOptions using @FM setting fPos
        If Get_Property(CtrlEntId, 'OLE.ItemChecked[' : FilterOption : ']') then
            ItemsChecked   := FilterOption : @FM
        end
    Next FilterOption
    ItemsChecked[-1, 1] = ''

    // Make sure all reactors are visible again.
    EntityList  = Get_Property(@Window : '.OLE_SCHEDULE', 'OLE.EntityList')
    For Each Entity in EntityList using @FM
        EntityID    = Entity<0, 3>
        If Not(Get_Property(@Window : '.OLE_SCHEDULE', 'OLE.EntityChecked[' : EntityID : ']')) then
            Set_Property(@Window : '.OLE_SCHEDULE', 'OLE.EntityChecked[' : EntityID : ']', True$)
        end
    Next Entity

    // Now apply the filter optons and hide those entities which should be hidden.
    Reactors    = Reactor_Services('GetReactors')
    If SRP_JSON(objReactors, 'PARSE', Reactors) EQ '' then
        objReactorArray     = SRP_JSON(objReactors, 'GET', 'Reactors')
        NumObjects          = SRP_JSON(objReactorArray, 'GETCOUNT')
        For ObjectCount = 1 to NumObjects
            ReactorNo   = SRP_JSON(objReactorArray, 'GETVALUE', '[' : ObjectCount : '].ReactorNumber')
            
            Begin Case
                Case FilterType _EQC 'Reactor Type'
                    Type        = SRP_JSON(objReactorArray, 'GETVALUE', '[' : ObjectCount : '].TypeVerbose')
                    Locate Type in ItemsChecked using @FM setting fPos else
                        Set_Property(@Window : '.OLE_SCHEDULE', 'OLE.EntityChecked[' : ReactorNo : ']', False$)
                    end

                Case FilterType _EQC 'Reactor Assignment'
                    AssignmentDescription  = SRP_JSON(objReactorArray, 'GETVALUE', '[' : ObjectCount : '].AssignmentDescription')
                    Locate AssignmentDescription in ItemsChecked using @FM setting fPos else
                        Set_Property(@Window : '.OLE_SCHEDULE', 'OLE.EntityChecked[' : ReactorNo : ']', False$)
                    end

                Case FilterType _EQC 'Cleanroom Area'
                    Location    = SRP_JSON(objReactorArray, 'GETVALUE', '[' : ObjectCount : '].Location')
                    Locate Location in ItemsChecked using @FM setting fPos else
                        Set_Property(@Window : '.OLE_SCHEDULE', 'OLE.EntityChecked[' : ReactorNo : ']', False$)
                    end

                Case FilterType _EQC 'Wafer Size'
                    WaferSize   = SRP_JSON(objReactorArray, 'GETVALUE', '[' : ObjectCount : '].SusceptorSize')
                    Locate WaferSize in ItemsChecked using @FM setting fPos else
                        Set_Property(@Window : '.OLE_SCHEDULE', 'OLE.EntityChecked[' : ReactorNo : ']', False$)
                    end

                Case FilterType _EQC 'Cleanroom Area'
                    Null
            End Case
        Next ObjectCount
        SRP_JSON(objReactorArray, 'RELEASE')
    end
    SRP_JSON(objReactors, 'RELEASE')

    Set_Property(@Window, 'REDRAW', True$)

end event


Event EDL_ASM_UTILIZATION.CHANGED(NewData)

    OrigValue   = Get_Property(CtrlEntId, 'GOTFOCUS_VALUE')
    CurrValue   = Get_Property(CtrlEntId, 'DEFPROP')
    If OrigValue NE CurrValue then
        ButtonCtrl  = CtrlEntId
        Swap 'EDL' with 'OLE_PUB_UPDATE' in ButtonCtrl
        Set_Property(ButtonCtrl, 'ENABLED', True$)
    end

end event


Event EDL_ASM_PLUS_UTILIZATION.CHANGED(NewData)

    OrigValue   = Get_Property(CtrlEntId, 'GOTFOCUS_VALUE')
    CurrValue   = Get_Property(CtrlEntId, 'DEFPROP')
    If OrigValue NE CurrValue then
        ButtonCtrl  = CtrlEntId
        Swap 'EDL' with 'OLE_PUB_UPDATE' in ButtonCtrl
        Set_Property(ButtonCtrl, 'ENABLED', True$)
    end

end event


Event EDL_HTR_UTILIZATION.CHANGED(NewData)

    OrigValue   = Get_Property(CtrlEntId, 'GOTFOCUS_VALUE')
    CurrValue   = Get_Property(CtrlEntId, 'DEFPROP')
    If OrigValue NE CurrValue then
        ButtonCtrl  = CtrlEntId
        Swap 'EDL' with 'OLE_PUB_UPDATE' in ButtonCtrl
        Set_Property(ButtonCtrl, 'ENABLED', True$)
    end

end event


Event EDL_EPIPRO_UTILIZATION.CHANGED(NewData)

    OrigValue   = Get_Property(CtrlEntId, 'GOTFOCUS_VALUE')
    CurrValue   = Get_Property(CtrlEntId, 'DEFPROP')
    If OrigValue NE CurrValue then
        ButtonCtrl  = CtrlEntId
        Swap 'EDL' with 'OLE_PUB_UPDATE' in ButtonCtrl
        Set_Property(ButtonCtrl, 'ENABLED', True$)
    end

end event


Event EDL_GAN_UTILIZATION.CHANGED(NewData)

    OrigValue   = Get_Property(CtrlEntId, 'GOTFOCUS_VALUE')
    CurrValue   = Get_Property(CtrlEntId, 'DEFPROP')
    If OrigValue NE CurrValue then
        ButtonCtrl  = CtrlEntId
        Swap 'EDL' with 'OLE_PUB_UPDATE' in ButtonCtrl
        Set_Property(ButtonCtrl, 'ENABLED', True$)
    end

end event


Event OLE_PUB_UPDATE_ASM_UTILIZATION.OnClick(Point, Button, Shift, Ctrl)

    ASMUtil     = Get_Property(@Window : '.EDL_ASM_UTILIZATION', 'INVALUE')
    Epi_Part_Services('SetReactorUtilization', 'ASM', ASMUtil)
    Set_Property(CtrlEntId, 'ENABLED', False$)
    EditCtrl  = CtrlEntId
    Swap 'OLE_PUB_UPDATE' with 'EDL' in EditCtrl
    Set_Property(EditCtrl, 'FOCUS', True$)

end event


Event OLE_PUB_UPDATE_ASM_PLUS_UTILIZATION.OnClick(Point, Button, Shift, Ctrl)

    ASMPlusUtil = Get_Property(@Window : '.EDL_ASM_PLUS_UTILIZATION', 'INVALUE')
    Epi_Part_Services('SetReactorUtilization', 'ASM+', ASMPlusUtil)
    Set_Property(CtrlEntId, 'ENABLED', False$)
    EditCtrl  = CtrlEntId
    Swap 'OLE_PUB_UPDATE' with 'EDL' in EditCtrl
    Set_Property(EditCtrl, 'FOCUS', True$)

end event


Event OLE_PUB_UPDATE_HTR_UTILIZATION.OnClick(Point, Button, Shift, Ctrl)

    HTRUtil     = Get_Property(@Window : '.EDL_HTR_UTILIZATION', 'INVALUE')
    Epi_Part_Services('SetReactorUtilization', 'HTR', HTRUtil)
    Set_Property(CtrlEntId, 'ENABLED', False$)
    EditCtrl  = CtrlEntId
    Swap 'OLE_PUB_UPDATE' with 'EDL' in EditCtrl
    Set_Property(EditCtrl, 'FOCUS', True$)

end event


Event OLE_PUB_UPDATE_EPIPRO_UTILIZATION.OnClick(Point, Button, Shift, Ctrl)

    EpiProUtil  = Get_Property(@Window : '.EDL_EPIPRO_UTILIZATION', 'INVALUE')
    Epi_Part_Services('SetReactorUtilization', 'EpiPro', EpiProUtil)
    Set_Property(CtrlEntId, 'ENABLED', False$)
    EditCtrl  = CtrlEntId
    Swap 'OLE_PUB_UPDATE' with 'EDL' in EditCtrl
    Set_Property(EditCtrl, 'FOCUS', True$)

end event


Event OLE_PUB_UPDATE_GAN_UTILIZATION.OnClick(Point, Button, Shift, Ctrl)

    GaNUtil     = Get_Property(@Window : '.EDL_GAN_UTILIZATION', 'INVALUE')
    Epi_Part_Services('SetReactorUtilization', 'GaN', GaNUtil)
    Set_Property(CtrlEntId, 'ENABLED', False$)
    EditCtrl  = CtrlEntId
    Swap 'OLE_PUB_UPDATE' with 'EDL' in EditCtrl
    Set_Property(EditCtrl, 'FOCUS', True$)

end event


Event OLE_PUB_REFRESH_SCHEDULE.OnClick(Point, Button, Shift, Ctrl)

    // The ShowWaitMessage gosub hides the schedule control and displays the picture contorl with the indicated caption.
    Caption     = 'Please wait...refreshing schedule'
    GoSub ShowWaitMessage
    StartDate   = Date() - 7
    EndDate     = Date() + 30
    // The GetScheduleAppointments gosub populates the AppointmentList, ApptIDs, and AppointmentFlags variables.
    GoSub GetScheduleAppointments
    Set_Property(@Window : '.OLE_SCHEDULE', 'OLE.AppointmentList', AppointmentList)
    // The SetScheduleFlags gosub loops through the ApptIDs array and parses the AppointmentFlags
    // array for the ApptFlags property.
    GoSub SetScheduleFlags
    GoSub HideWaitMessage

end event


Event OLE_SUBCLASS.OnOptionClick(CtrlId)

    Send_Event(CtrlId, 'OPTIONS')

end event


Event OLE_SUBCLASS.OnComboClick(CtrlId)

    Send_Event(CtrlId, 'LOSTFOCUS')

end event


Event OLE_POPUP.OnItemClick(Item)

    ApptID          = Get_Property(CtrlEntId, '@APPTID')
    ReactorNo       = ApptID[1, '*']
    StartDate       = ApptID[Col2() + 1, '*']
    Sequence        = ApptID[Col2() + 1, '*']
    ScheduleEvent   = Scheduling_Services('GetScheduleEvent', ReactorNo, StartDate, Sequence, True$)
    GoSub ParseScheduleEvent
    WOStepKey       = WorkOrderNo : '*1'

    // Item is the index value of the item being clicked on from the ItemList property.
    PreviousItemArray   = Get_Property(CtrlEntId, 'OLE.Item[' : Item - 1 : ']')
    PreviousCaption     = PreviousItemArray<2>
    CurrentItemArray    = Get_Property(CtrlEntId, 'OLE.Item[' : Item : ']')
    CurrentCaption      = CurrentItemArray<2>

    GoSub DismissPopup

    Begin Case
        Case PreviousCaption _EQC 'Work Order:'

            if security_check( 'WO Log', Read$ ) then
                NewForm = Xlate('APP_INFO', 'NEW_WO_FORM', '', 'X')
                If NewForm then
                    Start_Window('NDW_WO_LOG', @Window, WorkOrderNo)
                end else
                    Start_window( 'WO_LOG2', @window, WorkOrderNo:'*CENTER', '', '' )
                end
            end else
                security_err_msg( 'WO Log', Read$ )
            end

        Case PreviousCaption _EQC 'Epi Part:'

*            IF security_check( 'Prod Spec', Read$ ) THEN   

                Void = start_window( 'EPI_PART', @window, EpiPartNo : '*CENTER', '', '' )
*            END ELSE
*                security_err_msg( 'Prod Spec', Read$ )      
*            END

        Case PreviousCaption _EQC 'PSN:'

            IF security_check( 'Prod Spec', Read$ ) THEN   

                PSNId = XLATE('WO_STEP',WOStepKey,WO_STEP_PROD_SPEC_ID$,'X')
                Void = start_window( 'PROD_SPEC', @window, PSNId:'*CENTER', '', '' )
            END ELSE
                security_err_msg( 'Prod Spec', Read$ )      
            END

        Case PreviousCaption _EQC 'Recipe:'

            if security_check( 'Recipe', Read$ ) then 

                PSN = XLATE('WO_STEP',WOStepKey,1,'X')

                LayerSpecs = obj_Prod_Spec('GetLayerProp',PSN:@RM:@RM:1)	;* Returns specs for all layers in internal format

                LayerSpec 	= FIELD(LayerSpecs,@RM,1)				;* Take the first Layer
                LayerSet	= FIELD(LayerSpec,@FM,1)				;* Not used here but shown for clarity
                LayerSpec	= FIELD(LayerSpec,@FM,2,99)				;* LayerSpec without the LayerSet 

                RecipeNo = LayerSpec<PRS_LAYER_RECIPE$>
                Void = start_window( 'RECIPE', @window, RecipeNo:'*CENTER', '', '' )
            end else
                security_err_msg( 'Recipe', Read$ )
            end

        Case PreviousCaption _EQC 'SCHED_DET Key:'

            SchedDetKeyID   = CurrentCaption
            call SRP_Editor_Open('Record', 'SCHED_DET' : @FM : SchedDetKeyID, 1)

    End Case

end event


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

Setup_OLE_Controls:

    Ctrl        = @Window : '.OLE_PICTURE'
    Set_Property(Ctrl, 'OLE.BackgroundColor', 'Vertical(Gradient(LightSteelBlue L=90, LightSteelBlue L=80, 30%), Gradient(LightSteelBlue L=75, LightSteelBlue L=80), Border(LightSteelBlue L=50, LightSteelBlue L=50, LightSteelBlue L=50, LightSteelBlue L=50))')
    Set_Property(Ctrl, 'OLE.Font', SystemTypeface$ : @SVM : 30 : @SVM : 700)

    // The ShowWaitMessage gosub hides the schedule control and displays the picture contorl with the indicated caption.
    Caption     = 'Please wait...loading schedule'
    GoSub ShowWaitMessage
    Ctrl        = @Window : '.OLE_SCHEDULE'
    // Setup the inital date range during the 'Create'
    StartDate   = Date() - 365
    EndDate     = Date() + 90
    DateList    = ''
    For Date = StartDate to EndDate
        DateList   := Date : @FM
    Next Date
    DateList[-1, 1] = ''
    Set_Property(Ctrl, '@DATE_LIST', DateList)
    Set_Property(Ctrl, 'OLE.Border', 'XP Flat')
 	Set_Property(Ctrl, 'OLE.View', 'MultiDayHorz')			    ; // Landscape mode
 	Set_Property(Ctrl, 'OLE.DateHeaderFormat', 'DDDD  -  mmm DD, YYYY')
 	Set_Property(Ctrl, 'OLE.CurrentTimeColor', 'Blue')
 	Set_Property(Ctrl, 'OLE.ShowCalendar', False$)
 	Set_Property(Ctrl, 'OLE.ShowTree', False$)
 	Set_Property(Ctrl, 'OLE.AllowLeadTime', False$)
 	Set_Property(Ctrl, 'OLE.AllowTrailTime', False$)
 	Set_Property(Ctrl, 'OLE.EnableLeadTrailDisplay', Trail$)
 	Set_Property(Ctrl, 'OLE.AppointmentMetrics', 4 : @FM : 4)
 	Set_Property(Ctrl, 'OLE.Interval', 60)						; // Number of minutes per interval
 	Set_Property(Ctrl, 'OLE.IntervalSize', 10)					; // Space (width) for each time increment (in pixels)
* 	Set_Property(Ctrl, 'OLE.ConflictColor',	'Crimson')
 	Set_Property(Ctrl, 'OLE.TimeRange', 0 :@FM: 24 :@FM: 4)		; // <3> is hour display increment
* 	Set_Property(Ctrl, 'OLE.RightTimeBar', Yes$)
    Fonts = ''
    Fonts<1> = 'Segoe UI' : @SVM : '10'                 ; // Column Hours
    Fonts<2> = 'Segoe UI' : @SVM : '6'                  ; // Column Minutes
    Fonts<3> = 'Segoe UI' : @SVM : '12' : @SVM : '700'  ; // Reactor No
    Fonts<4> = 'Segoe UI' : @SVM : '8'                  ; // Reactor Meta
    Fonts<5> = 'Segoe UI' : @SVM : '12' : @SVM : '700'  ; // Column Date and Day
    Set_Property(Ctrl, 'OLE.ScheduleFonts', Fonts)
    // Setup the initial reactors list. This populates the EntityList variable.
    GoSub GetReactorEntities
    Set_Property(Ctrl, 'OLE.EntityList', EntityList)
    Set_Property(Ctrl, 'OLE.AutoSize', 0)
    Set_Property(Ctrl, 'OLE.EntitySize[All]', 75)
 	Set_Property(Ctrl, 'OLE.Date', Date()-1)
 	Layout          = ''
 	Layout<1, 1>    = 'APPTDATA'
 	Layout<1, 2>    = 0 : @SVM : 0 : @SVM : -1 : @SVM : -1
 	Layout<1, 3>    = 'NAME'
 	Layout<1, 4>    = ''
 	Layout<1, 5>    = 'Segoe UI' : @SVM : 9 : @SVM : 700
 	Layout<1, 6>    = 'Left'
 	Layout<1, 7>    = 'Top'
 	Layout<1, 8>    = 0
 	Layout<1, 10>   = 1
 	Layout<2, 1>    = 'APPTDATA'
 	Layout<2, 2>    = 0 : @SVM : 0 : @SVM : -1 : @SVM : -1
 	Layout<2, 3>    = 'DESC'
 	Layout<2, 4>    = ''
 	Layout<2, 6>    = 'Left'
 	Layout<2, 7>    = 'Bottom'
 	Layout<2, 8>    = 1
 	Layout<2, 10>   = 0
 	Layout<3, 1>    = 'FLAGS'
 	Layout<3, 2>    = 0 : @SVM : 0 : @SVM : -1 : @SVM : -1
 	Layout<3, 3>    = 'bmps\scheduler.png'
 	Layout<3, 4>    = 4 : @SVM : @SVM : 0
 	Layout<3, 6>    = 'Right'
 	Layout<3, 7>    = ''
 	Layout<3, 8>    = ''
 	Layout<3, 10>   = 0
 	Set_Property(Ctrl, 'OLE.Layout', Layout)
 	// The GetScheduleAppointments gosub populates the AppointmentList, ApptIDs, and AppointmentFlags variables.
    GoSub GetScheduleAppointments
    Set_Property(Ctrl, 'OLE.AppointmentList', AppointmentList)
    // The SetScheduleFlags gosub loops through the ApptIDs array and parses the AppointmentFlags
    // array for the ApptFlags property.
    GoSub SetScheduleFlags
 	Qualify     = ''
 	Qualify<1>  = 1
    Qualify<4>  = 0
 	Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnApptClick', 1)
 	Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnApptDblClick', 1)
 	Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnScheduleClick', 1)
 	Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnDateChange', 1)
 	Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnContextMenuClick', 1)
 	Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnApptHover', 1)
    GoSub HideWaitMessage

    Ctrl    = @Window : '.OLE_DATEPICKER'
    Set_Property(Ctrl, 'OLE.Border', 'XP Flat')
    Set_Property(Ctrl, 'OLE.Font', 'Segoe UI' : @SVM : '9')
 	Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnSelChange', 1)

    Ctrl        = @Window : '.OLE_SUBCLASS'
    EditLine    = @Window : '.EDL_REACTOR_FILTER'
    Set_Property(EditLine, 'TEXT', 'Reactor Type')
    Post_Event(EditLine, 'LOSTFOCUS')
    Handle      = Get_Property(EditLine, 'HANDLE')
    Send_Message(Ctrl, 'OLE.Subclass', Handle, EditLine)
    EditLine    = @Window : ';EDL_REACTOR_FILTER'
    FilterTypes = 'Reactor Type' : @STM : 'Reactor Assignment' : @STM : 'Wafer Size' : @STM : 'Cleanroom Area'
    Combo       = ''
    Combo<1>    = 1
    Combo<2, 1> = ''
    Combo<2, 2> = 'L' : @STM : 'DYN'
    Combo<2, 3> = FilterTypes
    Combo<2, 4> = 1
    Combo<2, 5> = 1
    Combo<2, 6> = 0
    Combo<2, 9> = 1
    Combo<2,11> = 0
    Set_Property(Ctrl, 'OLE.Combo[' : EditLine : ']', Combo)
 	Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnOptionClick', 1)
    Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnComboClick', 1)

    EditLine        = @Window : '.EDL_WORK_ORDER_SEARCH'
    Handle          = Get_Property(EditLine, 'HANDLE')
    Send_Message(Ctrl, 'OLE.Subclass', Handle, EditLine)
    EditLine        = @Window : ';EDL_WORK_ORDER_SEARCH'
    WorkOrderNos    = SRP_Array('Clean', WorkOrderNos, 'TrimAndMakeUnique', @FM)
    WorkOrderNos    = SRP_Array('SortRows', WorkOrderNos, 'AR1', 'LIST', @FM, @VM)
    Convert @FM to @STM in WorkOrderNos
    Combo       = ''
    Combo<1>    = 1
    Combo<2, 1> = ''
    Combo<2, 2> = 'L' : @STM : 'DYN'
    Combo<2, 3> = WorkOrderNos
    Combo<2, 4> = 1
    Combo<2, 5> = 1
    Combo<2, 6> = 0
    Combo<2, 9> = 1
    Combo<2,10> = 0
    Combo<2,11> = 0
    Set_Property(Ctrl, 'OLE.Combo[' : EditLine : ']', Combo)
* 	 Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnOptionClick', 1)
*    Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnComboClick', 1)

    EditLine    = @Window : '.EDL_EPI_PART_SEARCH'
    Handle      = Get_Property(EditLine, 'HANDLE')
    Send_Message(Ctrl, 'OLE.Subclass', Handle, EditLine)
    EditLine    = @Window : ';EDL_EPI_PART_SEARCH'
    EpiPartNos  = SRP_Array('Clean', EpiPartNos, 'TrimAndMakeUnique', @FM)
    EpiPartNos  = SRP_Array('SortRows', EpiPartNos, 'AR1', 'LIST', @FM, @VM)
    Convert @FM to @STM in EpiPartNos
    Combo       = ''
    Combo<1>    = 1
    Combo<2, 1> = ''
    Combo<2, 2> = 'L' : @STM : 'DYN'
    Combo<2, 3> = EpiPartNos
    Combo<2, 4> = 1
    Combo<2, 5> = 1
    Combo<2, 6> = 0
    Combo<2, 9> = 1
    Combo<2,10> = 0
    Combo<2,11> = 0
    Set_Property(Ctrl, 'OLE.Combo[' : EditLine : ']', Combo)
* 	 Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnOptionClick', 1)
*    Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnComboClick', 1)

    Ctrl    = @Window : '.OLE_TRE_REACTOR_FILTER_OPTIONS'
    Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnItemCheck', 1)
 	Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnApptDblClick', 1)

    Ctrls   = 'OLE_PUB_UPDATE_ASM_UTILIZATION,OLE_PUB_UPDATE_ASM_PLUS_UTILIZATION,OLE_PUB_UPDATE_HTR_UTILIZATION,OLE_PUB_UPDATE_EPIPRO_UTILIZATION,OLE_PUB_UPDATE_GAN_UTILIZATION'
    For Each ButtonCtrl in Ctrls using ','
        Ctrl    = @Window : '.' : ButtonCtrl
        Set_Property(Ctrl, 'OLE.Icon', '.\BMPS\Save.png')
        Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnClick', 1)
    Next ButtonCtrl

    Ctrl    = @Window : '.OLE_PUB_REFRESH_SCHEDULE'
    Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnClick', 1)

    Ctrl    = @Window : '.OLE_POPUP'
    Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnItemClick', 1)
    Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnHide', 1)

return


DisplayPopup:

    Utility('CURSOR', 'H')
    Set_Property(PopupCtrl, '@APPTID', ApptID)
    Appt            = Get_Property(CtrlEntID, 'OLE.Appt[' : ApptID : ']')
    HoverData       = ''
    BackColor       = Appt<4>   ; // Use the same BackColor of the current appointment as the base.
    ReactorNo       = ApptID[1, '*']
    Date            = ApptID[Col2() + 1, '*']
    Sequence        = ApptID[Col2() + 1, '*']
    ScheduleEvent   = Scheduling_Services('GetScheduleEvent', ReactorNo, Date, Sequence, True$)
    GoSub ParseScheduleEvent
    HoverData  := 'Reactor:' : @VM : ReactorNo : @FM
    HoverData  := 'Type:' : @VM : ReactorType : @FM
    HoverData  := 'Susceptor:' : @VM : SusceptorSize : @FM
    HoverData  := 'Work Order:' : @VM : WorkOrderNo : @FM
    HoverData  := 'Customer:' : @VM : CustNameShort : @FM
    HoverData  := 'Epi Part:' : @VM : EpiPartNo : @FM
    HoverData  := 'PSN:' : @VM : PSN : @FM
    HoverData  := 'Recipe:' : @VM : Recipe : @FM
    HoverData  := 'First Event:' : @VM : FirstScheduleDate : ' (' : FirstReactorNo : ')' : @FM
    HoverData  := 'Last Event:' : @VM : LastScheduleDate : ' (' : LastReactorNo : ')' : @FM
    HoverData  := 'Total Days:' : @VM : TotalScheduledDays : @FM
    HoverData  := 'Total Wafers:' : @VM : TotalWafers : @FM
    HoverData  := 'Remaining Wafers:' : @VM : WafersRemaining : @FM
    HoverData  := 'Complete:' : @VM : PercentComplete
    If MemberOf(@USER4, 'OI_ADMIN') then
        HoverData  := @FM : 'SCHED_DET Key:' : @VM : ReactorNo : '*' : Date : '*' : Sequence
    end
    BackColor  := ' L=40'
    NumLines    = DCount(HoverData, @FM)
    ForeColor   = 'White'
    Linkcolor   = 'LightGray'

    // Calculate the size and position of the popup. By default it will appear to the right of the
    // appointment (order), but if it will display off the screen then move it to the left.
    DesktopWidth    = Get_Property('SYSTEM', 'SIZE')<1>
    ApptRect        = Get_Property(CtrlEntId, 'OLE.ApptRect[' : ApptId : ']')
    RectLeft        = ApptRect<1>
    RectTop         = ApptRect<2>
    RectRight       = ApptRect<3>
    RectBottom      = ApptRect<4>
    ItemWidth       = 240
    // For popups with a top pointer
*        PopupWidth      = ItemWidth + 4
    // For popups with a left pointer
    PopupWidth      = ItemWidth + 4 + 30
*        ItemHeight      = NumLines * 20
    ItemHeight      = 20
    PopupHeight     = NumLines * ItemHeight + 14
    If (RectRight + PopupWidth) LE DesktopWidth then
        // SRP Popup will fit if displayed on the right.
        TailPosition    = 'Left'
        ItemMargin      = 28
        PopupX          = RectRight
    end else
        // SRP Popup will have to be positioned on the left.
        TailPosition    = 'Right'
        ItemMargin      = 12
        PopupX          = RectLeft - PopupWidth
    end
    // Calculate the center point of the appointment. Necessary to position the SRP Popup properly in the middle.
    ApptHCenter = RectTop + ((RectBottom - RectTop) / 2)
    ApptVCenter = RectLeft + ((RectRight - RectLeft) / 2)
    PopupY      = ApptHCenter - (PopupHeight / 2)
       
    // Use these coordinates to place the popup under the order.
*        PopupX      = ApptVCenter - (PopupWidth / 2)
*        PopupY      = RectBottom + 0

    ItemList    = ''
    If HoverData NE '' then
        For Each Item in HoverData using @FM setting ItemCnt
            // Add the label.
            Label       = Item<0, 1>
            ItemList   := ItemMargin : @SVM : 5 + (ItemCnt - 1) * ItemHeight : @SVM : ItemWidth / 2 : @SVM : ItemHeight : @VM
            ItemList   := Label : @VM
            ItemList   := Forecolor : @VM
            ItemList   := '' : @SVM : '' : @SVM : '700' : @SVM : '0' : @SVM : '0' : @VM
            ItemList   := 'Left' : @SVM : 'Center' : @VM
            ItemList   := @FM
            // Add the value.
            Value       = Item<0, 2>
            ItemList   := ItemMargin + (ItemWidth / 2) : @SVM : 5 + (ItemCnt - 1) * ItemHeight : @SVM : ItemWidth / 2 : @SVM : ItemHeight : @VM
            ItemList   := Value : @VM
            If Label _EQC 'Work Order:' OR Label _EQC 'Epi Part:' OR Label _EQC 'PSN:' OR Label _EQC 'Recipe:' OR Label _EQC 'SCHED_DET Key:' then
                ItemList   := Linkcolor : @VM
            end else
                ItemList   := Forecolor : @VM
            end
            If Label _EQC 'Work Order:' OR Label _EQC 'Epi Part:' OR Label _EQC 'PSN:' OR Label _EQC 'Recipe:' OR Label _EQC 'SCHED_DET Key:' then
                ItemList   := '' : @SVM : '' : @SVM : '700' : @SVM : '0' : @SVM : '1' : @VM
            end else
                ItemList   := '' : @SVM : '' : @SVM : '700' : @SVM : '0' : @SVM : '0' : @VM
            end
            ItemList   := 'Left' : @SVM : 'Center' : @VM
*            If Label _EQC 'Work Order:' OR Label _EQC 'PSN:' OR Label _EQC 'Recipe:' then
            If Label _EQC 'Work Order:' OR Label _EQC 'Epi Part:' OR Label _EQC 'PSN:' OR Label _EQC 'Recipe:' OR Label _EQC 'SCHED_DET Key:' then
                ItemList   := True$ : @VM : False$ : @VM
            end
            ItemList   := @FM
        Next Item
        ItemList[-1, 1] = ''
    end

    Set_Property(PopupCtrl, 'OLE.Theme', 'Custom')
    Set_Property(PopupCtrl, 'OLE.Opacity', 255)
    Set_Property(PopupCtrl, 'OLE.Animation', 'N')
    Set_Property(PopupCtrl, 'OLE.Background', 'Vertical(Gradient(' : Backcolor : ', ' : Backcolor : '), Border(' : Backcolor : ' L=20))' : @FM : 'None' : @FM : 'None')
    Set_Property(PopupCtrl, 'OLE.ItemList', ItemList)
    Set_Property(PopupCtrl, 'OLE.ShowDelay', 1500)
    Set_Property(PopupCtrl, 'OLE.Size', 0 : @FM : 0 : @FM : PopupWidth : @FM : PopupHeight)
    // This identifies the position of the tail. Options are:
    //   Left, Top, Right, Bottom
    Set_Property(PopupCtrl, 'OLE.Pointer', TailPosition)

    Utility('CURSOR', 'A')   

    // This tells the popup to appear at the designated X and Y coordinates which
    // have been calculated above based on the relative location of the order.
    Send_Message(PopupCtrl, 'OLE.ShowAt', PopupX, PopupY)

return


DismissPopup:

    PopupCtrl       = @Window : '.OLE_POPUP'
    PopupVisible    = Get_Property(PopupCtrl, 'OLE.Visible')
    If PopupVisible EQ True$ then
        Send_Message(PopupCtrl, 'OLE.Close')
        Set_Property(CtrlEntId, '@PREVAPPTID', '')
    end

return


ShowWaitMessage:

    Set_Property(@Window : '.OLE_PICTURE', 'OLE.Caption', Caption)
    Set_Property(@Window : '.OLE_PICTURE', 'VISIBLE', 1)
    Set_Property(@Window : '.OLE_SCHEDULE', 'VISIBLE', 0)
    Set_Property(@Window, 'REDRAW', 0)

return


HideWaitMessage:

    Set_Property(@Window : '.OLE_SCHEDULE', 'VISIBLE', 1)
    Set_Property(@Window : '.OLE_PICTURE', 'OLE.Caption', '')
    Set_Property(@Window : '.OLE_PICTURE', 'VISIBLE', 0)
    Set_Property(@Window, 'REDRAW', 1)

return


GetScheduleAppointments:
SRP_Stopwatch('Reset')
SRP_Stopwatch('Start', 'GetScheduleAppointments')
    Ctrl                = @Window : '.OLE_SCHEDULE'
    AppointmentList     = ''
    ApptIDs             = ''
    AppointmentFlags    = ''
*    ScheduleEvents      = Scheduling_Services('GetScheduleEvents', StartDate, EndDate, 23, 164525)
    ScheduleEvents      = Scheduling_Services('GetScheduleEvents', StartDate, EndDate)
    WorkOrderNos        = ''
    EpiPartNos          = ''
    If SRP_JSON(objScheduleEvents, 'PARSE', ScheduleEvents) EQ '' then
        objScheduleEventArray   = SRP_JSON(objScheduleEvents, 'GET', 'ScheduleEvents')
        objScheduleEventList    = SRP_JSON(objScheduleEventArray, 'GETELEMENTS')
        For Each objScheduleEvent in objScheduleEventList using @FM
            // The ParseScheduleEvent gosub parses the Schedule Event object and populates all the variables related
            // to a specific schedule event.
            GoSub ParseScheduleEvent
*            If EventID eq 164525 then Debug
            AppointmentList    := ReactorNo : @VM               ; // Entity ID
            ApptID      = ReactorNo : '*' : StartDate : '*' : EventID
            ApptIDs    := ApptID : @FM
            AppointmentList    := ApptID : @VM
            AppointmentList    := StartDateTime : @VM           ; // Start Date & Time
            AppointmentList    := EndDateTime : @VM             ; // End Date & Time
            AppointmentList    := BackColor : @VM               ; // Back Color
            AppointmentList    := ForeColor : @VM               ; // Fore Color
            If BlockOut then
                Title           = 'Block Out' : ' (' : BlockOutType : ')'
            end else
                WorkOrderNos   := WorkOrderNo : @FM
                EpiPartNos     := EpiPartNo : @FM
                Title           = WorkOrderNo : ' (' : CustNameShort : ' ' : EpiPartNo : ')'
            end
            AppointmentList    := Title : @VM                   ; // Title
            AppointmentList    := Description : @VM             ; // Description
            AppointmentList    := @VM : @VM : @VM : @VM : @VM : @VM : @VM : @VM : @VM : @VM
            AppointmentList    := ScheduleEvent                 ; // Class
            AppointmentList    := @FM
            Flags               = HotLot : @SVM : (Description NE '') : @SVM : Closed : @SVM : Current
            AppointmentFlags   := Flags : @FM
        Next ObjectCount
        AppointmentList[-1, 1]  = ''
        WorkOrderNos[-1, 1]     = ''
        EpiPartNos[-1, 1]       = ''
        ApptIDs[-1, 1]          = ''
        AppointmentFlags[-1, 1] = ''
        SRP_JSON(objScheduleEventArray, 'RELEASE')
    end
    SRP_JSON(objScheduleEvents, 'RELEASE')
SRP_Stopwatch('Stop', 'GetScheduleAppointments')
SRP_Stopwatch('ShowAll')
Debug
return


SetScheduleFlags:

    Ctrl    = @Window : '.OLE_SCHEDULE'
    For Each ApptID in ApptIDs using @FM setting fPos
        Flags    = AppointmentFlags<fPos>
        If Sum(Flags) GT 0 then
            Convert @SVM to @FM in Flags
            Set_Property(Ctrl, 'OLE.ApptFlags[' : ApptID : ']', Flags)
        end
    Next ApptID

return


GetReactorEntities:

    Ctrl    = @Window : '.OLE_SCHEDULE'
    If Memory_Services('IsValueCurrent', Ctrl : '*EntityList', 3600, True$) then
        EntityList  = Memory_Services('GetValue', Ctrl : '*EntityList')
    end else
        EntityList  = ''
        Reactors    = Reactor_Services('GetReactors')
        If SRP_JSON(objReactors, 'PARSE', Reactors) EQ '' then
            objReactorArray     = SRP_JSON(objReactors, 'GET', 'Reactors')
            objReactorList      = SRP_JSON(objReactorArray, 'GETELEMENTS')
            For Each objReactor in objReactorList using @FM
                ReactorNo       = SRP_JSON(objReactor, 'GETVALUE', 'ReactorNumber')
                Type            = SRP_JSON(objReactor, 'GETVALUE', 'TypeVerbose')
                Size            = SRP_JSON(objReactor, 'GETVALUE', 'SusceptorSize')
                Assignment      = SRP_JSON(objReactor, 'GETVALUE', 'AssignmentCode')
                SecondChamber   = SRP_JSON(objReactor, 'GETVALUE', 'SecondChamber')
                Begin Case
                    Case Assignment EQ 'M'
                        // Dedicated
                        Background  = 'Pink'
                    Case Assignment EQ 'C'
                        // Non-Dedicated
                        Background  = 'LightGreen'
                    Case Assignment EQ 'G'
                        // GaN
                        Background  = 'SkyBlue'
                    Case Assignment EQ 'O'
                        // Out-of-Service
                        Background  = 'Silver'
                    Case Otherwise$
                        // Default to Dedicated
                        Background  = 'Pink'
                End Case
                If (Type NE 'EpiPro') OR (SecondChamber NE '') then
                    EntityName  = ReactorNo
                    If SecondChamber NE '' then EntityName := '/' : SecondChamber
                    EntityList := 'ENT' : @VM : 1 : @VM : ReactorNo : @VM : EntityName : @VM : Type : CRLF$ : Size : @VM : 'Black' : @VM : Background : @FM
                end
                SRP_JSON(objReactor, 'RELEASE')
            Next objReactor
            EntityList[-1, 1]   = ''
            SRP_JSON(objReactorArray, 'RELEASE')
        end
        SRP_JSON(objReactors, 'RELEASE')
        Memory_Services('SetValue', Ctrl : '*EntityList', EntityList)
    end

return


ParseScheduleEvent:

    If Assigned(objScheduleEvent) else objScheduleEvent = 0
    If objScheduleEvent LE 0 then
        SRP_JSON(objScheduleEvent, 'PARSE', ScheduleEvent)
    end
    If objScheduleEvent GT 0 then
        EventID             = SRP_JSON(objScheduleEvent, 'GETVALUE', 'EventID')
        ReactorNo           = SRP_JSON(objScheduleEvent, 'GETVALUE', 'Reactor.ReactorNumber')
        ReactorType         = SRP_JSON(objScheduleEvent, 'GETVALUE', 'Reactor.Type')
        SusceptorSize       = SRP_JSON(objScheduleEvent, 'GETVALUE', 'Reactor.SusceptorSize')
        StartDate           = SRP_JSON(objScheduleEvent, 'GETVALUE', 'StartDate')
        StartDate           = Iconv(StartDate, 'D')
        StartTime           = SRP_JSON(objScheduleEvent, 'GETVALUE', 'StartTime')
        StartTime           = Iconv(StartTime, 'MT')
        StartDateTime       = SRP_JSON(objScheduleEvent, 'GETVALUE', 'StartDateTime')
        StartDateTime       = Iconv(StartDateTime, 'DT')
        EndDate             = SRP_JSON(objScheduleEvent, 'GETVALUE', 'EndDate')
        EndDate             = Iconv(EndDate, 'D')
        EndTime             = SRP_JSON(objScheduleEvent, 'GETVALUE', 'EndTime')
        EndTime             = Iconv(EndTime, 'MT')
        EndDateTime         = SRP_JSON(objScheduleEvent, 'GETVALUE', 'EndDateTime')
        EndDateTime         = Iconv(EndDateTime, 'DT')
        BackColor           = SRP_JSON(objScheduleEvent, 'GETVALUE', 'BackColor')
        ForeColor           = SRP_JSON(objScheduleEvent, 'GETVALUE', 'ForeColor')
        ModifiedDTM         = Iconv(SRP_JSON(objScheduleEvent, 'GETVALUE', 'ModifiedDTM'), 'DT')
        BlockOut            = Iconv(SRP_JSON(objScheduleEvent, 'GETVALUE', 'BlockOut'), 'BYes,No')
        BlockOutType        = SRP_JSON(objScheduleEvent, 'GETVALUE', 'BlockOutType')
        Description         = SRP_JSON(objScheduleEvent, 'GETVALUE', 'Note')
        If EndTime EQ 0 then EndTime = 86400
        objWorkOrder        = SRP_JSON(objScheduleEvent, 'GET', 'WorkOrder')
        GoSub ParseWorkOrder
        If BackColor EQ '' then
            Begin Case
                Case BackColor NE ''
                    // Set in the schedule detail record. Use current color.
                Case HotLot
                    BackColor   = 'LightCoral'
                Case Closed
                    BackColor   = 'LightGray'
                Case BlockOut
                    BackColor   = 'Plum'
                Case Otherwise$
                    BackColor   = 'LightSteelBlue'
            End Case
        end
        Current = False$    ; // Assume false for now.
        If (StartDate GE Date()) then
            If (ModifiedDTM NE '') then
                CurrentDTM  = Iconv(Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTH'), 'DTM')
                ElapseTime  = (CurrentDTM - ModifiedDTM) * 24
                IF (ElapseTime LE 12) then
                    CurrentFlag = True$
                end
            end
        end
        If ForeColor EQ '' then ForeColor = 'Black'
        TotalScheduledDays  = SRP_JSON(objScheduleEvent, 'GETVALUE', 'TotalScheduledDays')
        ScheduleEvent       = SRP_JSON(objScheduleEvent, 'STRINGIFY', 'FAST')
        SRP_JSON(objScheduleEvent, 'RELEASE')
    end else
        
    end

return


ParseWorkOrder:

    If Assigned(objWorkOrder) else objWorkOrder = 0
    If objWorkOrder LE 0 then
        SRP_JSON(objWorkOrder, 'PARSE', WorkOrder)
    end
    If objWorkOrder GT 0 then
        WorkOrderNo         = SRP_JSON(objWorkOrder, 'GETVALUE', 'WorkOrderNumber')
        EpiPartNo           = SRP_JSON(objWorkOrder, 'GETVALUE', 'EpiPartNumber')
        PSN                 = SRP_JSON(objWorkOrder, 'GETVALUE', 'PSN')
        Recipe              = SRP_JSON(objWorkOrder, 'GETVALUE', 'Recipe')
        HotLot              = Iconv(SRP_JSON(objWorkOrder, 'GETVALUE', 'HotLot'), 'BYes,No')
        Closed              = Iconv(SRP_JSON(objWorkOrder, 'GETVALUE', 'Closed'), 'BYes,No')
        TotalWafers         = SRP_JSON(objWorkOrder, 'GETVALUE', 'TotalWafers')
        WafersRemaining     = SRP_JSON(objWorkOrder, 'GETVALUE', 'WafersRemaining')
        PercentComplete     = SRP_JSON(objWorkOrder, 'GETVALUE', 'PercentComplete')
        CustNameShort       = SRP_JSON(objWorkOrder, 'GETVALUE', 'Company.NameShort')
        SRP_JSON(objWorkOrder, 'RELEASE')
    end else
        
    end

return

