Function NDW_Scheduler_Add_WO_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_Add_WO_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/12/17    dmb     Created initial commuter module.
        01/08/21    djs     Began work on version 2.0.

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

#pragma precomp SRP_PreCompiler
#Window NDW_SCHEDULER_ADD_WO

$insert APP_INSERTS
$insert EVENT_SETUP
$insert MSG_EQUATES
$insert SCHED_DET_NG_EQUATES
$insert WO_LOG_EQUATES
$insert WO_SCHEDULE_NG_EQUATES
$insert REACTOR_EQUATES

Equ OI_DISABLED_GREY$ TO 239 + (239*256) + (239*65536)

Declare function    SRP_Array, Schedule_Services, Database_Services, Work_Order_Services, SRP_Math
Declare function    Epi_Part_Services, Datetime
Declare subroutine  obj_Appwindow, Center_Window, Schedule_Services, Form_Services, SRP_Show_Window
Declare subroutine  Form_Services, ErrMsg

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

Type = Get_Property(CtrlEntId, 'TYPE')
If Type EQ 'RADIOBUTTON' then
	Convert ' ' to '_' in CtrlEntID
end

GoToEvent Event for CtrlEntID

Return EventFlow else EVENT_CONTINUE$


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

Event WINDOW.CREATE(CreateParam)
	
	ReactorNo        = CreateParam<1>
	SchedStartDTM    = CreateParam<2>
	Set_Property(@Window, '@SCHED_START_DTM', SchedStartDTM)
	NextStartDTM     = ''
	ReactSchedEvents = Xlate('REACTOR', ReactorNo, 'SCHED_EVENTS', 'X')
	If ReactSchedEvents NE '' then
		LastEventKey    = ReactSchedEvents[-1, 'B':@VM]
		LastSchedDetRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', LastEventKey)
		If LastSchedDetRec<SCHED_DET_NG.STOP_DTM$> GT SchedStartDTM then
			// The datetime passed in by the user (via where they right-clicked on the schedule)
			// is before the next available time slot.
			NextStartDTM = LastSchedDetRec<SCHED_DET_NG.STOP_DTM$>
		end
	end
	
	If NextStartDTM NE '' then
		StartDTM  = NextStartDTM
	end else
		StartDTM  = SchedStartDTM
	end
	Set_Property(@Window, '@NEXT_START_DTM', StartDTM)
	Set_Property(@Window : '.REACTOR_NO', 'TEXT', ReactorNo)
	Set_Property(@Window : '.SCHEDULE_START_DTM', 'INVALUE', StartDTM)
	
	GoSub Setup_OLE_Controls
	GoSub PopulateControls
	Set_Property(@Window : '.CLOSE_BUTTON', 'NEXT', @Window : '.REACTOR_NO')
	
	SRP_Show_Window(@Window, '', 'C', 'C', 1, '', False$, False$)
	
end event


Event WINDOW.CLOSE(CancelFlag)
	
end event


Event SCHEDULE_OPTIONS_DATETIME.NEXT_AVAILABLE.CLICK()
	
	StartDTM = Get_Property(@Window, '@NEXT_START_DTM')
	Set_Property(@Window:'.SCHEDULE_START_DTM', 'INVALUE', StartDTM)
	Set_Property(@Window:'.SCHEDULE_START_DTM', 'ENABLED', False$)
	Set_Property(@Window:'.SCHEDULE_START_DTM', 'BACKCOLOR', OI_DISABLED_GREY$)
	GoSub UpdateWorkOrderDetails
	
end event


Event SCHEDULE_OPTIONS_DATETIME.SPECIFIC_DATE_AND_TIME.CLICK()
	
	StartDTM = Get_Property(@Window, '@SCHED_START_DTM')
	Set_Property(@Window:'.SCHEDULE_START_DTM', 'INVALUE', StartDTM)
	Set_Property(@Window:'.SCHEDULE_START_DTM', 'ENABLED', True$)
	Set_Property(@Window:'.SCHEDULE_START_DTM', 'BACKCOLOR', WHITE$)
	GoSub UpdateWorkOrderDetails
	
end event


Event SCHEDULE_END_DTM.LOSTFOCUS(Flag, FocusID)
	
	StartDTM = Get_Property(@Window : '.SCHEDULE_START_DTM', 'INVALUE')
	EndDTM   = Get_Property(CtrlEntId, 'INVALUE')
	If StartDTM NE '' AND EndDTM NE '' then
		Days    = EndDTM - StartDTM + 1
		Set_Property(@Window : '.DAYS', 'DEFPROP', Days)
	end
	
end event


Event SCHEDULE_START_DTM.LOSTFOCUS(Flag, FocusID)
	
	WorkOrder   = Get_Property(@Window : '.WO_NO', 'TEXT')
	If WorkOrder NE '' then
		GoSub UpdateWorkOrderDetails
	end else
		Set_Property(@Window : '.SCHEDULE_END_DTM', 'INVALUE', '')
	end
	
end event


Event WO_NO.LOSTFOCUS(Flag, FocusID)
	
	WONo     = Get_Property(CtrlEntID, 'TEXT')
	OrigWONo = Get_Property(@Window, '@WO_NO')
	If WONo NE OrigWONo then 
		Set_Property(@Window, '@WO_NO', WONo)
		// User changed the value in this control. Update related controls.
		GoSub UpdateCustomerName
		GoSub InitializeProperties
		GoSub UpdateWorkOrderDetails
	end
	
end event


Event SAVE_BUTTON.CLICK()
	
	ResponseData = '' 
	ReactorNo    = Get_Property(@Window : '.REACTOR_NO', 'TEXT')
	WorkOrder    = Get_Property(@Window : '.WO_NO', 'TEXT')
	StartDTM     = Get_Property(@Window : '.SCHEDULE_START_DTM', 'INVALUE')
	EndDTM       = Get_Property(@Window : '.SCHEDULE_END_DTM', 'INVALUE')
	Description  = Get_Property(@Window : '.DESCRIPTION', 'INVALUE')
	EventQty     = Get_Property(@Window : '.SCHEDULE_WAFERS', 'TEXT')
	ResponseData = ReactorNo : @FM : WorkOrder : @FM : StartDTM : @FM : EndDTM : @FM : Description : @FM : EventQty
	End_Dialog(@Window, ResponseData)
	
end event


Event CLOSE_BUTTON.CLICK()
	
	Post_Event(@Window, 'CLOSE')
	
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 SCHEDULE_WAFERS.CHANGED(NewData)
	
	SchedQty = NewData
	AvailQty = Get_Property(@Window : '.AVAILABLE_QTY', 'TEXT')
	If SchedQty NE '' then
		If (SchedQty GT AvailQty) then
			Set_Property(CtrlEntID, 'FOCUS', True$)
			Set_Property(CtrlEntID, 'SELECTION', 1 : @FM : 999)
			Message = 'Schedule quantity must be less than or equal to the available quantity.'
			Form_Services('DisplayControlMessage', Message, 'Invalid Quantity', CtrlEntID, 'VALIDATION', 'RGB(229,20,0)')
		end else
			GoSub UpdateWorkOrderDetails
		end
	end
	GoSub EnableSaveButton
	
end event


Event SCHEDULE_WAFERS.CHAR(VirtCode, ScanCode, CtrlKey, ShiftKey, AltKey)
	
	Form_Services('CloseControlMessage', CtrlEntId)
	
end event


Event SCHEDULE_WAFERS.LOSTFOCUS(Flag, FocusID)
	
	SchedQty = Get_Property(CtrlEntID, 'TEXT')
	AvailQty = Get_Property(@Window : '.AVAILABLE_QTY', 'TEXT')
	If SchedQty GT AvailQty then
		Set_Property(CtrlEntID, 'FOCUS', True$)
		Set_Property(CtrlEntID, 'SELECTION', 1 : @FM : 999)
		Message = 'Schedule quantity must be less than or equal to the available quantity.'
		Form_Services('DisplayControlMessage', Message, 'Invalid Quantity', CtrlEntID, 'VALIDATION', 'RGB(229,20,0)')
	end else
		GoSub UpdateWorkOrderDetails
	end
	GoSub EnableSaveButton
	
end event


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

Setup_OLE_Controls:
	
	Ctrl        = @Window : '.OLE_SUBCLASS'
	// Get the current reactor type and size so the GetReactor and GetUnscheduledWorkOrders service results can be filtered
	// down to only those items that match the same type and size.
	ReactorNo       = Get_Property(@Window : '.REACTOR_NO', 'TEXT')
	ReactorRec      = Database_Services('ReadDataRow', 'REACTOR', ReactorNo)
	ReactorType     = ReactorRec<REACTOR_REACT_TYPE$>
	SusceptorSize   = ReactorRec<REACTOR_SUSC_POCKET_SIZE$>
	
	EditLine    = @Window : '.WO_NO'
	Handle      = Get_Property(EditLine, 'HANDLE')
	Send_Message(Ctrl, 'OLE.Subclass', Handle, EditLine)
	Combo       = ''
	Combo<1>    = 1
	Combo<2, 1> = 'Work Order' : @TM : 'Epi Part' : @TM : 'Customer' : @TM : 'Reactor Type' : @TM : 'PSN Block'
	Combo<2, 2> = 'L' : @STM : 'DYN' : @TM : 'L' : @STM : 'DYN' : @TM : 'L' : @STM : 'DYN' : @TM : 'L' : @STM : 'DYN' : @TM : 'C' : @STM : 'DYN'
	Combo<2, 3> = ''
	Combo<2, 4> = 1
	Combo<2, 5> = 1
	Combo<2, 6> = 0
	Combo<2, 7> = 40
	Combo<2, 9> = 1
	Combo<2,10> = 0
	Combo<2,11> = 0
	Combo<2,12> = 1
	Combo<2,24> = 0
	EditLine    = @Window : ';WO_NO'
	Set_Property(@Window : '.OLE_SUBCLASS', 'OLE.Combo[' : EditLine : ']', Combo)
	Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnOptionClick', 1)
	Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnComboClick', 1)
	
return


SelectAll:
	
	Set_Property(CtrlEntId, 'SELECTION', 1 : @FM : 999)
	
return


UpdateScheduleDetails:
	
	ScheduleDetail  = Schedule_Services('GetScheduleDetail', ScheduleKeyID)
	Set_Property(@Window, '@ORIG_SCHEDULEDETAIL', ScheduleDetail)
	WorkOrder           = Get_Property(@Window : '.WO_NO', 'TEXT')
	If WorkOrder NE '' then
		Set_Property(@Window : '.DESCRIPTION', 'TEXT', ScheduleDetail<SCHED_DET_NG.DESC$>)
	end else
		Set_Property(@Window : '.DESCRIPTION', 'TEXT', '')
	end
	
return

UpdateCustomerName:
	
	WoNo            = Get_Property(@Window : '.WO_NO', 'TEXT')
	If WoNo NE '' then
		WorkOrderDetail = Work_Order_Services('GetWorkOrderLogDetail', WONo)
		CustNo          = WorkOrderDetail<WO_LOG_CUST_NO$>
		CompanyRow      = Database_Services('ReadDataRow', 'COMPANY', CustNo)
		CustName        = CompanyRow<42>
	end else
		CustName        = ''
	end
	Set_Property(@Window : '.CUSTOMER_NAME', 'TEXT', CustName)
	
return


UpdateReactorDetails:
	
	ReactorNo       = Get_Property(@Window : '.REACTOR_NO', 'TEXT')
	If Index(ReactorNo, '/', 1) then
		// EpiPro reactors formatted as such, "40/42". We must truncate the reactor number to the first reactor.
		ReactorNo = Field(ReactorNo, '/', 1, 1)
		Set_Property(@Window : '.REACTOR_NO', 'TEXT', ReactorNo)
	end
	ReactorDetails  = Schedule_Services('GetReactorDetails', ReactorNo)
	ReactorType     = ReactorDetails<REACTOR_REACT_TYPE$>
	Begin Case
		Case ReactorType _EQC 'EPP' ; ReactorType = 'EpiPro'
		Case ReactorType _EQC 'GAN' ; ReactorType = 'GaN'
	End Case
	Set_Property(@Window : '.REACTOR_TYPE', 'TEXT', ReactorType)
	Set_Property(@Window : '.REACTOR_SIZE', 'TEXT', ReactorDetails<REACTOR_SUSC_POCKET_SIZE$>)
	FutureEvents    = Schedule_Services('GetScheduleEvents', Date() + 1, '', ReactorNo, '', False$)
	Set_Property(@Window, '@FUTURE_EVENTS', FutureEvents)
	
return


InitializeProperties:
	
	WorkOrder               = Get_Property(@Window : '.WO_NO', 'TEXT')
	ReactNo                 = Get_Property(@Window : '.REACTOR_NO', 'TEXT')
	ReactorType             = Get_Property(@Window : '.REACTOR_TYPE', 'TEXT')
	WorkOrderDetail         = Work_Order_Services('GetWorkOrderLogDetail', WorkOrder)
	RemainingToProcess      = Work_Order_Services('GetRemainingWafers', WorkOrder)
	RemainingToSchedule     = Schedule_Services('GetUnscheduledWfrQty', WorkOrder)
	EpiPart                 = WorkOrderDetail<WO_LOG_EPI_PART_NO$>
	MinutesPerWaferAdjusted = Epi_Part_Services('GetAdjustedWafersPerDayScheduler', EpiPart, ReactorType)
	ScheduledWfrQty         = Schedule_Services('GetScheduledWfrQty', WorkOrder)
	WOSchedCass             = Schedule_Services('GetScheduledCassettes', WorkOrder)
	Set_Property(@Window, '@WORK_ORDER_DETAIL', WorkOrderDetail)
	Set_Property(@Window, '@REMAINING_TO_PROCESS', RemainingToProcess)
	Set_Property(@Window, '@REMAINING_TO_SCHEDULE', RemainingToSchedule)
	Set_Property(@Window, '@MINUTES_PER_WAFER_ADJUSTED', MinutesPerWaferAdjusted)
	Set_Property(@Window, '@SCHEDULED_WFR_QTY', ScheduledWfrQty)
	Set_Property(@Window, '@WO_SCHED_CASS', WOSchedCass)
	
return


UpdateWorkOrderDetails:
	
	MinutesPerWaferAdjusted = ''
	WorkOrder               = Get_Property(@Window : '.WO_NO', 'TEXT')
	ReactNo                 = Get_Property(@Window : '.REACTOR_NO', 'TEXT')
	CurrDTM                 = Datetime()
	If WorkOrder NE '' then
		PSNBlocked      = False$
		WorkOrdersArray = Get_Property(@Window, '@UNSCHEDULED_WORK_ORDERS')
		Convert @TM to @FM in WorkOrdersArray
		Convert @STM to @VM in WorkOrdersArray
		WorkOrderList   = WorkOrdersArray<1>
		PSNBlockedList  = WorkOrdersArray<5>
		Locate WorkOrder in WorkOrderList using @VM setting vPos then PSNBlocked = PSNBlockedList<0, vPos>
		If PSNBlocked EQ '' then
			Set_Property(@Window:'.LBL_PSN_BLOCK', 'VISIBLE', False$)
			WorkOrderDetail     = Get_Property(@Window, '@WORK_ORDER_DETAIL')
			EpiPart             = WorkOrderDetail<WO_LOG_EPI_PART_NO$>
			TotalWafers         = WorkOrderDetail<WO_LOG_WO_QTY$>
			RemainingToProcess  = Get_Property(@Window, '@REMAINING_TO_PROCESS')
			RemainingToSchedule = Get_Property(@Window, '@REMAINING_TO_SCHEDULE')
			If TotalWafers GT 0 then
				Complete = ( (TotalWafers - RemainingToProcess) / TotalWafers) * 100
			end else
				Complete = 0
			end
			ReactorType             = Get_Property(@Window : '.REACTOR_TYPE', 'TEXT')
			MinutesPerWaferAdjusted = Get_Property(@Window, '@MINUTES_PER_WAFER_ADJUSTED')
			ScheduledWfrQty         = Get_Property(@Window, '@SCHEDULED_WFR_QTY')
			AvailableWfrQty         = RemainingToSchedule
			EventWafers             = Get_Property(@Window:'.SCHEDULE_WAFERS', 'TEXT')
			If ( (EventWafers EQ '') and (MinutesPerWaferAdjusted NE '') ) then
				EventWafers = AvailableWfrQty
				Set_Property(@Window : '.SCHEDULE_WAFERS', 'TEXT', AvailableWfrQty)
			end
			
			UnprocessedCassettes = ''
			ProcessedCassettes   = '' 
			// Look at the next slot to be scheduled!
			// Get the number of wafers scheduled up to this event.
			// This should give us the correct starting wafer slot.
			StartCassNo          = SRP_Math('CEILING', ( (ScheduledWfrQty + 1) / 25))
			If StartCassNo EQ 0 then StartCassNo = 1
			EventNumCass         = SRP_Math('CEILING', (EventWafers / 25))
			FirstRDS             = ''
			EventEngaged         = False$
			
			If ReactorType _EQC 'EpiPro' then
				// Example: Event starts on WM_IN cassette 6 (i.e. 172125*1*6), slot 13.
				StartSlotNo = Mod(ScheduledWfrQty, 25) + 1
				StopCassNo  = StartCassNo + EventNumCass - 1
				StopSlotNo  = Mod((ScheduledWfrQty + EventWafers), 25)
				If StopSlotNo EQ 0 then StopSlotNo = 25
				
				For CassIndex = 1 to EventNumCass
					CassNo           = (StartCassNo + CassIndex - 1)
					WMIKey           = WorkOrder:'*1*':CassNo
					WMIRdsKeys       = Xlate('WM_IN', WMIKey, 'RDS_NO', 'X')
					EventCassRDSKeys = ''
					Begin Case
						Case CassNo EQ StartCassNo
							StartIndex = StartSlotNo
							StopIndex  = 25
						Case CassNo EQ StopCassNo
							StartIndex = 1
							StopIndex  = StopSlotNo
						Case ( (CassNo EQ StartCassNo) and (CassNo EQ StopCassNo) )
							StartIndex = StartSlotNo
							StopIndex  = StopSlotNo
						Case Otherwise$
							StartIndex = 1
							StopIndex  = 25
					End Case
					For SlotIndex = StartIndex to StopIndex
						If FirstRDS EQ '' then
							FirstRDS     = WMIRdsKeys<0, SlotIndex>
							FirstLoad    = Xlate('RDS', FirstRDS, 'DATE_IN', 'X')
							EventEngaged = (FirstLoad NE '')
						end
						EventCassRDSKeys<0, -1> = WMIRdsKeys<0, SlotIndex>
					Next SlotIndex
					EventCassRDSKeys = SRP_Array('Clean', EventCassRDSKeys, 'TrimAndMakeUnique', @VM)
					// Now we have a list of RDS keys that only pertain to this event.
					If EventCassRDSKeys NE '' then
						// Are all of the RDS runs unloaded?
						NumUnloadedRDS = 0
						UnloadDtms     = Xlate('RDS', EventCassRDSKeys, 'DATETIME_OUT', 'X')
						If UnloadDtms NE '' then
							For each UnloadDtm in UnloadDtms using @VM
								If UnloadDtm NE '' then NumUnloadedRds += 1
							Next UnloadDtm
						end
						NumRDS        = DCount(EventCassRDSKeys, @VM)
						CassProcessed = (NumRds EQ NumUnloadedRds)
					end else
						CassProcessed = False$
					end
					If CassProcessed then
						ProcessedCassettes<0, -1> = CassNo
					end else
						UnprocessedCassettes<0, -1> = CassNo
					end
				Next CassIndex
				ProcessedCassettes = SRP_Array('Join', ProcessedCassettes, UnprocessedCassettes, 'NOT', @VM)
				// Estimate event unprocessed wafer quantity for duration estimate
				NumUnprocCass      = DCount(UnprocessedCassettes, @VM)
				UnprocessedWfrQty  = ( (NumUnprocCass - 1) * 25 ) + StopSlotNo
			end else
				// Example: Event starts on WO_MAT cassette 7. We don't need to schedule down to the
				//          wafer levels with non-epipro work order events.
				For CassIndex = 1 to EventNumCass
					CassNo        = (StartCassNo + CassIndex)
					WOMatKey      = WorkOrder:'*':CassNo
					RDSNo         = Xlate('WO_MAT', WOMatKey, 'RDS_NO', 'X')
					If FirstRDS EQ '' then
						FirstRDS = RDSNo
						FirstLoad    = Xlate('RDS', FirstRDS, 'DATE_IN', 'X')
						EventEngaged = (FirstLoad NE '')
					end
					UnloadDtm     = Xlate('RDS', RDSNo, 'DATETIME_OUT', 'X')
					CassProcessed = (UnloadDtm NE '')
					If CassProcessed then
						ProcessedCassettes<0, -1> = CassNo
					end else
						UnprocessedCassettes<0, -1> = CassNo
					end
				Next CassIndex
				NumUnprocCass     = DCount(UnprocessedCassettes, @VM)
				UnprocessedWfrQty = NumUnprocCass * 25
			end
			
			// Need to check if user is scheduling part of the work order on another reactor.
			PrevSchedEvents = Schedule_Services('GetScheduledEvents', WorkOrder)
			
			If EventEngaged and (PrevSchedEvents EQ '') then
				// Event already engaged
				// Set start DTM to first load dtm unless the work order is switching reactors or split
				Set_Property(@Window:'.OPTIONS_GRP_START_DTM', 'ENABLED', False$)
				StartDtm         = Xlate('RDS', FirstRDS, 'DATETIME_IN', 'X')
				If StartDtm EQ '' then StartDtm = Get_Property(@Window, '@NEXT_START_DTM')
				DurationEstimate = Schedule_Services('GetEventDuration', WorkOrder, UnprocessedWfrQty)
				EndDTM           = StartDtm + DurationEstimate
			end else
				// Event not engaged yet. Use previous event's end DTM unless it is in the past.
				// In that event use the current DTM.
				Set_Property(@Window:'.OPTIONS_GRP_START_DTM', 'ENABLED', True$)
				NextStartDTM     = Get_Property(@Window, '@NEXT_START_DTM')
				CurrDTM          = Datetime()
				If NextStartDTM GT CurrDTM then
					StartDTM = NextStartDTM
				end else
					StartDTM = CurrDTM
				end
				// Calculate End DTM based on the start DTM in the form and duration estimate
				DurationEstimate = Schedule_Services('GetEventDuration', WorkOrder, EventWafers)
				Set_Property(@Window:'.SCHEDULE_START_DTM', 'INVALUE', StartDTM)
				EndDTM           = StartDTM + DurationEstimate
			end
			
			If MinutesPerWaferAdjusted EQ '' then
				Msg(@Window, 'Warning: ' : EpiPart : ' appears to be missing minutes per wafer values for ' : ReactorType)
				Set_Property(@Window:'.CLOSE_BUTTON', 'FOCUS', True$)
			end
		end else
			// PSN Blocked
			Set_Property(@Window:'.LBL_PSN_BLOCK', 'VISIBLE', True$)
		end
	end
	
	If ( (WorkOrder NE '') and (MinutesPerWaferAdjusted NE '') ) then
		Set_Property(@Window : '.EPI_PART', 'TEXT', EpiPart)
		Set_Property(@Window : '.TOTAL_WAFERS', 'TEXT', TotalWafers)
		Set_Property(@Window : '.TOTAL_REMAINING', 'TEXT', RemainingToProcess)
		Set_Property(@Window : '.PERCENT_COMPLETE', 'TEXT', Oconv(Complete, 'MD0[ %]S'))
		Set_Property(@Window : '.SCHEDULE_START_DTM', 'INVALUE', StartDTM)
		Set_Property(@Window : '.SCHEDULE_END_DTM', 'INVALUE', EndDTM)
		DurationDaysRounded = SRP_Math('ROUND', DurationEstimate, 1)
		Set_Property(@Window : '.DAYS', 'DEFPROP', DurationDaysRounded)
		Set_Property(@Window : '.AVAILABLE_QTY', 'TEXT', AvailableWfrQty)
	end else
		Error_Services('DisplayError')
		Set_Property(@Window : '.EPI_PART', 'TEXT', '')
		Set_Property(@Window : '.TOTAL_WAFERS', 'TEXT', '')
		Set_Property(@Window : '.TOTAL_REMAINING', 'TEXT', '')
		Set_Property(@Window : '.SCHEDULE_WAFERS', 'TEXT', '')
		Set_Property(@Window : '.PERCENT_COMPLETE', 'TEXT', '')
		Set_Property(@Window : '.SCHEDULE_END_DTM', 'INVALUE', '')
		Set_Property(@Window : '.DAYS', 'DEFPROP', '')
	end
	
	GoSub EnableSaveButton
	
return


UpdateWorkOrderList:
	
	WorkOrders  = ''
	// Adding work order.
	WorkOrders  = Get_Property(@Window, '@UNSCHEDULED_WORK_ORDERS')
	If WorkOrders EQ '' then
		// Get the current reactor type and size so the GetReactor and GetUnscheduledWorkOrders service results 
		// can be filtered down to only those items that match the same type and size.
		ReactorNo     = Get_Property(@Window : '.REACTOR_NO', 'TEXT')
		ReactorRec    = Database_Services('ReadDataRow', 'REACTOR', ReactorNo)
		ReactorType   = ReactorRec<REACTOR_REACT_TYPE$>
		SusceptorSize = ReactorRec<REACTOR_SUSC_POCKET_SIZE$>
		WorkOrders    = Schedule_Services('GetAvailableWorkOrders', ReactorType, '', ReactorNo)
		WorkOrders    = SRP_Array('Rotate', WorkOrders)
		Convert @FM to @TM in WorkOrders
		Convert @VM to @STM in WorkOrders
		Set_Property(@Window, '@UNSCHEDULED_WORK_ORDERS', WorkOrders)
	end
	EditLine    = @Window : ';WO_NO'
	Set_Property(@Window : '.OLE_SUBCLASS', 'OLE.ComboData[' : EditLine : ']', WorkOrders)
	
return


PopulateControls:
	
	Set_Property(@Window, 'TEXT', 'Scheduler Actions - Add Work Order Event')
	Set_Property(@Window : '.REACTOR_NO', 'NEXT', @Window : '.SCHEDULE_START_DTM')
	Set_Property(@Window : '.DESCRIPTION', 'NEXT', @Window : '.REACTOR_NO')
	WorkOrders     = Get_Property(@Window, '@UNSCHEDULED_WORK_ORDERS')
	WONo           = ''
	ScheduleKeyID  = ''
	GoSub UpdateWorkOrderList
	GoSub UpdateScheduleDetails
	GoSub UpdateReactorDetails
	GoSub UpdateCustomerName
	GoSub EnableSaveButton
	Set_Property(@Window : '.REACTOR_NO', 'FOCUS', True$)
	
return


EnableSaveButton:
	
	PSNBlocked    = Get_Property(@Window:'.LBL_PSN_BLOCK', 'VISIBLE')
	SchedQty      = Get_Property(@Window : '.SCHEDULE_WAFERS', 'TEXT')
	AvailQty      = Get_Property(@Window : '.AVAILABLE_QTY', 'TEXT')
	ButtonEnabled = ( (SchedQty NE '') and (SchedQty NE 0) and (AvailQty NE 0) and (SchedQty LE AvailQty) and (PSNBlocked EQ False$) )
	Set_Property(@Window : '.SAVE_BUTTON', 'ENABLED', ButtonEnabled)
	
return


