#include "Script.hpp"
//===========================================================================//
// File:	 Script	.cpp													 //
// Project:  GOSScript				                                         //
// Contents: Script control													 //
//---------------------------------------------------------------------------//
// Date      Who    Modification                                             //
// 02/27/98  AG		Created													 //
//---------------------------------------------------------------------------//
// Copyright (C) 2000, Microsoft, Inc.										//
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

extern bool bIgnoreMouseMessages;
extern DWORD gIgnoreFlags;
extern OBJECT * pFocusedObject;
extern OBJECT * pInRegionTopmost;
extern SCRIPT * pFocusedScript;
extern char *ScriptMessageText[];

extern int ScriptMouseButton1;	// for use as variable within scripts
extern int ScriptMouseButton2; // for use as variable within scripts
extern int ScriptMouseButton3; // for use as variable within scripts
extern int ScriptMouseButton4; // for use as variable within scripts
extern int ScriptMouseButton5; // for use as variable within scripts

// Print the object's full descendency (by name)
// 
char * PrintObjectName(OBJECT * obj);

//
// Send a message to the current script. If the function or message is not handled it returns false
//
int SendScriptMessage( OBJECT* Object, MESSAGES Message )
{
	if( !Object || !Object->pFunction )
		return 0;

	LINEINFO* Li;
	FUNCTION* pFunc=Object->pFunction;
	MESSAGE* pMess=pFunc->pMessages;
	bool Found=0;

	if (Message == MSG_GUI_UNFOCUS || (Message == MSG_GUI_DEACTIVATE && pFocusedObject == Object))
	{
		Object->dwIMEState = gos_GetMachineInformation(gos_Info_GetIMEStatus);
		gos_ToggleIME(false);
		gos_EnableIME(false);
	}
	else
	if (Message == MSG_GUI_FOCUS || (Message == MSG_GUI_ACTIVATE && pFocusedObject == Object))
	{
		gos_EnableIME(Object->dwAvailIME);
		gos_ToggleIME(Object->dwIMEState);
	}
	else
	if (Message == MSG_LBUTTON_UPDATE)
		gos_FinalizeStringIME();

#ifdef _ARMOR
	if (!(Message == MSG_GUI_DRAW || Message == MSG_GUI_EXECUTE))
	{
		switch(Message)
		{
		case MSG_LBUTTON_UPDATE:
			{
				switch(ScriptMouseButton1)
				{
				case BUTTON_DCLICKED:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_DCLICKED) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				case BUTTON_CLICKED:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_CLICKED) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				case BUTTON_RELEASED:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_RELEASED) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				case BUTTON_HELD:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_HELD) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				case BUTTON_PRESSED:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_PRESSED) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				}
			}
			break;
		case MSG_RBUTTON_UPDATE:
			{
				switch(ScriptMouseButton2)
				{
				case BUTTON_DCLICKED:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_DCLICKED) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				case BUTTON_CLICKED:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_CLICKED) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				case BUTTON_RELEASED:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_RELEASED) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				case BUTTON_HELD:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_HELD) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				case BUTTON_PRESSED:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_PRESSED) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				}
			}
			break;
		case MSG_MBUTTON_UPDATE:
			{
				switch(ScriptMouseButton3)
				{
				case BUTTON_DCLICKED:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_DCLICKED) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				case BUTTON_CLICKED:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_CLICKED) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				case BUTTON_RELEASED:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_RELEASED) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				case BUTTON_HELD:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_HELD) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				case BUTTON_PRESSED:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_PRESSED) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				}
			}
			break;
		case MSG_AUX1BUTTON_UPDATE:
			{
				switch(ScriptMouseButton4)
				{
				case BUTTON_DCLICKED:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_DCLICKED) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				case BUTTON_CLICKED:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_CLICKED) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				case BUTTON_RELEASED:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_RELEASED) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				case BUTTON_HELD:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_HELD) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				case BUTTON_PRESSED:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_PRESSED) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				}
			}
			break;

		case MSG_AUX2BUTTON_UPDATE:
			{
				switch(ScriptMouseButton5)
				{
				case BUTTON_DCLICKED:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_DCLICKED) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				case BUTTON_CLICKED:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_CLICKED) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				case BUTTON_RELEASED:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_RELEASED) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				case BUTTON_HELD:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_HELD) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				case BUTTON_PRESSED:
					SPEW((GROUP_SCRIPTS, "Sending %s(BUTTON_PRESSED) to %s", ScriptMessageText[Message], PrintObjectName(Object)));
					break;
				}
			}
			break;


		default:
			SPEW((GROUP_SCRIPTS, "Sending %s to %s", ScriptMessageText[Message], PrintObjectName(Object)));
		}
	}
#endif
	while( pMess )
	{
		if( Message==pMess->Message )
		{
			Found=1;
			break;
		}
		pMess=pMess->pNext;
	}

	bIgnoreMouseMessages = true;
	if( !Found )
	{
		switch (Message)
		{
		case MSG_LBUTTON_UPDATE:
		case MSG_RBUTTON_UPDATE:
		case MSG_MBUTTON_UPDATE:
		case MSG_AUX1BUTTON_UPDATE:
		case MSG_AUX2BUTTON_UPDATE:
		case MSG_WHEEL_MOVED:
		case MSG_REGION_ENTERED:
		//case MSG_REGION_EXITED:
			gIgnoreFlags |= (1<<Message);		// didn't find a message, assume ignore
			break;
		}
		Object->dwBlockingFlags |= (1<<Message);
		if (Message != MSG_GUI_DESTROY && Message != MSG_GUI_PAUSE)
			return 0;
	}

	if (Found)
	{
		Li=pMess->pOffset;
		
		SavePosition();									// Do not interfere with any executing script
	
		pStartofLine=(char*)Li;
		pTempVariables=0;
		CurrentMessage=Message;
		pObject=Object;

		pScript = Object->pScript;

		DoCommands(1);									// Execute message

		while( pTempVariables )
		{
			VARIABLE* pTemp=pTempVariables;
			pTempVariables=pTempVariables->pNext;		// Remove any temporary variables
			DeleteVariable( pTemp );
		}

		RestorePosition(); 								// Restore previous execution state

		switch (Message)
		{
		case MSG_LBUTTON_UPDATE:
		case MSG_RBUTTON_UPDATE:
		case MSG_MBUTTON_UPDATE:
		case MSG_AUX1BUTTON_UPDATE:
		case MSG_AUX2BUTTON_UPDATE:
		case MSG_WHEEL_MOVED:
		case MSG_REGION_ENTERED:
		//case MSG_REGION_EXITED:
			gIgnoreFlags |= (bIgnoreMouseMessages<<Message);
			Object->dwBlockingFlags |= (bIgnoreMouseMessages<<Message);
			break;
		}
	}

	if (Message == MSG_GUI_DESTROY)
	{
		VARIABLE * var = Object->pVariables;
		while(var)
		{
			if (var->Type == VAR_OBJECT)
			{

				if (var->ArraySize == 0)
				{
					//
					// If the cursor is in this object's region, be sure to send it 
					// a region_exited msg before deactivation.
					//
					//if (((OBJECT*)var->Value)->bMouseInRegion)
					//	SendScriptMessage(((OBJECT*)var->Value), MSG_REGION_EXITED );	
					SendScriptMessage(((OBJECT*)var->Value), MSG_GUI_DESTROY);
				}
				else
				{
					for(int i=0; i < var->ArraySize; i++)
					{
						//	
						// If the cursor is in this object's region, be sure to send it 
						// a region_exited msg before deactivation.
						//
						//if (((OBJECT*)var->pValues[i])->bMouseInRegion)
						//	SendScriptMessage(((OBJECT*)var->pValues[i]), MSG_REGION_EXITED );	
						SendScriptMessage(((OBJECT*)var->pValues[i]), MSG_GUI_DESTROY);
					}
				}
			}
			var = var->pNext;
		}
	}
	else
	if (Message == MSG_GUI_PAUSE)
	{
		VARIABLE * var = Object->pVariables;
		while(var)
		{
			if (var->Type == VAR_OBJECT)
			{

				if (var->ArraySize == 0)
				{
					//
					// If the cursor is in this object's region, be sure to send it 
					// a region_exited msg before deactivation.
					//
					if (((OBJECT*)var->Value)->bMouseInRegion)
						SendScriptMessage(((OBJECT*)var->Value), MSG_REGION_EXITED );	
				}
				else
				{
					for(int i=0; i < var->ArraySize; i++)
					{
						//	
						// If the cursor is in this object's region, be sure to send it 
						// a region_exited msg before deactivation.
						//
						if (((OBJECT*)var->pValues[i])->bMouseInRegion)
							SendScriptMessage(((OBJECT*)var->pValues[i]), MSG_REGION_EXITED );	
					}
				}
			}
			var = var->pNext;
		}
	}

	return 1;
}

void DeleteScriptObject(OBJECT * del_obj)
{
	if (del_obj == pFocusedObject)
	{
//
//	Removed by JTR 09/11/99. unfocus now has to be called explicited before 
//	destroying an object-- it is no longer automatic
// 
//		SendScriptMessage(del_obj, MSG_GUI_UNFOCUS);
		pFocusedObject = NULL;
		pFocusedScript = NULL;
	}

	if (del_obj == pInRegionTopmost)
		pInRegionTopmost = NULL;

	//SendScriptMessage(del_obj, MSG_GUI_DESTROY);

	OBJECT * pPrev = NULL;
	OBJECT * pObj=pScript->pListofObjects;
	while (pObj)
	{
		if (del_obj == pObj)
		{
			if (pPrev)
			{
				pPrev->pNext = pObj->pNext;
			}
			else
			{
				pScript->pListofObjects = pObj->pNext;
			}

			//
			// Remove any variables
			//
			VARIABLE *pVariable=pObj->pVariables;
			while( pVariable )
			{
				VARIABLE* pTemp=pVariable->pNext;
				DeleteVariable( pVariable );
				pVariable=pTemp;
			}
//
// AG - this was causing leaks - never let a child object mess with it's parent!
//
//			if (pObj->pParentVariable)
//				pObj->pParentVariable->Value = 0;
			gos_Free(pObj);
			del_obj = 0;
			return;
		}
		pPrev = pObj;
		pObj = pObj->pNext;
	}
//
//
//
	ScriptError("Couldn't delete bogus object");
}









//
// End the current script
//
void EndScript()
{
//
// Is this a valid script?
//
	SCRIPT * ptr = pListofScripts;
	while(ptr)
	{
		if (ptr == pScript)
			break;
		else
			ptr = ptr->pNext;
	}
	if (ptr == NULL)
	{
		PAUSE(("Attempted to end a non-existent script"));
		return;
	}

	if (( *pScript->pMainObject->Priority & 0xff00) == 0x2000)
		ModalScripts--;
//
// Remove any objects
//
	DeleteScriptObject(pScript->pMainObject);
//
// Remove any file names
//
	FILENAME* pFileName=pScript->pFileNames;
	while( pFileName )
	{
		FILENAME* pTemp=pFileName->pNext;
		gos_Free( pFileName );
		pFileName=pTemp;
	}
//
// Remove any functions and message pointers
//
	FUNCTION* pFunction, *tFunction;
	MESSAGE* pMessage, *tMessage;
	pFunction=pScript->pFunctions;
	while( pFunction )
	{
		pMessage=pFunction->pMessages;
		while( pMessage )
		{
			tMessage=pMessage;
			pMessage=pMessage->pNext;
			gos_Free( tMessage );
		}
				
		tFunction=pFunction;
		pFunction=pFunction->pNext;
		gos_Free( tFunction );
	}
//
// Find in global list of scripts and remove it.
//
	SCRIPT* pTemp=pListofScripts;
	SCRIPT* pLast=0;
	while( pTemp )
	{
		if( pTemp==pScript )
		{
			if( pLast )
			{
				pLast->pNext=pTemp->pNext;		// Remove from chain
			}
			else
			{
				pListofScripts=pTemp->pNext;
			}
			break;
		}
		pLast=pTemp;
		pTemp=pTemp->pNext;
	}
//
// Release script buffer
//
	while( pScript->pBuffer )
	{
		char* pNext=(char*)*((DWORD*)(pScript->pBuffer+SizeOfProcessBlock));			// Pointer to any 'next block'
		gos_Free( pScript->pBuffer );
		pScript->pBuffer=pNext;
	}
//
// Release memory used for script itself
//
	pTemp=pScript->pNext;
	gos_Free( pScript );
	ScriptNumber--;
	pScript=pTemp;								// Make pScript point to next valid script
}


char * PrintObjectName(OBJECT * obj)
{
	static char ObjectName[256];

	strcpy(ObjectName, obj->Name);

	OBJECT * itr = obj->pParentObject;
	while (itr)
	{
		strcat(ObjectName, "<-");
		strcat(ObjectName, itr->Name);
		itr = itr->pParentObject;
	}
	return ObjectName;
}