#include ".\pythoninclude\Python.h"
#include "scripts.h"
#include "engine.h"
#include "scriptsmanager.h"
#include "helper_functions.h"
#pragma warning( disable : 701 127 )

ScriptManager::Script *ScriptManager::Scripts[256];



void ScriptManager::Load()
{
	memset((void *)Scripts, 0, 256*4);
}

void ScriptManager::Cleanup()
{
	for(int script_it = 0; script_it < 256; script_it++)
	{
		Script *s = Scripts[script_it];
		if(!s)
		{
			continue;
		}
		delete s->scriptreg;
		delete s;
		
	}
	memset((void *)Scripts, 0, 256*4);
}


PyCFunction* ScriptManager::registerscript(PyObject *self, PyObject *args)
{
	const char *name, *params;
	PyObject* pTemp = 0;


	if (!PyArg_ParseTuple(args, "ss", &name, &params))
	{
		printf("\nError occured inside scriptsdll.registerscript.\n Bad argument(s)?\n");
        return NULL;
	}	

	for(int script_it = 0; script_it < 256; script_it++)
	{
		if(Scripts[script_it])
		{
			if(_stricmp(Scripts[script_it]->name, name) == 0)
			{
				printf("\nYou cannot register more than one script with the same name.\n");
				return NULL;
			}
		}
	}

	Script *s = new Script;
	//s->classobject = uRef;
	strcpy(s->name, name);
	strcpy(s->params, params);
	s->scriptreg = new ScriptRegistrant<PythonScript>((char *)name, (char *)params);

	for( int i = 0; i < ModulesArrayIndex; i++)
	{
		if (PyObject_HasAttrString(ModulesArray[i], name)) 
		{
			pTemp = PyObject_GetAttrString(ModulesArray[i], name);
			 /* pTemp is a new reference */
			if (pTemp) 
			{			
				s->classobject = pTemp;
				Py_XDECREF(pTemp);
				break;
			}
		}
	}
	
	if ( s->classobject == 0)
	{
		fprintf(stderr, "Cannot find class \"%s\"\n", name);
		return NULL;
	}

	for(int script_it = 0; script_it < 256; script_it++)
	{
		if(Scripts[script_it] == 0)
		{
			Scripts[script_it] = s;
			Py_INCREF(Py_None);
			return (PyCFunction*)Py_None;
		}
	}
	return NULL;
}

void ScriptManager::PythonScript::Created(GameObject *obj) // God bless copy paste
{
	for(int script_it = 0; script_it < 256; script_it++)
	{
		Script *s = Scripts[script_it];
		if(!s)
		{
			continue;
		}
		if(strcmp(s->name, this->Get_Name()) == 0)
		{
			if (PyObject_HasAttrString(s->classobject, "Created"))
			{
				PyObject* pFunc = PyObject_GetAttrString(s->classobject, "Created");
				if (pFunc && PyCallable_Check(pFunc))
				{
					int id = GetID();
					int o = Helper::Get_ID(obj);
					PyObject* pArgs = Py_BuildValue("(ii)", id, o);
					PyObject* result = PyObject_CallObject(pFunc, pArgs);
					if ( result == NULL)
					{
						Py_XDECREF(result);
						printf("\nError occured while trying to call %s::Created(). Bad arguments?\n", s->name);
						PyErr_Clear();
					}
					Py_XDECREF(result);
					break;
				}
				break;
			}
		}
	}
}

void ScriptManager::PythonScript::Destroyed(GameObject *obj)
{
	for(int script_it = 0; script_it < 256; script_it++)
	{
		Script *s = Scripts[script_it];
		if(!s)
		{
			continue;
		}
		if(strcmp(s->name, this->Get_Name()) == 0)
		{
			if (PyObject_HasAttrString(s->classobject, "Destroyed"))
			{
				PyObject* pFunc = PyObject_GetAttrString(s->classobject, "Destroyed");
				if (pFunc && PyCallable_Check(pFunc))
				{
					int id = GetID();
					int o = Helper::Get_ID(obj);
					PyObject* pArgs = Py_BuildValue("(ii)", id, o);
					PyObject* result = PyObject_CallObject(pFunc, pArgs);
					if ( result == NULL)
					{
						Py_XDECREF(result);
						printf("\nError occured while trying to call %s::Destroyed(). Bad arguments?\n", s->name);
						PyErr_Clear();
					}
					Py_XDECREF(result);
					break;
				}
				break;
			}
		}
	}
}

void ScriptManager::PythonScript::Killed(GameObject *obj,GameObject *shooter)
{
	for(int script_it = 0; script_it < 256; script_it++)
	{
		Script *s = Scripts[script_it];
		if(!s)
		{
			continue;
		}
		if(strcmp(s->name, this->Get_Name()) == 0)
		{
			if (PyObject_HasAttrString(s->classobject, "Killed"))
			{
				PyObject* pFunc = PyObject_GetAttrString(s->classobject, "Killed");
				if (pFunc && PyCallable_Check(pFunc))
				{
					int id = GetID();
					int o = Helper::Get_ID(obj);
					int killer = Helper::Get_ID(shooter);
					PyObject* pArgs = Py_BuildValue("(iii)", id, o, killer);
					PyObject* result = PyObject_CallObject(pFunc, pArgs);
					if ( result == NULL)
					{
						Py_XDECREF(result);
						printf("\nError occured while trying to call %s::Killed(). Bad arguments?\n", s->name);
						PyErr_Clear();
					}
					Py_XDECREF(result);
					break;
				}
				break;
			}
		}
	}
}

void ScriptManager::PythonScript::Damaged(GameObject *obj,GameObject *damager,float damage)
{
	for(int script_it = 0; script_it < 256; script_it++)
	{
		Script *s = Scripts[script_it];
		if(!s)
		{
			continue;
		}
		if(strcmp(s->name, this->Get_Name()) == 0)
		{
			if (PyObject_HasAttrString(s->classobject, "Damaged"))
			{
				PyObject* pFunc = PyObject_GetAttrString(s->classobject, "Damaged");
				if (pFunc && PyCallable_Check(pFunc))
				{
					int id = GetID();
					int o = Helper::Get_ID(obj);
					int shooter = Helper::Get_ID(damager);
					PyObject* pArgs = Py_BuildValue("(iiif)", id, o, shooter, damage);
					PyObject* result = PyObject_CallObject(pFunc, pArgs);
					if ( result == NULL)
					{
						Py_XDECREF(result);
						printf("\nError occured while trying to call %s::Damaged(). Bad arguments?\n", s->name);
						PyErr_Clear();
					}
					Py_XDECREF(result);
					break;
				}
				break;
			}
		}
	}
}

void ScriptManager::PythonScript::Custom(GameObject *obj,int message,int param,GameObject *sender)
{
	for(int script_it = 0; script_it < 256; script_it++)
	{
		Script *s = Scripts[script_it];
		if(!s)
		{
			continue;
		}
		if(strcmp(s->name, this->Get_Name()) == 0)
		{
			if (PyObject_HasAttrString(s->classobject, "Custom"))
			{
				PyObject* pFunc = PyObject_GetAttrString(s->classobject, "Custom");
				if (pFunc && PyCallable_Check(pFunc))
				{
					int id = GetID();
					int o = Helper::Get_ID(obj);
					int sendid = Helper::Get_ID(sender);
					PyObject* pArgs = Py_BuildValue("(iiiii)", id, o, message, param, sendid);
					PyObject* result = PyObject_CallObject(pFunc, pArgs);
					if ( result == NULL)
					{
						Py_XDECREF(result);
						printf("\nError occured while trying to call %s::Damaged(). Bad arguments?\n", s->name);
						PyErr_Clear();
					}
					Py_XDECREF(result);
					break;
				}
				break;
			}
		}
	}
}

void ScriptManager::PythonScript::Enemy_Seen(GameObject *obj,GameObject *seen)
{
	for(int script_it = 0; script_it < 256; script_it++)
	{
		Script *s = Scripts[script_it];
		if(!s)
		{
			continue;
		}
		if(strcmp(s->name, this->Get_Name()) == 0)
		{
			if (PyObject_HasAttrString(s->classobject, "Enemy_Seen"))
			{
				PyObject* pFunc = PyObject_GetAttrString(s->classobject, "Enemy_Seen");
				if (pFunc && PyCallable_Check(pFunc))
				{
					int id = GetID();
					int o = Helper::Get_ID(obj);
					int seenid = Helper::Get_ID(seen);
					PyObject* pArgs = Py_BuildValue("(iii)", id, o, seenid);
					PyObject* result = PyObject_CallObject(pFunc, pArgs);
					if ( result == NULL)
					{
						Py_XDECREF(result);
						printf("\nError occured while trying to call %s::Enemy_Seen(). Bad arguments?\n", s->name);
						PyErr_Clear();
					}
					Py_XDECREF(result);
					break;
				}
				break;
			}
		}
	}
}

void ScriptManager::PythonScript::Action_Complete(GameObject *obj,int action,ActionCompleteReason reason)
{
	for(int script_it = 0; script_it < 256; script_it++)
	{
		Script *s = Scripts[script_it];
		if(!s)
		{
			continue;
		}
		if(strcmp(s->name, this->Get_Name()) == 0)
		{
			if (PyObject_HasAttrString(s->classobject, "Action_Complete"))
			{
				PyObject* pFunc = PyObject_GetAttrString(s->classobject, "Action_Complete");
				if (pFunc && PyCallable_Check(pFunc))
				{
					int id = GetID();
					int o = Helper::Get_ID(obj);
					PyObject* pArgs = Py_BuildValue("(iii)", id, o, action);
					PyObject* result = PyObject_CallObject(pFunc, pArgs);
					if ( result == NULL)
					{
						Py_XDECREF(result);
						printf("\nError occured while trying to call %s::Action_Complete(). Bad arguments?\n", s->name);
						PyErr_Clear();
					}
					Py_XDECREF(result);
					break;
				}
				break;
			}
		}
	}
}

void ScriptManager::PythonScript::Timer_Expired(GameObject *obj,int number)
{
	for(int script_it = 0; script_it < 256; script_it++)
	{
		Script *s = Scripts[script_it];
		if(!s)
		{
			continue;
		}
		if(strcmp(s->name, this->Get_Name()) == 0)
		{
			if (PyObject_HasAttrString(s->classobject, "Timer_Expired"))
			{
				PyObject* pFunc = PyObject_GetAttrString(s->classobject, "Timer_Expired");
				if (pFunc && PyCallable_Check(pFunc))
				{
					int id = GetID();
					int o = Helper::Get_ID(obj);
					PyObject* pArgs = Py_BuildValue("(iii)", id, o, number);
					PyObject* result = PyObject_CallObject(pFunc, pArgs);
					if ( result == NULL)
					{
						Py_XDECREF(result);
						printf("\nError occured while trying to call %s::Timer_Expired(). Bad arguments?\n", s->name);
						PyErr_Clear();
					}
					Py_XDECREF(result);
					break;
				}
				break;
			}
		}
	}
}

void ScriptManager::PythonScript::Animation_Complete(GameObject *obj,const char *anim)
{
	for(int script_it = 0; script_it < 256; script_it++)
	{
		Script *s = Scripts[script_it];
		if(!s)
		{
			continue;
		}
		if(strcmp(s->name, this->Get_Name()) == 0)
		{
			if (PyObject_HasAttrString(s->classobject, "Animation_Complete"))
			{
				PyObject* pFunc = PyObject_GetAttrString(s->classobject, "Animation_Complete");
				if (pFunc && PyCallable_Check(pFunc))
				{
					int id = GetID();
					int o = Helper::Get_ID(obj);
					PyObject* pArgs = Py_BuildValue("(iis)", id, o, anim);
					PyObject* result = PyObject_CallObject(pFunc, pArgs);
					if ( result == NULL)
					{
						Py_XDECREF(result);
						printf("\nError occured while trying to call %s::Animation_Complete(). Bad arguments?\n", s->name);
						PyErr_Clear();
					}
					Py_XDECREF(result);
					break;
				}
				break;
			}
		}
	}
}

void ScriptManager::PythonScript::Poked(GameObject *obj,GameObject *poker)
{
	for(int script_it = 0; script_it < 256; script_it++)
	{
		Script *s = Scripts[script_it];
		if(!s)
		{
			continue;
		}
		if(strcmp(s->name, this->Get_Name()) == 0)
		{
			if (PyObject_HasAttrString(s->classobject, "Poked"))
			{
				PyObject* pFunc = PyObject_GetAttrString(s->classobject, "Poked");
				if (pFunc && PyCallable_Check(pFunc))
				{
					int id = GetID();
					int o = Helper::Get_ID(obj);
					int pokerid = Helper::Get_ID(poker);
					PyObject* pArgs = Py_BuildValue("(iii)", id, o, pokerid);
					PyObject* result = PyObject_CallObject(pFunc, pArgs);
					if ( result == NULL)
					{
						Py_XDECREF(result);
						printf("\nError occured while trying to call %s::Poked(). Bad arguments?\n", s->name);
						PyErr_Clear();
					}
					Py_XDECREF(result);
					break;
				}
				break;
			}
		}
	}
}

void ScriptManager::PythonScript::Entered(GameObject *obj,GameObject *enter)
{
	for(int script_it = 0; script_it < 256; script_it++)
	{
		Script *s = Scripts[script_it];
		if(!s)
		{
			continue;
		}
		if(strcmp(s->name, this->Get_Name()) == 0)
		{
			if (PyObject_HasAttrString(s->classobject, "Entered"))
			{
				PyObject* pFunc = PyObject_GetAttrString(s->classobject, "Entered");
				if (pFunc && PyCallable_Check(pFunc))
				{
					int id = GetID();
					int o = Helper::Get_ID(obj);
					int enterid = Helper::Get_ID(enter);
					PyObject* pArgs = Py_BuildValue("(iii)", id, o, enterid);
					PyObject* result = PyObject_CallObject(pFunc, pArgs);
					if ( result == NULL)
					{
						Py_XDECREF(result);
						printf("\nError occured while trying to call %s::Entered(). Bad arguments?\n", s->name);
						PyErr_Clear();
					}
					Py_XDECREF(result);
					break;
				}
				break;
			}
		}
	}
}

void ScriptManager::PythonScript::Exited(GameObject *obj,GameObject *exit)
{
	for(int script_it = 0; script_it < 256; script_it++)
	{
		Script *s = Scripts[script_it];
		if(!s)
		{
			continue;
		}
		if(strcmp(s->name, this->Get_Name()) == 0)
		{
			if (PyObject_HasAttrString(s->classobject, "Exited"))
			{
				PyObject* pFunc = PyObject_GetAttrString(s->classobject, "Exited");
				if (pFunc && PyCallable_Check(pFunc))
				{
					int id = GetID();
					int o = Helper::Get_ID(obj);
					int exitid = Helper::Get_ID(exit);
					PyObject* pArgs = Py_BuildValue("(iii)", id, o, exitid);
					PyObject* result = PyObject_CallObject(pFunc, pArgs);
					if ( result == NULL)
					{
						Py_XDECREF(result);
						printf("\nError occured while trying to call %s::Exited(). Bad arguments?\n", s->name);
						PyErr_Clear();
					}
					Py_XDECREF(result);
					break;
				}
				break;
			}
		}
	}
}