Function NDW_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        :   NDW_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.
        04/20/21    djs     Updated GetReactorEntities to use PickPlace instead of Dedicated and Non-Dedicated
                            reactor assignments for form color purposes.

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

#pragma precomp SRP_PreCompiler
#Window NDW_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 LOGICAL
$insert SECURITY_RIGHTS_EQU
$insert REACTOR_EQUATES
$insert WO_STEP_EQUATES
$insert SCHEDULE_EVENT_SUMMMARY_EQUATES
$insert SCHED_DET_NG_EQUATES
$insert COMPANY_EQUATES
$insert USER_CONFIG_EQUATES
$insert RLIST_EQUATES

Equ LightGrey$ TO 239 + (239*256) + (239*65536)
Equ LTORANGE$  TO 255 + (220*256) + (128*65536)
Equ Comma$     to ','

Declare function    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    DateTime, Database_Services, SRP_Get_IdleTime, Environment_Services,
Declare function    Logging_Services, GetCurrentProcessID
Declare subroutine  obj_Appwindow, Schedule_Services, Epi_Part_Services, SRP_Stopwatch, SRP_JSON, Database_Services
Declare subroutine  Security_Err_Msg, Start_Window, Messaging_Services, Work_Order_Services, Sleepery, Logging_Services

ProcessID = GetCurrentProcessID()

LogPath     = Environment_Services('GetApplicationRootPath') : '\LogFiles\SchedulerPro'
LogDate     = Oconv(Date(), 'D4/')
LogTime     = Oconv(Time(), 'MTS')
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' ' : @User4 : ' ' : ProcessID : ' Crash Log.csv'
Headers     = 'Logging DTM' : @FM : 'LSL User' : @FM : 'Notes'
objLog      = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, True$)
LoggingDTM  = LogDate : ' ' : LogTime   ; // Logging DTM

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
	
	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)
	
end event


Event WINDOW.CLOSE(CancelFlag)
	
	UserConfigKey   = @User4:'*':@Window
	UserConfigRec   = Get_Property(@Window, '@USER_CONFIG_REC')
	UserConfigProps = UserConfigRec<USER_CONFIG.PROPERTY$>
	UserConfigVals  = UserConfigRec<USER_CONFIG.VALUE$>
	IntervalSize    = Get_Property(@Window:'.OLE_SCHEDULE', 'OLE.IntervalSize')
	Locate 'IntervalSize' in UserConfigProps using @VM setting vPos then
		UserConfigVals<0, vPos> = IntervalSize
	end else
		UserConfigProps<0, -1>               = 'IntervalSize'
		UserConfigVals<0, -1>                = IntervalSize
		UserConfigRec<USER_CONFIG.PROPERTY$> = UserConfigProps
	end
	UserConfigRec<USER_CONFIG.VALUE$> = UserConfigVals
	Database_Services('WriteDataRow', 'USER_CONFIG', UserConfigKey, UserConfigRec, True$, False$, True$)
	
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$)
		SearchAppointmentKeys   = Get_Property(@Window : '.OLE_SCHEDULE', '@SELECTED_KEYIDS')
		If SearchAppointmentKeys NE '' then
			For Each AppointmentKey in SearchAppointmentKeys using @FM
				Appt        = Get_Property(@Window : '.OLE_SCHEDULE', 'OLE.Appt[' : AppointmentKey : ']')
				Flags       = Appt<18>
				Convert @SVM to @FM in Flags
				Begin Case
					Case Flags<1>
						BackColor   = 'LightCoral'
					Case Flags<3>
						BackColor   = 'LightGray'
					Case Otherwise$
						BackColor   = 'LightSteelBlue'
				End Case
				Appt<4>     = BackColor
				Appt<5>     = 'Black'
				Set_Property(@Window : '.OLE_SCHEDULE', 'OLE.Appt[' : AppointmentKey : ']', Appt)
			Next AppointmentKey
		end
		SearchAppointmentKeys   = ''
		AppointmentList         = Get_Property(@Window : '.OLE_SCHEDULE', 'OLE.AppointmentList')
		AppointmentArray        = SRP_Array('Rotate', AppointmentList, @FM, @VM)
		AllAppointmentKeys      = AppointmentArray<2>
		For Each AppointmentKey in AllAppointmentKeys using @VM setting vPos
			WorkOrderNo = Xlate('SCHED_DET_NG', AppointmentKey, 'WO_NO', 'X')
			If WorkOrderNo EQ SearchWorkOrderNo then
				SearchAppointmentKeys := AppointmentKey : @FM
			end
		Next AppointmentKey
		SearchAppointmentKeys[-1, 1]   = ''
		For Each AppointmentKey in SearchAppointmentKeys using @FM
			Appt        = Get_Property(@Window : '.OLE_SCHEDULE', 'OLE.Appt[' : AppointmentKey : ']')
			Flags       = Appt<18>
			Convert @SVM to @FM in Flags
			Begin Case
				Case Flags<1>
					BackColor   = 'LightCoral L=40'
				Case Flags<3>
					BackColor   = 'LightGray L=40'
				Case Otherwise$
					BackColor   = 'LightSteelBlue L=40'
			End Case
			Appt<4>     = BackColor
			Appt<5>     = 'White'
			Set_Property(@Window : '.OLE_SCHEDULE', 'OLE.Appt[' : AppointmentKey : ']', Appt)
		Next AppointmentKey
		Set_Property(@Window : '.OLE_SCHEDULE', '@SELECTED_KEYIDS', SearchAppointmentKeys)
		Send_Message(@Window : '.OLE_SCHEDULE', 'OLE.EnsureVisible', SearchAppointmentKeys<1>)
		Set_Property(@Window : '.OLE_SCHEDULE', 'OLE.SelAppt[' : SearchAppointmentKeys<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$)
		SearchAppointmentKeys   = Get_Property(@Window : '.OLE_SCHEDULE', '@SELECTED_KEYIDS')
		If SearchAppointmentKeys NE '' then
			For Each AppointmentKey in SearchAppointmentKeys using @FM
				Appt        = Get_Property(@Window : '.OLE_SCHEDULE', 'OLE.Appt[' : AppointmentKey : ']')
				Flags       = Appt<18>
				Convert @SVM to @FM in Flags
				Begin Case
					Case Flags<1>
						BackColor   = 'LightCoral'
					Case Flags<3>
						BackColor   = 'LightGray'
					Case Otherwise$
						BackColor   = 'LightSteelBlue'
				End Case
				Appt<4>     = BackColor
				Appt<5>     = 'Black'
				Set_Property(@Window : '.OLE_SCHEDULE', 'OLE.Appt[' : AppointmentKey : ']', Appt)
			Next AppointmentKey
		end
		SearchAppointmentKeys   = ''
		AppointmentList         = Get_Property(@Window : '.OLE_SCHEDULE', 'OLE.AppointmentList')
		AppointmentArray        = SRP_Array('Rotate', AppointmentList, @FM, @VM)
		AllAppointmentKeys      = AppointmentArray<2>
		For Each AppointmentKey in AllAppointmentKeys using @VM setting vPos
			WorkOrderNo = Xlate('SCHED_DET_NG', AppointmentKey, 'WO_NO', 'X')
			EpiPartNo   = Xlate('WO_LOG', WorkOrderNo, 'EPI_PART_NO', 'X')
			If EpiPartNo EQ SearchEpiPartNo then
				SearchAppointmentKeys := AppointmentKey : @FM
			end
		Next AppointmentKey
		SearchAppointmentKeys[-1, 1]   = ''
		For Each AppointmentKey in SearchAppointmentKeys using @FM
			Appt        = Get_Property(@Window : '.OLE_SCHEDULE', 'OLE.Appt[' : AppointmentKey : ']')
			Flags       = Appt<18>
			Convert @SVM to @FM in Flags
			Begin Case
				Case Flags<1>
					BackColor   = 'LightCoral L=40'
				Case Flags<3>
					BackColor   = 'LightGray L=40'
				Case Otherwise$
					BackColor   = 'LightSteelBlue L=40'
			End Case
			Appt<4>     = BackColor
			Appt<5>     = 'White'
			Set_Property(@Window : '.OLE_SCHEDULE', 'OLE.Appt[' : AppointmentKey : ']', Appt)
		Next AppointmentKey
		Set_Property(@Window : '.OLE_SCHEDULE', '@SELECTED_KEYIDS', SearchAppointmentKeys)
		Send_Message(@Window : '.OLE_SCHEDULE', 'OLE.EnsureVisible', SearchAppointmentKeys<1>)
		Set_Property(@Window : '.OLE_SCHEDULE', 'OLE.SelAppt[' : SearchAppointmentKeys<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)
	
	PopupCtrl    = @Window : '.OLE_POPUP'
	PopupVisible = Get_Property(PopupCtrl, 'OLE.Visible')
	If PopupVisible EQ True$ then GoSub DismissPopup
	
	If Button EQ 'Left' then
		SchedEventRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', ApptID)
		WorkOrderNo   = SchedEventRec<SCHED_DET_NG.WO_NO$>
		EpiPartNo     = Xlate('WO_LOG', WorkOrderNo, 'EPI_PART_NO', 'X')
		ReactorNo     = SchedEventRec<SCHED_DET_NG.REACT_NO$>
		StartDate     = Field(SchedEventRec<SCHED_DET_NG.START_DTM$>, '.', 1)
		WOStepKey     = WorkOrderNo : '*1'
		ReactType     = Xlate('REACTOR', ReactorNo, 'REACT_TYPE', 'X')
		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
					RDSKeys = Schedule_Services('GetEventRDSKeys', ApptID)
					
					If RDSKeys NE '' then
						SelRDSKeys = Dialog_Box('NDW_RDS_QUERY', @Window, RDSKeys)
						IF SelRDSKeys NE '' THEN
							Void = Start_Window( 'RDS', @window, SelRDSKeys:'*CENTER', '', '' )
						END
					end else
						MsgStruct         = ''
						MsgStruct<MICON$> = '*' ; // Information icon
						Msg(@Window, MsgStruct, 'OK', '', 'Scheduler':@FM:'RDS records for this work order event do not yet exist.')
					end
				end else
					security_err_msg( 'RDS', Read$ )                  
				end
				
			CASE ChosenOpt = 'WO'
				if security_check( 'WO Log', Read$ ) then
					Start_Window('NDW_WO_LOG', @Window, WorkOrderNo)
				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)
	
	ContextMenu     = ''
	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 : @FM
		end
	end
	
	If (@Station[1, 11] _EQC 'MESIRWAP001') OR (@Station[1, 9] _EQC 'MESSA01EC') then
		If Button EQ 'Right' AND Location EQ 'Entity' then
			If ContextMenu NE '' then
				ContextMenu    := '' : @FM
			end
			ContextMenu    := 'ADJUSTREACTOR' : @VM : 'Auto Adjust Reactor ' : EntityId : @VM : 1 : @FM
			ContextMenu    := '' : @FM
			ContextMenu    := 'ADJUSTREACTORLOGONLY' : @VM : 'Auto Adjust Reactor ' : EntityId : ' (Log Only)' : @VM : 1 : @FM
			ContextMenu    := 'ADJUSTALLREACTORSLOGONLY' : @VM : 'Auto Adjust All Reactors (Log Only)' : @VM : 1 : @FM
		end
	end
	
	If ContextMenu NE '' then
		ContextMenu[-1, 1] = ''
		X                  = Field(Point, ',', 1)
		StartDTM           = Send_Message(CtrlEntId, 'OLE.MapClientToTime', X, 1)
		Send_Message(CtrlEntId, 'OLE.ShowContextMenu', Point, ContextMenu, EntityID : @VM : StartDTM)
	end
	
end event


Event OLE_SCHEDULE.OnApptHover(ApptID, Point)
	
	PopupCtrl    = @Window : '.OLE_POPUP'
	Set_Property(@Window, '@PREV_APPT_ID', ApptID)
	PopupVisible = Get_Property(PopupCtrl, 'OLE.Visible')
	If PopupVisible EQ False$ then GoSub DisplayPopup
	
end event


Event OLE_SCHEDULE.OnScheduleMouseMove(EntityId, ApptID, Location, Point, Shift, Ctrl)
	
	PrevApptID   = Get_Property(@Window, '@PREV_APPT_ID')
	If ( (ApptID EQ '') or (ApptID NE PrevApptID) ) then
		GoSub DismissPopup
	end
	
end event


Event OLE_SCHEDULE.OnApptClick(ApptID, Button, Shift, Ctrl, Point)
	
	Begin Case
		Case Button EQ 'Left'
			Null
			
		Case Button EQ 'Right'
			ScheduleDetail  = Schedule_Services('GetScheduleDetail', ApptID)
			ReactorNo       = ScheduleDetail<SCHED_DET_NG.REACT_NO$>
			WONo            = ScheduleDetail<SCHED_DET_NG.WO_NO$>
			ProcessedCass   = ScheduleDetail<SCHED_DET_NG.PROCESSED_CASS$>
			UnprocessedCass = ScheduleDetail<SCHED_DET_NG.UNPROCESSED_CASS$>
			InProgress      = (ProcessedCass NE '')
			EligibleToStop  = False$
			EpiPro          = (Xlate('WO_LOG', WONo, 'REACT_TYPE', 'X') EQ 'EPP')
			For each CassNo in UnprocessedCass using @VM setting vPos
				WOMatKey = WONo:'*':CassNo
				If EpiPro then
					WMIKey = WONo:'*1*':CassNo
					RDSNos = Xlate('WM_IN', WMIKey, 'RDS_NO', 'X')
					RDSNo  = RDSNos<0, 25>
				end else
					RDSNo  = Xlate('WO_MAT', WOMatKey, 'RDS_NO', 'X')
				end
				DateIn = Xlate('RDS', RDSNo, 'DATE_IN', 'X')
				If DateIn EQ '' then EligibleToStop = True$
			Until EligibleToStop EQ True$
			Next CassNo
			
			ContextMenu     = ''
			If MemberOf(@USER4, 'SCHEDULER_ADMIN') OR MemberOf(@USER4, 'SCHEDULER_MASTER') then
				BlockOut       = ScheduleDetail<SCHED_DET_NG.BLOCK_OUT$>
				If BlockOut then
					ContextMenu    := 'CANCELBLOCK' : @VM : 'Cancel Block Out Event...' : @VM : 1 : @FM
				end else
					WorkOrderNo = ScheduleDetail<SCHED_DET_NG.WO_NO$>
					HotFlag     = Xlate('WO_LOG', WONo, 'HOT_FLAG', 'X')
					If HotFlag then
						ContextMenu := 'REMOVE_HOT_FLAG' : @VM : 'Remove Hot Flag' : @VM : 1 : @FM
					end else
						ContextMenu := 'ADD_HOT_FLAG' : @VM : 'Add Hot Flag' : @VM : 1 : @FM
					end
					ContextMenu := '' : @FM
					ContextMenu := 'ADD' : @VM : 'Add Work Order Events...' : @VM : 1 : @FM
					ContextMenu := '' : @FM
					ContextMenu := 'MODIFY' : @VM : 'Modify Work Order Event...' : @VM : 1 : @FM
					ContextMenu := '' : @FM
					If InProgress EQ True$ then
						ContextMenu := 'STOP' : @VM : 'Stop Work Order Event...' : @VM : EligibleToStop : @FM
					end else
						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 for ' : WorkOrderNo : @VM : 1 : @FM
					If MemberOf(@USER4, 'SCHEDULER_MASTER') then
						ContextMenu := '' : @FM
						ContextMenu := 'REMOVEEVENT' : @VM : 'Remove This Work Order Event' : @VM : 1 : @FM
					end
				end
				
			end
			
			If ContextMenu NE '' then
				ContextMenu[-1, 1] = ''
				X                  = Field(Point, ',', 1)
				DateTime           = Send_Message(CtrlEntId, 'OLE.MapClientToTime', X, 1)
				StartDate          = DateTime[1, '.']
				UserData           = ''
				UserData<0, 1>     = ReactorNo
				UserData<0, 2>     = DateTime
				UserData<0, 3>     = ApptID
				Send_Message(CtrlEntId, 'OLE.ShowContextMenu', Point, ContextMenu, UserData)
			end
			
	End Case
	
end event


Event OLE_SCHEDULE.OnContextMenuClick(Item, UserData)
	
	PopupCtrl    = @Window : '.OLE_POPUP'
	PopupVisible = Get_Property(PopupCtrl, 'OLE.Visible')
	If PopupVisible EQ True$ then GoSub DismissPopup
	
	Convert @VM to @FM in UserData
	ReactorNo = UserData<1>
	SchedDTM  = UserData<2>
	ApptID    = UserData<3>
	RefreshWO = Xlate('SCHED_DET_NG', ApptID, 'WO_NO', 'X')
	RemAppts  = Xlate('REACTOR', ReactorNo, 'SCHED_EVENTS', 'X')
	Swap @VM with @FM in RemAppts
	
	Begin Case
		
		Case Item EQ 'ADD_HOT_FLAG'
			
			Work_Order_Services('SetHotFlag', RefreshWO, True$)
			If Error_Services('NoError') then
				ScheduleEventSummary  = Schedule_Services('GetScheduleEventSummary', ApptID, False$)
				Send_Message(CtrlEntID, 'OLE.RemoveAppts', ApptID)
				ScheduleEvent         = ReactorNo : @VM
				ScheduleEvent        := ApptID : @VM 
				ScheduleEvent        := ScheduleEventSummary<SES_STARTDTM$> : @VM
				ScheduleEvent        := ScheduleEventSummary<SES_ENDDTM$> : @VM
				ScheduleEvent        := ScheduleEventSummary<SES_BACKCOLOR$> : ' L=' : 80 : @VM
				ScheduleEvent        := ScheduleEventSummary<SES_FORECOLOR$> : @VM
				ScheduleEvent        := ScheduleEventSummary<SES_TITLE$> : @VM
				ScheduleEvent        := ScheduleEventSummary<SES_DESCRIPTION$> : @VM
				ScheduleEvent        := @VM : @VM : @VM : @VM : @VM : @VM : @VM : @VM : @VM : @VM
				ScheduleEvent        := ScheduleEventSummary<SES_HOTLOTFLAG$> : @SVM : ScheduleEventSummary<SES_NOTEFLAG$> : @SVM : ScheduleEventSummary<SES_WOCLOSEDFLAG$> : @SVM : ScheduleEventSummary<SES_CURRENTFLAG$>
				Send_Message(CtrlEntID, 'OLE.AddAppts', ScheduleEvent)
				Send_Event('REACT_STATUS_EVEN', 'TIMER')
				Send_Event('REACT_STATUS_ODD', 'TIMER')
				WOLogVis              = Get_Property('NDW_WO_LOG', 'VISIBLE')
				If WOLogVis then
					FormWONo = Get_Property('NDW_WO_LOG.EDL_WO_NO', 'TEXT')
					If FormWONo EQ RefreshWO then Set_Property('NDW_WO_LOG.CHB_HOT_FLAG', 'CHECK', True$)
				end
			end else
				Error_Services('DisplayError')
			end
			
		Case Item EQ 'REMOVE_HOT_FLAG'
			
			Work_Order_Services('SetHotFlag', RefreshWO, False$)
			If Error_Services('NoError') then
				ScheduleEventSummary  = Schedule_Services('GetScheduleEventSummary', ApptID, False$)
				Send_Message(CtrlEntID, 'OLE.RemoveAppts', ApptID)
				ScheduleEvent         = ReactorNo : @VM
				ScheduleEvent        := ApptID : @VM 
				ScheduleEvent        := ScheduleEventSummary<SES_STARTDTM$> : @VM
				ScheduleEvent        := ScheduleEventSummary<SES_ENDDTM$> : @VM
				ScheduleEvent        := ScheduleEventSummary<SES_BACKCOLOR$> : ' L=' : 80 : @VM
				ScheduleEvent        := ScheduleEventSummary<SES_FORECOLOR$> : @VM
				ScheduleEvent        := ScheduleEventSummary<SES_TITLE$> : @VM
				ScheduleEvent        := ScheduleEventSummary<SES_DESCRIPTION$> : @VM
				ScheduleEvent        := @VM : @VM : @VM : @VM : @VM : @VM : @VM : @VM : @VM : @VM
				ScheduleEvent        := ScheduleEventSummary<SES_HOTLOTFLAG$> : @SVM : ScheduleEventSummary<SES_NOTEFLAG$> : @SVM : ScheduleEventSummary<SES_WOCLOSEDFLAG$> : @SVM : ScheduleEventSummary<SES_CURRENTFLAG$>
				Send_Message(CtrlEntID, 'OLE.AddAppts', ScheduleEvent)
				Send_Event('REACT_STATUS_EVEN', 'TIMER')
				Send_Event('REACT_STATUS_ODD', 'TIMER')
				WOLogVis              = Get_Property('NDW_WO_LOG', 'VISIBLE')
				If WOLogVis then
					FormWONo = Get_Property('NDW_WO_LOG.EDL_WO_NO', 'TEXT')
					If FormWONo EQ RefreshWO then Set_Property('NDW_WO_LOG.CHB_HOT_FLAG', 'CHECK', False$)
				end
			end else
				Error_Services('DisplayError')
			end
			
		Case Item EQ 'ADD'
			
			AddEventDetails = Dialog_Box('NDW_SCHEDULER_ADD_WO', @Window, UserData)
			
			If AddEventDetails NE '' then
				Caption     = 'Please wait...updating the schedule'
				GoSub ShowWaitMessage
				ReactorNo   = AddEventDetails<1>
				WorkOrder   = AddEventDetails<2>
				RefreshWO   = WorkOrder
				StartDTM    = AddEventDetails<3>
				StopDTM     = AddEventDetails<4>
				Description = AddEventDetails<5>
				WaferQty    = AddEventDetails<6>
				NewApptID   = Schedule_Services('AddSchedEvent', ReactorNo, WorkOrder, StartDTM, StopDTM, Description, WaferQty)
				NewAppt     = Schedule_Services('GetScheduleEvent', NewApptID)
				If Error_Services('NoError') then
					GoSub RefreshReactor
					If NewApptID NE '' then
						SchedRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', NewApptID)
						Schedule_Services('NotifySupervisorsIfSameDayChange', SchedRec)
					end
				end else
					Error_Services('DisplayError')
				end
				GoSub HideWaitMessage
			end
			
		Case Item EQ 'MODIFY'
			
			ModifyEventDetails = Dialog_Box('NDW_SCHEDULER_MODIFY_WO', @Window, UserData)
			
			If ModifyEventDetails NE '' then
				Caption     = 'Please wait...updating the schedule'
				GoSub ShowWaitMessage
				
				OrigRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', ApptID)
				
				ReactorNo   = ModifyEventDetails<1>
				WorkOrder   = ModifyEventDetails<2>
				RefreshWO   = WorkOrder
				StartDTM    = ModifyEventDetails<3>
				StopDTM     = ModifyEventDetails<4>
				Description = ModifyEventDetails<5>
				WaferQty    = ModifyEventDetails<6>
				Schedule_Services('ModifySchedEvent', ApptID, ReactorNo, WorkOrder, StartDTM, StopDTM, Description, WaferQty)
				
				If Error_Services('NoError') then
					GoSub RefreshReactor
					If ApptID NE '' then
						SchedRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', ApptID)
						Schedule_Services('NotifySupervisorsIfSameDayChange', SchedRec, OrigRec)
					end
				end else
					Error_Services('DisplayError')
				end
				GoSub HideWaitMessage
			end
			
		Case Item EQ 'STOP'
			
			StopEventDetails = Dialog_Box('NDW_SCHEDULER_STOP_WO', @Window, UserData)
			
			If StopEventDetails NE '' then
				Caption     = 'Please wait...updating the schedule'
				GoSub ShowWaitMessage
				
				OrigRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', ApptID)
				
				ReactorNo   = StopEventDetails<1>
				WorkOrder   = StopEventDetails<2>
				RefreshWO   = WorkOrder
				StartDTM    = StopEventDetails<3>
				StopDTM     = StopEventDetails<4>
				Description = StopEventDetails<5>
				WaferQty    = StopEventDetails<6>
				Schedule_Services('ModifySchedEvent', ApptID, ReactorNo, WorkOrder, StartDTM, StopDTM, Description, WaferQty)
				
				If Error_Services('NoError') then
					GoSub RefreshReactor
					If ApptID NE '' then
						SchedRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', ApptID)
						Schedule_Services('NotifySupervisorsIfSameDayChange', SchedRec, OrigRec)
					end
				end else
					Error_Services('DisplayError')
				end
				GoSub HideWaitMessage
			end
			
		Case Item EQ 'CANCEL'
			
			Response = Dialog_Box('NDW_SCHEDULER_CANCEL_WO', @Window, UserData)
			If Response EQ 'Proceed' then
				Caption   = 'Please wait...updating the schedule'
				GoSub ShowWaitMessage
				
				OrigRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', ApptID)
				
				Schedule_Services('CancelScheduleEvent', ApptID)
				If Error_Services('NoError') then
					GoSub RefreshReactor
					If ApptID NE '' then
						SchedRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', ApptID)
						Schedule_Services('NotifySupervisorsIfSameDayChange', SchedRec, OrigRec)
					end
				end else
					Error_Services('DisplayError')
				end
				GoSub HideWaitMessage
			end
			
		Case Item EQ 'ADDBLOCK'
			
			BlockEventDetails = Dialog_Box('NDW_SCHEDULER_ADD_BLOCK', @Window, UserData)
			If BlockEventDetails NE '' then
				Caption            = 'Please wait...updating the schedule'
				GoSub ShowWaitMessage
				BlockReactorNo     = BlockEventDetails<1>
				BlockStartDTM      = BlockEventDetails<2>
				BlockStopDTM       = BlockEventDetails<3>
				BlockComment       = BlockEventDetails<4>
				BlockType          = BlockEventDetails<5>
				BlockOption        = BlockEventDetails<6>
				
				BlockId = Schedule_Services('AddBlockOutEvent', BlockReactorNo, BlockStartDTM, BlockStopDTM, BlockType, BlockComment, BlockOption)
				
				If Error_Services('NoError') then
					GoSub RefreshReactor
					If BlockID NE '' then
						SchedRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', BlockID)
						Schedule_Services('NotifySupervisorsIfSameDayChange', SchedRec)
					end
				end else
					Error_Services('DisplayError')
				end
				GoSub HideWaitMessage
			end
			
		Case Item EQ 'CANCELBLOCK'
			
			Response = Msg(@Window, MsgStruct, 'YESNO', '', 'Cancel Block Out' : @FM : 'Cancel block out event?')
			If Response EQ True$ then
				Caption   = 'Please wait...updating the schedule'
				GoSub ShowWaitMessage
				
				OrigRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', ApptID)
				
				ReactorNo     = Xlate('SCHED_DET_NG', ApptID, 'REACT_NO', 'X')
				UpdatedEvents = Schedule_Services('CancelScheduleEvent', ApptID, True$)
				If Error_Services('NoError') then
					GoSub RefreshReactor
					If ApptID NE '' then
						SchedRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', ApptID)
						Schedule_Services('NotifySupervisorsIfSameDayChange', SchedRec, OrigRec)
					end
				end else
					Error_Services('DisplayError')
				end 
				GoSub HideWaitMessage
			end
			
		Case Item EQ 'REMOVEEVENT'
			Caption   = 'Please wait...updating the schedule'
			GoSub ShowWaitMessage
			
			OrigRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', ApptID)
			
			Schedule_Services('DeleteScheduleDetail', ApptID)
			Send_Message(CtrlEntId, 'RemoveAppts', ApptID)
			
			If Error_Services('NoError') then
				GoSub RefreshReactor
				If ApptID NE '' then
					SchedRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', ApptID)
					Schedule_Services('NotifySupervisorsIfSameDayChange', SchedRec, OrigRec)
				end
			end else
				Error_Services('DisplayError')
			end 
			GoSub HideWaitMessage
			
	End Case
	
	If ( (RefreshWO NE '') and (Item NE 'ADD_HOT_FLAG') and (Item NE 'REMOVE_HOT_FLAG') ) then
		Work_Order_Services('UpdateUnscheduledQuantities', RefreshWO)
	end
	
end event


Event OLE_SCHEDULE.OnDateChange(Date)
	
	DateList            = Get_Property(CtrlEntId, '@DATE_LIST')
	ReloadStartDate     = Date - 60
	ReloadEndDate       = Date + 60
	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
		AppointmentList     = Schedule_Services('GetScheduleEvents', ReloadStartDate, ReloadEndDate)
		Set_Property(@Window, '@APPT_LIST', AppointmentList)
		Send_Message(CtrlEntId, 'OLE.AddAppts', AppointmentList)
		// The SetScheduleFlags gosub loops through the AppointmentKeys array and parses the AppointmentFlags
		// array for the ApptFlags property.
		AppointmentArray    = SRP_Array('Rotate', AppointmentList, @FM, @VM)
		AppointmentKeys     = AppointmentArray<2>
		Convert @VM to @FM in AppointmentKeys
		AppointmentFlags    = AppointmentArray<19>
		Convert @VM to @FM in AppointmentFlags
		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')
	objReactors = ''
	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)
	
	GoSub RefreshSchedule
	
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')
	SchedDetNGRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', ApptID)
	WorkOrderNo   = SchedDetNGRec<SCHED_DET_NG.WO_NO$>
	EpiPartNo     = Xlate('WO_LOG', WorkOrderNo, 'EPI_PART_NO', 'X')
	ReactorNo     = SchedDetNGRec<SCHED_DET_NG.REACT_NO$>
	StartDate     = Field(SchedDetNGRec<SCHED_DET_NG.START_DTM$>, '.', 1)
	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            
				Void = start_window( 'NDW_WO_LOG', @window, WorkOrderNo, '', '' )
			end else
				security_err_msg( 'WO Log', Read$ )
			end
			
		Case PreviousCaption _EQC 'Epi Part:'
			
			Void = start_window( 'EPI_PART', @window, EpiPartNo : '*CENTER', '', '' )
			
		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_NG' : @FM : SchedDetKeyID, 1)
			
	End Case
	
end event


Event OLE_PUB_ZOOM_IN.OnClick(Point, Button, Shift, Ctrl)
	
	PopupCtrl    = @Window : '.OLE_POPUP'
	PopupVisible = Get_Property(PopupCtrl, 'OLE.Visible')
	If PopupVisible EQ True$ then GoSub DismissPopup
	Ctrl          = @Window : '.OLE_SCHEDULE'
	IntervalSize  = Get_Property(Ctrl, 'OLE.IntervalSize')
	IntervalSize += 2
	Set_Property(Ctrl, 'OLE.IntervalSize', IntervalSize) ; // Space (width) for each time increment (in pixels)
	ZoomPercent   = ((IntervalSize + 1) * 10):'%'
	Set_Property(@Window:'.LBL_ZOOM_PERCENT', 'TEXT', ZoomPercent)
	GoSub EnableZoomButtons
	
end event


Event OLE_PUB_ZOOM_OUT.OnClick(Point, Button, Shift, Ctrl)
	
	PopupCtrl     = @Window : '.OLE_POPUP'
	PopupVisible  = Get_Property(PopupCtrl, 'OLE.Visible')
	If PopupVisible EQ True$ then GoSub DismissPopup
	Ctrl          = @Window : '.OLE_SCHEDULE'
	IntervalSize  = Get_Property(Ctrl, 'OLE.IntervalSize')
	IntervalSize -= 2
	Set_Property(Ctrl, 'OLE.IntervalSize', IntervalSize) ; // Space (width) for each time increment (in pixels)
	ZoomPercent   = ((IntervalSize + 1) * 10):'%'
	Set_Property(@Window:'.LBL_ZOOM_PERCENT', 'TEXT', ZoomPercent)
	GoSub EnableZoomButtons
	
end event


Event WINDOW.OMNIEVENT(Message, Param1, Param2, Param3, Param4)
	
	If Message EQ 'RefreshSchedule' then
		Sender       = Param1
		If Sender NE @User4 then
			// Only update the schedule if someone else sent the update message (e.g. the auto-scheduler service).
			PopupCtrl    = @Window : '.OLE_POPUP'
			PopupVisible = Get_Property(PopupCtrl, 'OLE.Visible')
			If PopupVisible EQ True$ then GoSub DismissPopup
			Caption      = 'Please wait...refreshing schedule'
			GoSub ShowWaitMessage
			GoSub UpdateAppointmentList
			GoSub HideWaitMessage  
		end
	end
	
end event

Event WINDOW.INACTIVATED()
	
	PopupCtrl    = @Window : '.OLE_POPUP'
	PopupVisible = Get_Property(PopupCtrl, 'OLE.Visible')
	If PopupVisible EQ True$ then GoSub DismissPopup
	
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() - 120
	EndDate     = Date() + 120
	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
	UserConfigKey   = @User4:'*':@Window
	UserConfigRec   = Database_Services('ReadDataRow', 'USER_CONFIG', UserConfigKey)
	If UserConfigRec NE '' then
		Set_Property(@Window, '@USER_CONFIG_REC', UserConfigRec)
		UserConfigProps = UserConfigRec<USER_CONFIG.PROPERTY$>
		UserConfigVals  = UserConfigRec<USER_CONFIG.VALUE$>
		Locate 'IntervalSize' in UserConfigProps using @VM setting vPos then
			IntervalSize = UserConfigVals<0, vPos>
			ZoomPercent   = ((IntervalSize + 1) * 10):'%'
			Set_Property(@Window:'.LBL_ZOOM_PERCENT', 'TEXT', ZoomPercent)
		end else
			IntervalSize = 11
		end
	end else
		IntervalSize = 11
	end
	Set_Property(Ctrl, 'OLE.IntervalSize', IntervalSize)	; // Space (width) for each time increment (in pixels)
	Set_Property(Ctrl, 'OLE.TimeRange', 0 :@FM: 24 :@FM: 4)		; // <3> is hour display increment

	// 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>  = 'Center'
	Layout<1, 7>  = 'Center'
	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>  = 'Center'
	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, AppointmentKeys, and AppointmentFlags variables.
	GoSub GetScheduleAppointments
	Set_Property(Ctrl, 'OLE.AppointmentList', AppointmentList)
	// The SetScheduleFlags gosub loops through the AppointmentKeys 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', Qualify)
	Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnApptDblClick', Qualify)
	Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnScheduleClick', Qualify)
	Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnContextMenuClick', Qualify)
	Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnApptHover', Qualify)
	Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnScheduleMouseMove', Qualify)
	Set_Property(Ctrl, "OLE.EnableMouseMoveEvent", True$)
	Send_Message(@Window:'.OLE_PUB_ZOOM_IN', 'QUALIFY_EVENT', 'OLE.OnClick', Qualify)
	Send_Message(@Window:'.OLE_PUB_ZOOM_OUT', 'QUALIFY_EVENT', 'OLE.OnClick', Qualify)
	
	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)
	
	Qualify<4> = 1
	Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnDateChange', Qualify)
	Qualify<4> = 0
	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'
	ApptIDs     = AppointmentArray<2>
	WorkOrders  = Xlate('SCHED_DET_NG', ApptIDs, 'WO_NO', 'X')
	Convert @VM to @FM in WorkOrders
	Convert '*' to @VM in WorkOrders
	WorkOrders  = SRP_Array('Rotate', WorkOrders, @FM, @VM)
	WorkOrders  = WorkOrders<1>
	Convert @VM to @FM in WorkOrders
	WorkOrders  = SRP_Array('Clean', WorkOrders, 'TrimAndMakeUnique', @FM)
	WorkOrders  = SRP_Array('SortRows', WorkOrders, 'AR1', 'LIST', @FM, @VM)
	Convert @FM to @STM in WorkOrders
	Combo       = ''
	Combo<1>    = 1
	Combo<2, 1> = ''
	Combo<2, 2> = 'L' : @STM : 'DYN'
	Combo<2, 3> = WorkOrders
	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)
	
	EditLine = @Window : '.EDL_EPI_PART_SEARCH'
	Handle   = Get_Property(EditLine, 'HANDLE')
	Send_Message(Ctrl, 'OLE.Subclass', Handle, EditLine)
	EditLine = @Window : ';EDL_EPI_PART_SEARCH'
	Convert @STM to @VM in WorkOrders
	EpiParts = Xlate('WO_LOG', WorkOrders, 'EPI_PART_NO', 'X')
	Convert @VM to @FM in EpiParts
	Convert '*' to @VM in EpiParts
	EpiParts = SRP_Array('Rotate', EpiParts, @FM, @VM)
	Convert @VM to @FM in EpiParts
	EpiParts = SRP_Array('Clean', EpiParts, 'TrimAndMakeUnique', @FM)
	OSWrite EpiParts to 'E:\apps\Temp\TEMP\EpiParts.txt'
	EpiParts = SRP_Array('SortRows', EpiParts, 'AR1', 'LIST', @FM, @VM)
	
	Convert @FM to @STM in EpiParts
	Combo       = ''
	Combo<1>    = 1
	Combo<2, 1> = ''
	Combo<2, 2> = 'L' : @STM : 'DYN'
	Combo<2, 3> = EpiParts
	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)
	
	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)
	GoSub EnableZoomButtons
	
return


DisplayPopup:
	
	Utility('CURSOR', 'H')
	Set_Property(PopupCtrl, '@APPTID', ApptID)
	Appt        = Get_Property(CtrlEntID, 'OLE.Appt[' : ApptID : ']')
	HoverData   = ''
	BackColor   = 'LightSteelBlue'; //Appt<4>   ; // Use the same BackColor of the current appointment as the base.
	EventRec    = Database_Services('ReadDataRow', 'SCHED_DET_NG', ApptID)
	WorkOrderNo = EventRec<SCHED_DET_NG.WO_NO$>;
	EpiPartNo   = Xlate('WO_LOG', WorkOrderNo, 'EPI_PART_NO', 'X')
	ReactorNo   = EventRec<SCHED_DET_NG.REACT_NO$>
	Date        = EventRec<SCHED_DET_NG.START_DTM$>
	Sequence    = ''
	Summary     = Schedule_Services('GetScheduleEventSummary', ApptID, True$)
	
	BlockOut    = Summary<SES_BLOCK_OUT$>
	If BlockOut then
		HoverData    := 'Reactor:' : @VM : ReactorNo : @FM
		HoverData    := 'Type:' : @VM : Summary<SES_TYPE$> : @FM
		HoverData    := 'Block Type: ' : @VM : Summary<SES_BLOCK_TYPE$> :@FM
		HoverData    := 'Start Date:' : @VM : OConv(Summary<SES_STARTDTM$>, 'DT/^3H') : @FM
		HoverData    := 'End Date:' : @VM : OConv(Summary<SES_ENDDTM$>, 'DT/^3H') : @FM
		HoverData    := 'Total Days:' : @VM : Summary<SES_TOTALDAYS$>
	end else
		HoverData := 'Reactor:' : @VM : ReactorNo : @FM
		HoverData := 'Type:' : @VM : Summary<SES_TYPE$> : @FM
		HoverData := 'Susceptor:' : @VM : Summary<SES_SUSCEPTOR$> : @FM
		HoverData := 'Work Order:' : @VM : WorkOrderNo : @FM
		HoverData := 'Customer:' : @VM : Summary<SES_CUSTNAMESHORT$> : @FM
		HoverData := 'Epi Part:' : @VM : EpiPartNo : @FM
		HoverData := 'PSN:' : @VM : Summary<SES_PSN$> : @FM
		HoverData := 'Recipe:' : @VM : Summary<SES_RECIPE$> : @FM
		HoverData := 'Start Date:' : @VM : OConv(Summary<SES_STARTDTM$>, 'DT/^3H') : @FM
		HoverData := 'End Date:' : @VM : OConv(Summary<SES_ENDDTM$>, 'DT/^3H') : @FM
		HoverData := 'Total Days:' : @VM : Summary<SES_TOTALDAYS$> : @FM
		HoverData := 'Total Wafers:' : @VM : Summary<SES_TOTALWAFERS$> : @FM
		HoverData := 'Remaining Wafers:' : @VM : Summary<SES_REMAINING$> : @FM
		HoverData := 'Complete:' : @VM : Summary<SES_COMPLETE$>
	end
	
	Note         = Summary<SES_DESCRIPTION$>
	If Note NE '' then
		HoverData  := @FM : 'Note:' : @VM : Summary<SES_DESCRIPTION$>
	end
	If MemberOf(@USER4, 'OI_ADMIN') then
		HoverData  := @FM : 'SCHED_DET Key:' : @VM : ApptID
	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>
	DesktopHeight  = Get_Property('SYSTEM', 'SIZE')<2>
	WindowOffsetX  = Get_Property(@Window, 'SIZE')<1>
	WindowOffsetY  = Get_Property(@Window, 'SIZE')<2>
	
	ApptRect      = Get_Property(CtrlEntId, 'OLE.ApptRect[' : ApptId : ']')
	RectLeft      = ApptRect<1>
	RectTop       = ApptRect<2>
	RectRight     = ApptRect<3>
	RectBottom    = ApptRect<4>
	If BlockOut then
		ItemWidth = 260
	end else
		ItemWidth = 300
	end
	
	PopupWidth  = ItemWidth + 4 + 30
	ItemHeight  = 20
	PopupHeight = NumLines * ItemHeight + 14
	
	MouseX = Field(Point, ',', 1)
	MouseY = Field(Point, ',', 2)
	
	ApptHCenter = RectTop + ((RectBottom - RectTop) / 2)
	ApptVCenter = RectLeft + ((RectRight - RectLeft) / 2)
	
	ItemMargin  = 12
	YItemMargin = 0
	
	Begin Case
		
		Case ( (MouseY + PopupHeight) GT DesktopHeight) 
			// SRP Popup will fit if displayed on the top
			TailPosition  = 'Bottom'
			PopupHeight   = NumLines * ItemHeight + 30
			PopupWidth   -= 13
			PopupX        = MouseX - (PopupWidth / 2)
			PopupY        = MouseY - PopupHeight
			
		Case ( ( (MouseX + PopupWidth) LE DesktopWidth) and ( (MouseY - PopupHeight) GT 0) )
			// SRP Popup will fit if displayed on the right
			TailPosition  = 'Left'
			ItemMargin    = 28
			PopupX        = MouseX + 10
			PopupY        = (MouseY - (PopupHeight / '2.1') )
			PopupWidth   += 18
			
		Case ( (MouseX + PopupWidth) GT DesktopWidth)
			// SRP Popup will fit if displayed on the left
			TailPosition  = 'Right'
			PopupWidth   += 4
			PopupX        = MouseX - PopupWidth
			PopupY        = (MouseY - (PopupHeight / '2.1') )
			
		Case Otherwise$ 
			// SRP Popup will fit if displayed on the bottom
			TailPosition  = 'Top'
			PopupWidth   -= 12
			PopupHeight   = NumLines * ItemHeight + 50
			PopupX        = MouseX - (PopupWidth / 2)
			PopupY        = MouseY 
			YItemMargin   = 20
			
	End Case
	
	ItemList    = ''
	If HoverData NE '' then
		For Each Item in HoverData using @FM setting ItemCnt
			// Add the label.
			Label       = Item<0, 1>
			If BlockOut then
				ItemList   := ItemMargin : @SVM : 5 + (ItemCnt - 1) * ItemHeight + YItemMargin : @SVM : ItemWidth * (2/5) : @SVM : ItemHeight : @VM
			end else
				ItemList   := ItemMargin : @SVM : 5 + (ItemCnt - 1) * ItemHeight + YItemMargin : @SVM : ItemWidth * (9/20) : @SVM : ItemHeight : @VM
			end
			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>
			If BlockOut then
				ItemList   := ItemMargin + (ItemWidth * (2/5)) : @SVM : 5 + (ItemCnt - 1) * ItemHeight + YItemMargin : @SVM : ItemWidth * (3/5) : @SVM : ItemHeight : @VM
			end else
				ItemList   := ItemMargin + (ItemWidth * (9/20)) : @SVM : 5 + (ItemCnt - 1) * ItemHeight + YItemMargin : @SVM : ItemWidth * (11/20) : @SVM : ItemHeight : @VM
			end
			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 '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', 0)
	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(@Window, '@PREV_APPT_ID', '')
	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)
	
return


GetScheduleAppointments:
	
	Ctrl             = @Window : '.OLE_SCHEDULE'
	AppointmentList  = ''
	AppointmentKeys  = ''
	AppointmentFlags = ''
	StartDate        = Date() - 160
	EndDate          = Date() + 160
	AppointmentList  = Schedule_Services('GetScheduleEvents', StartDate, EndDate)
	Set_Property(@Window, '@APPT_LIST', AppointmentList)
	AppointmentArray = SRP_Array('Rotate', AppointmentList, @FM, @VM)
	AppointmentKeys  = AppointmentArray<2>
	Convert @VM to @FM in AppointmentKeys
	AppointmentFlags = AppointmentArray<19>
	Convert @VM to @FM in AppointmentFlags
	
	DateList = Get_Property(@Window, '@DATE_LIST')
	For Date = StartDate to EndDate
		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)
	
return


SetScheduleFlags:
	
	Ctrl    = @Window : '.OLE_SCHEDULE'
	For Each AppointmentKey in AppointmentKeys using @FM setting fPos
		Flags    = AppointmentFlags<fPos>
		If Sum(Flags) GT 0 then
			Convert @SVM to @FM in Flags
			Set_Property(Ctrl, 'OLE.ApptFlags[' : AppointmentKey : ']', Flags)
		end
	Next AppointmentKey
	
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')
				PickPlace     = SRP_JSON(objReactor, 'GETVALUE', 'PickPlace')
				NotRepairable = SRP_JSON(objReactor, 'GETVALUE', 'NotRepairable')
				EpiPro        = (Type EQ 'EpiPro')
				Begin Case
					Case Assignment EQ 'G'
						// GaN
						Background  = 'SkyBlue'
					Case Assignment EQ 'O'
						// Out-of-Service
						Background  = 'Silver'
					Case Not(NotRepairable)
						Background  = 'LightGreen'
					Case NotRepairable
						Background = LTORANGE$
					Case Otherwise$
						Background  = 'Silver'
				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 = ''
	If objScheduleEvent EQ '' then
		SRP_JSON(objScheduleEvent, 'PARSE', ScheduleEvent)
	end
	If objScheduleEvent GT 0 then
		ReactorNo           = SRP_JSON(objScheduleEvent, 'GETVALUE', 'Reactor.ReactorNumber')
		ReactorType         = SRP_JSON(objScheduleEvent, 'GETVALUE', 'Reactor.Type')
		SusceptorSize       = SRP_JSON(objScheduleEvent, 'GETVALUE', 'Reactor.SusceptorSize')
		ScheduleDate        = SRP_JSON(objScheduleEvent, 'GETVALUE', 'ScheduleDate')
		ScheduleDate        = Iconv(ScheduleDate, 'D')
		Sequence            = SRP_JSON(objScheduleEvent, 'GETVALUE', 'Sequence')
		BackColor           = SRP_JSON(objScheduleEvent, 'GETVALUE', 'BackColor')
		ForeColor           = SRP_JSON(objScheduleEvent, 'GETVALUE', 'ForeColor')
		ModifiedDTM         = SRP_JSON(objScheduleEvent, 'GETVALUE', 'ModifiedDTM')
		BlockOut            = Iconv(SRP_JSON(objScheduleEvent, 'GETVALUE', 'BlockOut'), 'BYes,No')
		BlockOutType        = SRP_JSON(objScheduleEvent, 'GETVALUE', 'BlockOutType')
		Description         = SRP_JSON(objScheduleEvent, 'GETVALUE', 'Note')
		objWorkOrder        = SRP_JSON(objScheduleEvent, 'GET', 'WorkOrder')
		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')
		CustNameShort       = SRP_JSON(objWorkOrder, 'GETVALUE', 'Company.NameShort')
		SRP_JSON(objWorkOrder, 'RELEASE')
		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 (ScheduleDate 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'
		FirstSchedDetKeyID  = SRP_JSON(objScheduleEvent, 'GETVALUE', 'FirstSchedDetKeyID')
		FirstReactorNo      = FirstSchedDetKeyID[1, '*']
		FirstScheduleDate   = Oconv(FirstSchedDetKeyID[Col2() + 1, '*'], 'D4/')
		LastSchedDetKeyID   = SRP_JSON(objScheduleEvent, 'GETVALUE', 'LastSchedDetKeyID')
		LastReactorNo       = LastSchedDetKeyID[1, '*']
		LastScheduleDate    = Oconv(LastSchedDetKeyID[Col2() + 1, '*'], 'D4/')
		TotalScheduledDays  = SRP_JSON(objScheduleEvent, 'GETVALUE', 'TotalScheduledDays')
		TotalWafers         = SRP_JSON(objScheduleEvent, 'GETVALUE', 'WorkOrder.TotalWafers')
		WafersRemaining     = SRP_JSON(objScheduleEvent, 'GETVALUE', 'WorkOrder.WafersRemaining')
		PercentComplete     = SRP_JSON(objScheduleEvent, 'GETVALUE', 'WorkOrder.PercentComplete')
		ScheduleEvent       = SRP_JSON(objScheduleEvent, 'STRINGIFY', 'FAST')
		SRP_JSON(objScheduleEvent, 'RELEASE')
	end
	
return


EnableZoomButtons:
	
	Ctrl          = @Window : '.OLE_SCHEDULE'
	IntervalSize  = Get_Property(Ctrl, 'OLE.IntervalSize')
	Set_Property(@Window:'.OLE_PUB_ZOOM_OUT', 'ENABLED', (IntervalSize GT 9))
	Set_Property(@Window:'.LBL_ZOOM_OUT', 'ENABLED', (IntervalSize GT 9))
	Set_Property(@Window:'.OLE_PUB_ZOOM_IN', 'ENABLED', (IntervalSize LT 29))
	Set_Property(@Window:'.LBL_ZOOM_IN', 'ENABLED', (IntervalSize LT 29))
	
return


UpdateAppointmentList:
	
	Ctrl         = @Window : '.OLE_SCHEDULE'
	CurrApptList = Get_Property(Ctrl, 'OLE.AppointmentList')
	CurrApptArray = SRP_Array('Rotate', CurrApptList, @FM, @VM)
	CurrApptKeys  = CurrApptArray<2>
	Convert @VM to @FM in CurrApptKeys
	// Remove all appointments in the schedule control
	Send_Message(Ctrl, 'OLE.RemoveAppts', CurrApptKeys)
	GoSub GetScheduleAppointments    
	// Populate the schedule control with the the new list
	Send_Message(Ctrl, 'OLE.AddAppts', AppointmentList)
	GoSub SetScheduleFlags
	
return


RefreshReactor:
	
	Ctrl           = @Window : '.OLE_SCHEDULE'
	Caption        = 'Please wait...updating the schedule'
	GoSub ShowWaitMessage
	Set_Property(Ctrl, "OLE.Redraw", False$)
	If RemAppts NE '' then Send_Message(Ctrl, 'RemoveAppts', RemAppts)
	Schedule_Services('AdjustScheduleEvents', ReactorNo)
	ReactEventKeys = Xlate('REACTOR', ReactorNo, 'SCHED_EVENTS', 'X')
	Swap @VM with @FM in ReactEventKeys
	AddAppts       = ''
	For each EventKey in ReactEventKeys using @FM setting fPos
		AddAppts<fPos> = Schedule_Services('GetScheduleEvent', EventKey)
	Next EventKey
	If AddAppts NE '' then Send_Message(Ctrl, 'AddAppts', AddAppts)
	Set_Property(Ctrl, "OLE.Redraw", True$)
	GoSub HideWaitMessage
	
return


RefreshSchedule:
	
	// The ShowWaitMessage gosub hides the schedule control and displays the picture control with the indicated caption.
	PopupCtrl    = @Window : '.OLE_POPUP'
	PopupVisible = Get_Property(PopupCtrl, 'OLE.Visible')
	If PopupVisible EQ True$ then GoSub DismissPopup
	Caption      = 'Please wait...refreshing schedule'
	GoSub ShowWaitMessage
	GoSub UpdateAppointmentList
	GoSub HideWaitMessage
	
Return



