implementation module timerdevice


import	StdInt, StdBool, StdFunc, StdEnum, StdList, StdTuple
from StdPSt import accPIO, appPIO
import	commondef, devicefunctions, iostate, receiveraccess, timeraccess, timerdefaccess, timerevent


timerdeviceFatalError :: String String -> .x
timerdeviceFatalError function error
	= fatalError function "timerdevice" error

timerFunctions :: DeviceFunctions (PSt .l)
timerFunctions
	= {	dDevice	= TimerDevice
	  ,	dShow	= id
	  ,	dHide	= id
	  ,	dEvent	= timerEvent
	  ,	dDoIO	= timerIO
	  ,	dOpen	= timerOpen
	  ,	dClose	= timerClose
	  }

timerOpen :: !(PSt .l) -> PSt .l
timerOpen pState=:{io=ioState}
	# (hasTimer,ioState)	= ioStHasDevice TimerDevice ioState
	| hasTimer
		= {pState & io=ioState}
	| otherwise
		# ioState			= ioStSetDevice (TimerSystemState {tTimers=[]}) ioState
		# ioState			= ioStSetDeviceFunctions timerFunctions ioState
		= {pState & io=ioState}

timerClose :: !(PSt .l) -> PSt .l
timerClose pState=:{io=ioState}
	# (found,timers,ioState)= ioStGetDevice TimerDevice ioState
	| not found
		= {pState & io=ioState}
	| otherwise
		# (rt,ioState)		= ioStGetReceiverTable ioState
		# (tt,ioState)		= ioStGetTimerTable ioState
		# (idtable,ioState)	= ioStGetIdTable ioState
		# (pid,ioState)		= ioStGetIOId ioState
		  tHs				= timerSystemStateGetTimerHandles timers
		  (tt,rt,idtable)	= stateMap2 (closeTimerIds pid) tHs.tTimers (tt,rt,idtable)
		# ioState			= ioStSetReceiverTable rt ioState
		# ioState			= ioStSetTimerTable tt ioState
		# ioState			= ioStSetIdTable idtable ioState
		# ioState			= ioStRemoveDeviceFunctions TimerDevice ioState
		= {pState & io=ioState}
where
	closeTimerIds :: !SystemId !(TimerStateHandle .pst) !*(!*TimerTable,!*ReceiverTable,!*IdTable) -> *(!*TimerTable,!*ReceiverTable,!*IdTable)
	closeTimerIds pid (TimerLSHandle {tHandle={tId,tItems}}) tables
		# (tt,rt,it)	= unbindTimerElementIds pid tItems tables
		= (snd (removeTimerFromTimerTable teLoc tt),rt,snd (removeIdFromIdTable tId it))
	where
		teLoc			= {tlIOId=pid,tlDevice=TimerDevice,tlParentId=tId,tlTimerId=tId}

timerIO	:: !DeviceEvent !(PSt .l) -> (!DeviceEvent,!PSt .l)
timerIO deviceEvent pState
	# (hasDevice,pState)= accPIO (ioStHasDevice TimerDevice) pState
	| not hasDevice
		= timerdeviceFatalError "timerFunctions.dDoIO" "could not retrieve TimerSystemState from IOSt"
	| otherwise
		= timerIO deviceEvent pState
where
	timerIO	:: !DeviceEvent !(PSt .l) -> (!DeviceEvent,!PSt .l)
	timerIO deviceEvent=:(TimerEvent te=:{teLoc={tlParentId,tlTimerId},teNrInterval}) pState=:{io}
		# (_,timer,ioState)	= ioStGetDevice TimerDevice io
		  timers			= timerSystemStateGetTimerHandles timer
		  pState			= {pState & io=ioState}
		# pState			= letOneTimerDoIO tlParentId tlTimerId teNrInterval timers pState
		= (deviceEvent,pState)
	where
		letOneTimerDoIO :: !Id !Id !NrOfIntervals !(TimerHandles (PSt .l)) !(PSt .l) -> PSt .l
		letOneTimerDoIO parent timer nrOfIntervals timers=:{tTimers=tHs} pState
			= pState2
		where
			(_,tH,tHs1)		= uremove (identifyTimerStateHandle parent) (timerdeviceFatalError "timerIO (TimerEvent _)" "timer could not be found") tHs
			pState1			= appPIO (ioStSetDevice timers1) pState
			(tH1,pState2)	= letTimerDoIO nrOfIntervals tH pState1
			timers1			= TimerSystemState {timers & tTimers=tHs1++[tH1]}
			
/*			Compiling with 'Reuse Unique Nodes' causes a space-leak in this function definition.
			Therefore it is replaced temporarily with the function below.
			letTimerDoIO :: !NrOfIntervals !(TimerStateHandle .ps) !.ps -> (!TimerStateHandle .ps, .ps)
			letTimerDoIO nrOfIntervals (TimerLSHandle tsH=:{tState=ls,tHandle=tH=:{tFun}}) pState
				= (TimerLSHandle {tsH & tState=ls1},pState1)
			where
				(ls1,pState1)	= tFun nrOfIntervals (ls,pState)
*/			
			letTimerDoIO :: !NrOfIntervals !(TimerStateHandle .ps) !.ps -> (!TimerStateHandle .ps, .ps)
			letTimerDoIO nrOfIntervals (TimerLSHandle tsH=:{tState=ls,tHandle=tH=:{tFun}}) pState
				= (TimerLSHandle {tsH & tState=ls1},pState1)
			where
				(ls1,pState1)	= apply tFun nrOfIntervals ls pState
				
				apply :: !(TimerFunction *(.ls,.pst)) !NrOfIntervals .ls !.pst -> (.ls,!.pst)
				apply f d_i ls pst = f d_i (ls,pst)
	
	timerIO deviceEvent=:(ReceiverEvent (QASyncMessage event)) pState
		= (deviceEvent,timerQASync event pState)
	where
		timerQASync :: !QASyncMessage !(PSt .l) -> PSt .l
		timerQASync msg=:{qasmRecLoc={rlReceiverId=rid}} pState
			# (_,timer,ioState)	= ioStGetDevice TimerDevice pState.io
			  timers			= timerSystemStateGetTimerHandles timer
			  tsHs				= handleASyncReceiver rid msg timers.tTimers
			  timers			= {timers & tTimers=tsHs}
			# ioState			= ioStSetDevice (TimerSystemState timers) ioState
			# pState			= {pState & io=ioState}
			= pState
		where
			handleASyncReceiver :: !Id !QASyncMessage ![TimerStateHandle .pst] -> [TimerStateHandle .pst]
			handleASyncReceiver rid msg [TimerLSHandle tlsH=:{tHandle=tH=:{tItems}}:tsHs]
				# (done,tItems)	= qMessage rid msg tItems
				  tsH			= TimerLSHandle {tlsH & tHandle={tH & tItems=tItems}}
				| done			= [tsH:tsHs]
				| otherwise		= [tsH:handleASyncReceiver rid msg tsHs]
			where
				qMessage :: !Id !QASyncMessage ![TimerElementHandle .ls .pst] -> (!Bool,![TimerElementHandle .ls .pst])
				qMessage rid msg [itemH:itemHs]
					# (done,itemH)	= qMessage` rid msg itemH
					| done
						= (done,[itemH:itemHs])
					| otherwise
						# (done,itemHs)	= qMessage rid msg itemHs
						= (done,[itemH:itemHs])
				where
					qMessage` :: !Id !QASyncMessage !(TimerElementHandle .ls .pst) -> (!Bool,!TimerElementHandle .ls .pst)
					qMessage` rid {qasmMsg} (TimerReceiverHandle trH=:{tReceiverHandle=rH})
						| receiverIdentified rid rH	= (True, TimerReceiverHandle {trH & tReceiverHandle=receiverAddASyncMessage rid qasmMsg rH})
						| otherwise					= (False,TimerReceiverHandle trH)
					qMessage` rid msg (TimerListLSHandle itemHs)
						# (done,itemHs) = qMessage rid msg itemHs
						= (done,TimerListLSHandle itemHs)
					qMessage` rid msg (TimerElimLSHandle itemHs)
						# (done,itemHs) = qMessage rid msg itemHs
						= (done,TimerElimLSHandle itemHs)
					qMessage` rid msg (TimerIntroLSHandle tInH=:{tIntroItems})
						# (done,itemHs) = qMessage rid msg tIntroItems
						= (done,TimerIntroLSHandle {tInH & tIntroItems=itemHs})
					qMessage` rid msg (TimerExtendLSHandle tExH=:{tExtendItems})
						# (done,itemHs) = qMessage rid msg tExtendItems
						= (done,TimerExtendLSHandle {tExH & tExtendItems=itemHs})
					qMessage` rid msg (TimerChangeLSHandle tChH=:{tChangeItems})
						# (done,itemHs) = qMessage rid msg tChangeItems
						= (done,TimerChangeLSHandle {tChH & tChangeItems=itemHs})
				qMessage _ _ _
					= (False,[])
			handleASyncReceiver _ _ _
				= []
	timerIO deviceEvent=:(ReceiverEvent (ASyncMessage event)) pState
		= (deviceEvent,timerASync event pState)
	where
		timerASync :: !ASyncMessage !(PSt .l) -> PSt .l
		timerASync {asmRecLoc={rlReceiverId=rid}} pState
			= pState2
		where
			(_,timers,ioState)	= ioStGetDevice TimerDevice pState.io
			tHs					= timerSystemStateGetTimerHandles timers
			(tsHs,pState2)		= aSyncTimerStateHandles rid tHs.tTimers pState1
			tHs1				= {tHs & tTimers=tsHs}
			ioState1			= ioStSetDevice (TimerSystemState tHs1) ioState
			pState1				= {pState & io=ioState1}
			
			aSyncTimerStateHandles :: !Id ![TimerStateHandle .pst] .pst -> *(![TimerStateHandle .pst],.pst)
			aSyncTimerStateHandles rid [TimerLSHandle {tState=ls,tHandle=tH=:{tItems}}:tsHs] ps
				# (done,tItems,(ls,ps))	= aSyncTimerElementHandles rid tItems (ls,ps)
				  tsH					= TimerLSHandle {tState=ls,tHandle={tH & tItems=tItems}}
				| done
					= ([tsH:tsHs],ps)
				| otherwise
					# (tsHs,ps)			= aSyncTimerStateHandles rid tsHs ps
					= ([tsH:tsHs],ps)
			where
				aSyncTimerElementHandles :: !Id ![TimerElementHandle .ls .pst] *(.ls,.pst)
									  -> (!Bool,![TimerElementHandle .ls .pst],*(.ls,.pst))
				aSyncTimerElementHandles rid [itemH:itemHs] ps
					# (done,itemH, ps)	= aSyncTimerElementHandle  rid itemH  ps
					| done
						= (done,[itemH:itemHs],ps)
					| otherwise
						# (done,itemHs,ps)	= aSyncTimerElementHandles rid itemHs ps
						= (done,[itemH:itemHs],ps)
				where
					aSyncTimerElementHandle :: !Id !(TimerElementHandle .ls .pst) *(.ls,.pst)
										  -> (!Bool,!TimerElementHandle .ls .pst, *(.ls,.pst))
					aSyncTimerElementHandle rid (TimerListLSHandle itemHs) ps
						# (done,itemHs,ps) = aSyncTimerElementHandles rid itemHs ps
						= (done,TimerListLSHandle itemHs,ps)
					aSyncTimerElementHandle rid (TimerElimLSHandle itemHs) ps
						# (done,itemHs,ps) = aSyncTimerElementHandles rid itemHs ps
						= (done,TimerElimLSHandle itemHs,ps)
					aSyncTimerElementHandle rid (TimerIntroLSHandle {tIntroLS,tIntroItems}) (ls,ps)
						# (done,itemHs,(introLS,ps)) = aSyncTimerElementHandles rid tIntroItems (tIntroLS,ps)
						= (done,TimerIntroLSHandle {tIntroLS=introLS,tIntroItems=itemHs},(ls,ps))
					aSyncTimerElementHandle rid (TimerExtendLSHandle {tExtendLS,tExtendItems}) (ls,ps)
						# (done,itemHs,((extendLS,ls),ps)) = aSyncTimerElementHandles rid tExtendItems ((tExtendLS,ls),ps)
						= (done,TimerExtendLSHandle {tExtendLS=extendLS,tExtendItems=itemHs},(ls,ps))
					aSyncTimerElementHandle rid (TimerChangeLSHandle {tChangeLS,tChangeItems}) (ls,ps)
						# (done,itemHs,(changeLS,ps)) = aSyncTimerElementHandles rid tChangeItems (tChangeLS,ps)
						= (done,TimerChangeLSHandle {tChangeLS=changeLS,tChangeItems=itemHs},(ls,ps))
					aSyncTimerElementHandle rid itemH=:(TimerReceiverHandle trH=:{tReceiverHandle=rH}) (ls,ps)
						| receiverIdentified rid rH	= (True, TimerReceiverHandle trH1,(ls1,ps1))
						| otherwise					= (False,TimerReceiverHandle trH, (ls, ps ))
					where
						(rH1,(ls1,ps1))				= aSyncReceiverHandle rH (ls,ps)
						trH1						= {trH & tReceiverHandle=rH1}
						
						aSyncReceiverHandle :: !(ReceiverHandle .ls .pst) *(.ls,.pst) -> *(!ReceiverHandle .ls .pst,*(.ls,.pst))
						aSyncReceiverHandle rH=:{rFun,rASMQ=[m:tailQ]} (ls,ps)
							# (ls,_,ps)	= rFun m (ls,ps)
							= ({rH & rASMQ=tailQ},(ls,ps))
						aSyncReceiverHandle _ _
							= timerdeviceFatalError "asyncReceiverHandle" "message queue of target receiver is empty"
				aSyncTimerElementHandles _ _ ps
					= (False,[],ps)
			aSyncTimerStateHandles _ _ ps
				= ([],ps)
	timerIO (ReceiverEvent (SyncMessage event)) pState
		# (event,pState)	= timerSync event pState
		= (ReceiverEvent (SyncMessage event),pState)
	where
		timerSync :: !SyncMessage !(PSt .l) -> (!SyncMessage,!PSt .l)
		timerSync msg=:{smRecLoc={rlReceiverId=rid}} pState
			= (msg1,pState2)
		where
			(_,timers,ioState)	= ioStGetDevice TimerDevice pState.io
			tHs					= timerSystemStateGetTimerHandles timers
			(msg1,tsHs,pState2)	= syncTimerStateHandles rid msg tHs.tTimers pState1
			tHs1				= {tHs & tTimers=tsHs}
			ioState1			= ioStSetDevice (TimerSystemState tHs1) ioState
			pState1				= {pState & io=ioState1}
			
			syncTimerStateHandles :: !Id !SyncMessage ![TimerStateHandle .pst] .pst
									 -> (!SyncMessage,![TimerStateHandle .pst],.pst)
			syncTimerStateHandles rid msg [TimerLSHandle {tState=ls,tHandle=tH=:{tItems}}:tsHs] ps
				# (done,msg,tItems,(ls,ps))	= syncTimerElementHandles rid msg tItems (ls,ps)
				  tsH						= TimerLSHandle {tState=ls,tHandle={tH & tItems=tItems}}
				| done
					= (msg,[tsH:tsHs],ps)
				| otherwise
					# (msg,tsHs,ps)			= syncTimerStateHandles rid msg tsHs ps
					= (msg,[tsH:tsHs],ps)
			where
				syncTimerElementHandles :: !Id !SyncMessage ![TimerElementHandle .ls .pst] (.ls,.pst)
									 -> (!Bool,!SyncMessage,![TimerElementHandle .ls .pst],(.ls,.pst))
				syncTimerElementHandles rid msg [itemH:itemHs] (ls,ps)
					# (done,msg,itemH,(ls,ps))	= syncTimerElementHandle rid msg itemH (ls,ps)
					| done
						= (done,msg,[itemH:itemHs],(ls,ps))
					| otherwise
						# (done,msg,itemHs,(ls,ps))	= syncTimerElementHandles rid msg itemHs (ls,ps)
						= (done,msg,[itemH:itemHs],(ls,ps))
				where
					syncTimerElementHandle :: !Id !SyncMessage !(TimerElementHandle .ls .pst) (.ls,.pst)
										-> (!Bool,!SyncMessage, !TimerElementHandle .ls .pst, (.ls,.pst))
					syncTimerElementHandle rid msg (TimerReceiverHandle trH=:{tReceiverHandle=rH}) (ls,ps)
						| not (receiverIdentified rid rH)
							= (False,msg,TimerReceiverHandle trH,(ls,ps))
						| otherwise
							# (resp,rH,(ls,ps))	= receiverHandleSyncMessage msg rH (ls,ps)
							= (True, {msg & smResp=resp},TimerReceiverHandle {trH & tReceiverHandle=rH},(ls,ps))
					syncTimerElementHandle rid msg (TimerListLSHandle itemHs) (ls,ps)
						# (done,msg,itemHs,(ls,ps))	= syncTimerElementHandles rid msg itemHs (ls,ps)
						= (done,msg,TimerListLSHandle itemHs,(ls,ps))
					syncTimerElementHandle rid msg (TimerElimLSHandle itemHs) (ls,ps)
						# (done,msg,itemHs,(ls,ps))	= syncTimerElementHandles rid msg itemHs (ls,ps)
						= (done,msg,TimerElimLSHandle itemHs,(ls,ps))
					syncTimerElementHandle rid msg (TimerIntroLSHandle {tIntroLS=inLS,tIntroItems}) (ls,ps)
						# (done,msg,itemHs,(inLS,ps))	= syncTimerElementHandles rid msg tIntroItems (inLS,ps)
						= (done,msg,TimerIntroLSHandle {tIntroLS=inLS,tIntroItems=itemHs},(ls,ps))
					syncTimerElementHandle rid msg (TimerExtendLSHandle {tExtendLS,tExtendItems}) (ls,ps)
						# (done,msg,itemHs,((exLS,ls),ps))	= syncTimerElementHandles rid msg tExtendItems ((tExtendLS,ls),ps)
						= (done,msg,TimerExtendLSHandle {tExtendLS=exLS,tExtendItems=itemHs},(ls,ps))
					syncTimerElementHandle rid msg (TimerChangeLSHandle {tChangeLS,tChangeItems}) (ls,ps)
						# (done,msg,itemHs,(chLS,ps))	= syncTimerElementHandles rid msg tChangeItems (tChangeLS,ps)
						= (done,msg,TimerChangeLSHandle {tChangeLS=chLS,tChangeItems=itemHs},(ls,ps))
				syncTimerElementHandles _ msg _ (ls,ps)
					= (False,msg,[],(ls,ps))
			syncTimerStateHandles _ msg _ ps
				= (msg,[],ps)
	timerIO _ _
		= timerdeviceFatalError "timerIO" "device event passed timer event filter without handling"
