BOOL SM_CloseStateTree(STATE_TREE_INFO_T * pStateTreeInfo)
{
	s32 i;
	const STATE_NODE_T *pStateTree, *pStateNode;

	MT_ASSERT(NULL!=pStateTreeInfo);
	MT_ASSERT(NULL!=pStateTreeInfo->pStateTree);
	MT_ASSERT(0!=pStateTreeInfo->activeDepth);

	SM_TRACE("SM Closing...: %s", pStateTreeInfo->pModuleName);
	pStateTree = pStateTreeInfo->pStateTree;

	//Exit current states
	for (i=pStateTreeInfo->activeDepth-1; i>=0; i--)
	{
		pStateNode = &pStateTree[pStateTreeInfo->activeStateID[i]];
		SM_TRACE("SM Exiting state: %d", pStateTreeInfo->activeStateID[i]);
		if (NULL!=pStateNode->Exit)
		{
			pStateNode->Exit();
		}
		SM_TRACE("SM Exited state: %d", pStateTreeInfo->activeStateID[i]);
		pStateTreeInfo->activeStateID[i] = SID_NULL;
		pStateTreeInfo->activeDepth--;
	}
	
	return 1;
}
// Load the module information from the given DLL
bool SMModuleInfo::LoadInfo(const char* szPathAndFilename)
{
	SM_TRACE(SMTRACE, "SMModuleInfo: Loading module '" << szPathAndFilename << "'");

	// Reset everything
	Cleanup();

	bool result = false;

    DWORD dwHandle;

	// Get the size of the buffer we need to allocation
    dwModuleInfoSize = ::GetFileVersionInfoSize(szPathAndFilename, &dwHandle);
    
	SM_TRACE(SMTRACE, "SMModuleInfo: Module info size =" << dwModuleInfoSize);

	if (dwModuleInfoSize > 0)
	{
		// Allocate the buffer
		pModuleInfo = new BYTE[dwModuleInfoSize];

		if (pModuleInfo != NULL)
		{
			SM_TRACE(SMTRACE, "SMModuleInfo: Getting module info.");
			// Fill the buffer with all the module info
			if (::GetFileVersionInfo(szPathAndFilename, 0, dwModuleInfoSize, pModuleInfo) != FALSE)
			{
				SM_TRACE(SMTRACE, "SMModuleInfo: Checking Codepage.");
				// How many codepages does the module have?
				if (::VerQueryValue(pModuleInfo, "\\VarFileInfo\\Translation", (LPVOID*)&pTranslate, &uiTranslateSize) != FALSE)
				{
					// Success!
					result = true;
				}
			}
		}
	}

	// How'd we do?
	return result;
}
BOOL SM_OpenStateTree(STATE_TREE_INFO_T * pStateTreeInfo)
{
	s32 i;

	MT_ASSERT(NULL!=pStateTreeInfo);
	MT_ASSERT(NULL!=pStateTreeInfo->pStateTree);
	MT_ASSERT(0==pStateTreeInfo->activeDepth);

	SM_TRACE("SM Opening...: %s", pStateTreeInfo->pModuleName);

	for (i=0; i<STATE_TREE_MAX_DEPTH; i++)
	{
		pStateTreeInfo->activeStateID[i] = SID_NULL;
	}

	return SmDoTransition(pStateTreeInfo, SID_ROOT);
}
static BOOL SmDoTransition(
	STATE_TREE_INFO_T * pStateTreeInfo, 
	STATEID nDstStateID)
{
	s32 i;
	const STATE_NODE_T *pStateTree = pStateTreeInfo->pStateTree, *pStateNode;
	u16 sameParentDepth = 0;
	u16 curDepth, dstDepth;
	STATEID dstStates[STATE_TREE_MAX_DEPTH];

	MT_ASSERT(nDstStateID>SID_NULL);
	MT_ASSERT(nDstStateID<pStateTreeInfo->maxStateID);
	SM_TRACE("SM Transiting...: %s", pStateTreeInfo->pModuleName);

	//Get state chain of destination, and its depth
	dstDepth = SmGetStatesChain(pStateTreeInfo, nDstStateID, dstStates);
	curDepth = pStateTreeInfo->activeDepth;

	//Get the fork of these two state chain
	for (i=0; (i<curDepth) && (i<dstDepth); i++)
	{
		if (pStateTreeInfo->activeStateID[i]!=dstStates[i])
		{ //Their parent is the fork!
			break;
		}
		if (nDstStateID==dstStates[i])
		{ //Treat their parent as the fork!
			break;
		}
		sameParentDepth = (u16)(i + 1);
	}

	//Exit current states
	for (i=curDepth-1; i>=sameParentDepth; i--)
	{
		pStateNode = &pStateTree[pStateTreeInfo->activeStateID[i]];
		SM_TRACE("SM Exiting state: %d", pStateTreeInfo->activeStateID[i]);
		if (NULL!=pStateNode->Exit)
		{
			pStateNode->Exit();
		}
		SM_TRACE("SM Exited state: %d", pStateTreeInfo->activeStateID[i]);
		pStateTreeInfo->activeStateID[i] = SID_NULL;
		pStateTreeInfo->activeDepth--;
	}
	//Enter new states
	for (i=sameParentDepth; i<dstDepth; i++)
	{
		pStateTreeInfo->activeStateID[i] = dstStates[i];
		pStateTreeInfo->activeDepth++;
		pStateNode = &pStateTree[dstStates[i]];
		SM_TRACE("SM Entering state: %d", pStateTreeInfo->activeStateID[i]);
		if (NULL!=pStateNode->Entry)
		{
			pStateNode->Entry();
		}
		SM_TRACE("SM Entered state: %d", pStateTreeInfo->activeStateID[i]);
	}

	SM_TRACE("SM Transited...: %s", pStateTreeInfo->pModuleName);
	return TRUE;
}
s32 SM_DispatchMsg(STATE_TREE_INFO_T * pStateTreeInfo, control_t *ctrl, u16 msg, u32 para1, u32 para2)
{
	s32 i, j;
	s32 result = ERR_NOFEATURE; //The message has NOT been processed
	const STATE_NODE_T *pStateTree, *pStateNode;
	const STATE_TRANS_T *pStateTransTab, *pStateTrans;
	STATEID curStateID = SID_NULL;
	STATEID nextStateID = SID_NULL;
	MSGID nMsgID = 0;

	MT_ASSERT(NULL!=pStateTreeInfo);
	MT_ASSERT(NULL!=pStateTreeInfo->pStateTree);
	MT_ASSERT(0!=pStateTreeInfo->activeDepth);

	SM_TRACE("SM Dispatching MSG %d to MODULE %s", msg, pStateTreeInfo->pModuleName);
	pStateTree = pStateTreeInfo->pStateTree;
	nMsgID = msg;

	//Check each state node from top to bottom
	//for (i=0; i<pStateTreeInfo->activeDepth; i++)
	//Check each state node from bottom to top
	for (i=pStateTreeInfo->activeDepth-1; i>=0; i--)
	{
		SM_TRACE("SM Parsing in state: %d", pStateTreeInfo->activeStateID[i]);
		curStateID = pStateTreeInfo->activeStateID[i];
		if ((SID_NULL==curStateID)
			|| (curStateID>=pStateTreeInfo->maxStateID)
			|| (NULL==(pStateNode=&pStateTreeInfo->pStateTree[curStateID])))
		{ //Error
			break;
		}
		if (NULL==(pStateTransTab=pStateNode->pTransTab))
		{ //No transition table
			continue;
		}

		//Check each transition in the transition table of this node
		for (j=0; j<pStateNode->transCount; j++)
		{
			pStateTrans = &pStateTransTab[j];

			if (pStateTrans->msgID==nMsgID) //Message ID matched, then check transit condition and do transition
			{
				SM_TRACE("SM Msg matched in state %d at pos %d", pStateTreeInfo->activeStateID[i], j);
				if ((NULL!=pStateTrans->TransCondition) 
					&& (FALSE==pStateTrans->TransCondition(ctrl, msg, para1, para2)))
				{ //It has transit condition, but the condition is FALSE
					continue;
				}

				SM_TRACE("SM Msg processing in state %d at pos %d", pStateTreeInfo->activeStateID[i], j);
				result = SUCCESS; //The message has been processed

				if (NULL!=pStateTrans->TransAction)
				{ //Process its transit action
					SM_TRACE("SM Msg action...MODULE: %s", pStateTreeInfo->pModuleName);
					nextStateID = pStateTrans->TransAction(ctrl, msg, para1, para2);
					SM_TRACE("SM Msg action OK...MODULE: %s", pStateTreeInfo->pModuleName);
				}

				SM_TRACE("SM destState: %d, but nextState: %d", pStateTrans->dstStateID, nextStateID);
				if (SID_INTERNAL==pStateTrans->dstStateID)
				{
					if (SID_NULL==nextStateID)
					{
						return result;
					}
					if ((SID_NULL!=nextStateID) && (nextStateID<pStateTreeInfo->maxStateID))
					{ //Transit to the RETURNed state, and return directly
						SM_TRACE("SM Msg INTERNAL jumping...next state: %d", nextStateID);
						SmDoTransition(pStateTreeInfo, nextStateID);
						SM_TRACE("SM Msg INTERNAL jumped...next state: %d", nextStateID);
						return result;
					}
					else
					{
						continue;
					}
				}
				else
				{
					nextStateID = pStateTrans->dstStateID;
					if ((SID_NULL!=nextStateID) && (nextStateID<pStateTreeInfo->maxStateID))
					{ //We will not check any more and return directly
						SM_TRACE("SM Msg JUMPing...next state: %d", nextStateID);
						SmDoTransition(pStateTreeInfo, nextStateID);
						SM_TRACE("SM Msg JUMPed...next state: %d", nextStateID);
					}
					return result;
				}
			}
		}
	}

	return result;
}