implementation module mstate


import	StdBool, StdClass, StdInt
import	menuhandle
from commondef import fatalError


mstateFatalError :: String String -> .x
mstateFatalError rule error
	= fatalError rule "mstate" error


/*	The MenuHandle` data type.
	This type is a subtype of the MenuHandle data type. The MenuHandle` data type 
	takes the projection of those fields of the (MenuHandle ls ps) data type that 
	do not depend on the type variables {ls,ps}.
*/

::	MenuHandle`
	=	{	mHandle`	:: !OSMenu						// The handle to the menu as created by the OS
		,	mMenuId`	:: !Id							// The menu id
		,	mOSMenuNr`	:: !OSMenuNr					// The OSMenuNr
		,	mTitle`		:: !String						// The title of the menu
		,	mSelect`	:: !Bool						// The MenuSelect==Able (by default True)
		,	mItems`		:: ![MenuElementHandle`]		// The menu elements of this menu
		}
::	MenuElementHandle`
	=	MenuItemHandle`			!MenuItemHandle`
	|	MenuReceiverHandle`		!MenuReceiverHandle`
	|	SubMenuHandle`			!SubMenuHandle`
	|	RadioMenuHandle`		!RadioMenuHandle`
	|	MenuSeparatorHandle`	!MenuSeparatorHandle`
	|	MenuRecursiveHandle`	![MenuElementHandle`] !MenuRecursiveKind
::	MenuRecursiveKind
	=	IsMenuListLSHandle
	|	IsMenuExtendLSHandle
	|	IsMenuChangeLSHandle
::	MenuItemHandle`
	=	{	mItemId`		:: !Maybe Id
		,	mItemKey`		:: !Maybe Char
		,	mItemTitle`		:: !Title
		,	mItemSelect`	:: !Bool
		,	mItemMark`		:: !Bool
		,	mItemAtts`		:: ![MenuAttribute`]
		,	mOSMenuItem`	:: !OSMenuItem
		}
::	MenuReceiverHandle`
	=	{	mReceiverId`	:: !Id
		,	mReceiverSelect`:: !Bool
		}
::	SubMenuHandle`
	=	{	mSubHandle`		:: !OSMenu
		,	mSubMenuId`		:: !Maybe Id
		,	mSubOSMenuNr`	:: !OSSubMenuNr
		,	mSubItems`		:: ![MenuElementHandle`]
		,	mSubTitle`		:: !Title
		,	mSubSelect`		:: !Bool
		,	mSubAtts`		:: ![MenuAttribute`]
		}
::	RadioMenuHandle`
	=	{	mRadioId`		:: !Maybe Id
		,	mRadioIndex`	:: !Int						// If mRadioItems==[] 0, otherwise 1..#mRadioItems
		,	mRadioItems`	:: ![MenuElementHandle`]
		,	mRadioSelect`	:: !Bool
		,	mRadioAtts`		:: ![MenuAttribute`]
		}
::	MenuSeparatorHandle`
	=	{	mSepId`			:: !Maybe Id
		}
::	MenuAttribute`										//	Default:
	=	MenuId`				Id							//	no Id
	|	MenuSelectState`	SelectState					//	menu(item) Able
	|	MenuShortKey`		Char						//	no ShortKey
	|	MenuMarkState`		MarkState					//	NoMark


getMenuHandle` :: !(MenuHandle .ls .ps) -> (!MenuHandle`,!MenuHandle .ls .ps)
getMenuHandle` mH=:{mHandle,mMenuId,mOSMenuNr,mTitle,mSelect,mItems=items}
	# (items`,items)	= getMenuElementHandles items
	= (	{mHandle`=mHandle,mMenuId`=mMenuId,mOSMenuNr`=mOSMenuNr,mTitle`=mTitle,mSelect`=mSelect,mItems`=items`}
	  ,	{mH & mItems=items}
	  )
where
	getMenuElementHandles :: ![MenuElementHandle .ls .ps] -> (![MenuElementHandle`],![MenuElementHandle .ls .ps])
	getMenuElementHandles [itemH:itemHs]
		#! (itemH`, itemH)	= getMenuElementHandle  itemH
		#! (itemHs`,itemHs)	= getMenuElementHandles itemHs
		=  ([itemH`:itemHs`],[itemH:itemHs])
	where
		getMenuElementHandle :: !(MenuElementHandle .ls .ps) -> (!MenuElementHandle`,!MenuElementHandle .ls .ps)
		getMenuElementHandle (MenuItemHandle itemH=:{mItemId,mItemKey,mItemTitle,mItemSelect,mItemMark,mItemAtts=atts,mOSMenuItem})
			# (atts`,atts)		= getMenuAttributes atts
			= ( MenuItemHandle`
				{	mItemId`	= mItemId
				,	mItemKey`	= mItemKey
				,	mItemTitle`	= mItemTitle
				,	mItemSelect`= mItemSelect
				,	mItemMark`	= mItemMark
				,	mItemAtts`	= atts`
				,	mOSMenuItem`= mOSMenuItem
				}
			  , MenuItemHandle 
				{itemH & mItemAtts=atts}
			  )
		getMenuElementHandle (MenuReceiverHandle recH=:{mReceiverHandle={rId,rSelect}})
			= ( MenuReceiverHandle`
					{	mReceiverId`	= rId
					,	mReceiverSelect`= rSelect==Able
					}
			  , MenuReceiverHandle recH
			  )
		getMenuElementHandle (SubMenuHandle subH=:{mSubHandle,mSubMenuId,mSubOSMenuNr,mSubItems=items,mSubTitle,mSubSelect,mSubAtts=atts})
			# (items`,items)		= getMenuElementHandles items
			  (atts`, atts)			= getMenuAttributes atts
			= ( SubMenuHandle`
				{	mSubHandle`		= mSubHandle
				,	mSubMenuId`		= mSubMenuId
				,	mSubOSMenuNr`	= mSubOSMenuNr
				,	mSubItems`		= items`
				,	mSubTitle`		= mSubTitle
				,	mSubSelect`		= mSubSelect
				,	mSubAtts`		= atts`
				}
			  , SubMenuHandle
				{subH & mSubItems=items,mSubAtts=atts}
			  )
		getMenuElementHandle (RadioMenuHandle radioH=:{mRadioId,mRadioIndex,mRadioItems=items,mRadioSelect,mRadioAtts=atts})
			# (items`,items)		= getMenuElementHandles items
			  (atts`, atts)			= getMenuAttributes atts
			= ( RadioMenuHandle`
				{	mRadioId`		= mRadioId
				,	mRadioIndex`	= mRadioIndex
				,	mRadioItems`	= items`
				,	mRadioSelect`	= mRadioSelect
				,	mRadioAtts`		= atts`
				}
			  ,	RadioMenuHandle
				{radioH & mRadioItems=items,mRadioAtts=atts}
			  )
		getMenuElementHandle (MenuSeparatorHandle sepH=:{mSepId})
			= (MenuSeparatorHandle` {mSepId`=mSepId},MenuSeparatorHandle sepH)
		getMenuElementHandle (MenuListLSHandle items)
			# (items`,items)		= getMenuElementHandles items
			= (MenuRecursiveHandle` items` IsMenuListLSHandle,MenuListLSHandle items)
		getMenuElementHandle (MenuExtendLSHandle exH=:{mExtendItems=items})
			# (items`,items)		= getMenuElementHandles items
			= (MenuRecursiveHandle` items` IsMenuExtendLSHandle,MenuExtendLSHandle {exH & mExtendItems=items})
		getMenuElementHandle (MenuChangeLSHandle chH=:{mChangeItems=items})
			# (items`,items)		= getMenuElementHandles items
			= (MenuRecursiveHandle` items` IsMenuChangeLSHandle,MenuChangeLSHandle {chH & mChangeItems=items})
		
		getMenuAttributes :: ![MenuAttribute .ps] -> (![MenuAttribute`],![MenuAttribute .ps])
		getMenuAttributes [att:atts]
			#! (ok,att`,att)	= getMenuAttribute  att
			#! (atts`, atts)	= getMenuAttributes atts
			| ok				= ([att`:atts`],[att:atts])
			| otherwise			= (      atts`, [att:atts])
		where
			getMenuAttribute :: !(MenuAttribute .ps) -> (!Bool,!MenuAttribute`,!MenuAttribute .ps)
			getMenuAttribute att=:(MenuId			id)		= (True,MenuId`			 id,	 att)
			getMenuAttribute att=:(MenuSelectState	select)	= (True,MenuSelectState` select, att)
			getMenuAttribute att=:(MenuShortKey		keycode)= (True,MenuShortKey`	 keycode,att)
			getMenuAttribute att=:(MenuMarkState	mark)	= (True,MenuMarkState`	 mark,	 att)
			getMenuAttribute att							= (False,MenuShortKey`	 '0',	 att)
		getMenuAttributes _
			= ([],[])
	getMenuElementHandles _
		= ([],[])


setMenuHandle` :: !MenuHandle` !(MenuHandle .ls .ps) -> MenuHandle .ls .ps
setMenuHandle` mH`=:{mHandle`,mTitle`,mSelect`,mItems`} mH=:{mHandle,mItems}
	| mHandle`<>mHandle	= mstateFatalError "setMenuHandle`" "mHandle` field <> mHandle field"
	| otherwise			= {mH & mItems=setMenuElementHandles mItems` mItems}
where
	setMenuElementHandles :: ![MenuElementHandle`] ![MenuElementHandle .ls .ps] -> [MenuElementHandle .ls .ps]
	setMenuElementHandles [itemH`:itemHs`] [itemH:itemHs]
		#! itemH		= setElementHandle itemH` itemH
		#! itemHs		= setMenuElementHandles itemHs` itemHs
		= [itemH:itemHs]
	where
		setElementHandle :: !MenuElementHandle` !(MenuElementHandle .ls .ps) -> MenuElementHandle .ls .ps
		
		setElementHandle (MenuItemHandle` itemH`=:{mItemAtts`,mItemTitle`,mItemSelect`,mItemMark`})
						 (MenuItemHandle  itemH =:{mItemAtts})
			# atts	= setMenuAttributes mItemAtts` mItemAtts
			= MenuItemHandle {itemH & mItemAtts=atts,mItemTitle=mItemTitle`,mItemSelect=mItemSelect`,mItemMark=mItemMark`}
		
		setElementHandle (MenuReceiverHandle` recH`=:{mReceiverSelect`})
						 (MenuReceiverHandle  recH =:{mReceiverHandle=rH})
			= MenuReceiverHandle {recH & mReceiverHandle={rH & rSelect=if mReceiverSelect` Able Unable}}
		
		setElementHandle (SubMenuHandle` subH`=:{mSubItems`,mSubAtts`,mSubTitle`,mSubSelect`})
						 (SubMenuHandle  subH =:{mSubItems, mSubAtts})
			# atts	= setMenuAttributes mSubAtts` mSubAtts
			  items	= setMenuElementHandles mSubItems` mSubItems
			= SubMenuHandle {subH & mSubItems=items,mSubAtts=atts,mSubTitle=mSubTitle`,mSubSelect=mSubSelect`}
		
		setElementHandle (RadioMenuHandle` radioH`=:{mRadioItems`,mRadioAtts`,mRadioSelect`,mRadioIndex`})
						 (RadioMenuHandle  radioH =:{mRadioItems, mRadioAtts})
			# atts	= setMenuAttributes mRadioAtts` mRadioAtts
			  items	= setMenuElementHandles mRadioItems` mRadioItems
			= RadioMenuHandle {radioH & mRadioIndex=mRadioIndex`,mRadioItems=items,mRadioSelect=mRadioSelect`,mRadioAtts=atts}
		
		setElementHandle (MenuSeparatorHandle` _) sepH=:(MenuSeparatorHandle _)
			= sepH
		
		setElementHandle (MenuRecursiveHandle` itemHs` IsMenuListLSHandle) (MenuListLSHandle itemHs)
			= MenuListLSHandle (setMenuElementHandles itemHs` itemHs)
		
		setElementHandle (MenuRecursiveHandle` itemHs` IsMenuExtendLSHandle) (MenuExtendLSHandle exH=:{mExtendItems})
			= MenuExtendLSHandle {exH & mExtendItems=setMenuElementHandles itemHs` mExtendItems}
		
		setElementHandle (MenuRecursiveHandle` itemHs` IsMenuChangeLSHandle) (MenuChangeLSHandle chH=:{mChangeItems})
			= MenuChangeLSHandle {chH & mChangeItems=setMenuElementHandles itemHs` mChangeItems}
		
		setElementHandle _ _
			= mstateFatalError "setMenuHandle`" "MenuElementHandles do not match pairwise"
	setMenuElementHandles [] []
		= []
	setMenuElementHandles _ _
		= mstateFatalError "setMenuHandle`" "incompatible number of MenuElementHandles"
	
	setMenuAttributes :: ![MenuAttribute`] ![MenuAttribute .ps] -> [MenuAttribute .ps]
	setMenuAttributes [att`:atts`] atts
		| isConstantAttribute att`		= setMenuAttributes atts` atts
		| otherwise						= setMenuAttributes atts` (setAttribute att` atts)
	where
		isConstantAttribute :: !MenuAttribute` -> Bool
		isConstantAttribute (MenuId` _)	= True
		isConstantAttribute _			= False
		
		setAttribute :: !MenuAttribute` ![MenuAttribute .ps] -> [MenuAttribute .ps]
		setAttribute att` [att:atts]
			| match att` att	= [att1:atts]
			| otherwise
				#! atts			= setAttribute att` atts
				=  [att:atts]
		where
			att1	= case att` of
						(MenuSelectState`	select)	-> MenuSelectState	select
						(MenuShortKey`		keycode)-> MenuShortKey		keycode
						(MenuMarkState`		mark)	-> MenuMarkState	mark
						_							-> mstateFatalError "setMenuHandle" "illegal MenuAttribute` encountered"
			
			match (MenuSelectState` _) (MenuSelectState _)	= True
			match (MenuShortKey`	_) (MenuShortKey	_)	= True
			match (MenuMarkState`	_) (MenuMarkState	_)	= True
			match _						_					= False
		setAttribute att` _
			= mstateFatalError "setMenuHandle" "non-matching MenuAttribute encountered"
	setMenuAttributes _ atts
		= atts
