#include "ScriptManager.h"
#include "../../object/Model/ModelMaker.h"
#include "../../object/Indicator.h"
#include "../../object/PrintBoard.h"
#include "../../object/ShowBoard.h"
#include "../../object/VerticalMenu.h"
#include "../../object/TestFade.h"

class RenderResourceMaker {
public:
	static RenderResource* makeCubeQueue(RenderManager* _pRenderManager, TiXmlElement* _pRenderElement){
		RenderResource* pRenderResource = new RenderResource;
		const char *pTextureName = _pRenderElement->Attribute("texture");
		int scale; _pRenderElement->Attribute("scale", &scale);
		Model* pModel = new Model;
		ModelMaker::createCubeModel(_pRenderManager->getD3DDevice(), pModel, pTextureName, scale);
		pRenderResource->pModel = pModel;
		
		//_refRenderManager.pCurrentSortedModelObjectQueue->push_back(pRenderResource); //M5
		//m6
		int num; _pRenderElement->Attribute("num", &num);
		_pRenderManager->textureOnlyPolygonIndex.push_back(num);
		//
		return pRenderResource;
	}
	static RenderResource* makeSpriteQueue(RenderManager* _pRenderManager, TiXmlElement* _pRenderElement){
		RenderResource* pRenderResource = new RenderResource;
		const char *pTextureName = _pRenderElement->Attribute("texture");
		int w, h;
		_pRenderElement->Attribute("w", &w);
		_pRenderElement->Attribute("h", &h);
		Model* pModel = new Model;
		D3DXIMAGE_INFO d3dxImageInfo;
		D3DXCreateTextureFromFileEx( _pRenderManager->getD3DDevice(), pTextureName,
			w, // 텍스쳐의 가로좌표를 직접 설정
			h, // 텍스쳐의 세로좌표를 직접 설정
			1,   // 스프라이트 경우에는 밉맵을 만들지 않는다.
			D3DPOOL_DEFAULT,D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, D3DX_DEFAULT,D3DX_DEFAULT,
			D3DCOLOR_COLORVALUE(1.0f,0.0f,1.0f,1.0f), //color key
			//만일 컬러키를 무효화하고 싶다면 0으로 세팅한다.
			//알파블렌드를 활성화하면 알파값은 자동으로 뚫린다.
			&d3dxImageInfo, NULL, &pModel->pTexture);
		pRenderResource->pModel = pModel;
		
		//_refRenderManager.pCurrentSortedSpriteObjectQueue->push_back(pRenderResource); //M5

		//m6
		int num; _pRenderElement->Attribute("num", &num);
		_pRenderManager->spriteIndex.push_back(num);
		//

		return pRenderResource;
	}	
};
class ManagerCommand {
public:
	static void cmdShowAll(ScriptManager* _pScriptManager){
		vector<Actor*>::iterator itrActor_;
		for(itrActor_  = _pScriptManager->pActionManager_->pCurrentActorPocket->begin();
			itrActor_ != _pScriptManager->pActionManager_->pCurrentActorPocket->end(); itrActor_++){
			(*itrActor_)->bShow = true;
		}
	}

	static void cmdFadeOut(ScriptManager* _pScriptManager){
		_pScriptManager->pControlTable_->bFade = true;
		_pScriptManager->pControlTable_->fadeType = ControlTable::FADE_OUT;
		double dt;
		_pScriptManager->pControlTable_->pCommandElement->Attribute("dt", &dt);
		_pScriptManager->pRenderManager_->aFadeTime.dt = dt;
		_pScriptManager->pControlTable_->runMode = ControlTable::PROCESS;
	}

	static void cmdFadeIn(ScriptManager* _pScriptManager){
		_pScriptManager->pControlTable_->bFade = true;
		_pScriptManager->pControlTable_->fadeType = ControlTable::FADE_IN;
		double dt;
		_pScriptManager->pControlTable_->pCommandElement->Attribute("dt", &dt);
		_pScriptManager->pRenderManager_->aFadeTime.dt = dt;
		_pScriptManager->pControlTable_->runMode = ControlTable::PROCESS;
	}

	static void cmdProcess(ScriptManager* _pScriptManager){
		_pScriptManager->bScriptWait_ = true;
		double dt;
		_pScriptManager->pControlTable_->pCommandElement->Attribute("dt", &dt);
		//refoctor me
		_pScriptManager->aScriptProcessTime_.dt = dt;
		_pScriptManager->pControlTable_->runMode = ControlTable::PROCESS;
	}

};

// 스크립트 메니져 파일
ScriptManager::ScriptManager() : bScriptWait_(false) {

	//actor
	makeActor_["indicator"  ] = Indicator::makeIndicator;
	makeActor_["print_board"] = PrintBoard::makePrintBoard;
	makeActor_["show_board" ] = ShowBoard::makeShowBoard;
	makeActor_["test_Fade"  ] = TestFade::makeTestFade;
	//special actor : toolkit
	makeToolKit_["v_menu_list"] = VerticalMenu::makeVetricalMenu;
	
	//render resource
	makeRenderResource_["cube"  ] = RenderResourceMaker::makeCubeQueue;
	makeRenderResource_["sprite"] = RenderResourceMaker::makeSpriteQueue;

	actorCommand_["show"  ] = Actor::cmdShow;
	actorCommand_["focus" ] = Actor::cmdFocus;
	actorCommand_["rotate"] = Indicator::cmdRotate;
	actorCommand_["print" ] = PrintBoard::cmdPrint;

	managerCommand_["show_all"] = ManagerCommand::cmdShowAll;
	managerCommand_["fade_out"] = ManagerCommand::cmdFadeOut;
	managerCommand_["fade_in" ] = ManagerCommand::cmdFadeIn;
	managerCommand_["process" ] = ManagerCommand::cmdProcess;
}

void ScriptManager::initManager(ActionManager* _pActionManager, RenderManager* _pRenderManager){
	pActionManager_ = _pActionManager;
	pRenderManager_ = _pRenderManager;
	pControlTable_ = &(_pActionManager->aControlTable);
}

void ScriptManager::putActorPocket_(TiXmlElement* _pActorElement){
	int render;
	Actor* pActor;
	while(_pActorElement){
		key_ = _pActorElement->Attribute("type");
		if(_pActorElement->Attribute("render", &render)){
			if(!makeActor_[key_]){
				MessageBox(NULL, "Error in XML (Actor Node)", "Error Message", MB_OK | MB_ICONERROR);
				exit(1);
			}
			pActor = makeActor_[key_](_pActorElement);
			pActor->setRObject(&(pActionManager_->aDevicePocket), pControlTable_);
			(*(pRenderManager_->pCurrentRenderPocket))[render]->actorPocket.push_back(pActor);
		}else{
			//make ToolKit, having Actor, not "render" resource
			if(!makeToolKit_[key_]){
				MessageBox(NULL, "Error in XML (Actor Node)", "Error Message", MB_OK | MB_ICONERROR);
				exit(1);
			}
			pActor = makeToolKit_[key_](pActionManager_->pCurrentActorPocket, _pActorElement);
			pActor->setRObject(&(pActionManager_->aDevicePocket), pControlTable_);
		}
		pActionManager_->pCurrentActorPocket->push_back(pActor);
		_pActorElement = _pActorElement->NextSiblingElement("list");
	}
}
void ScriptManager::putRenderPocket_(TiXmlElement* _pRenderElement){
	while(_pRenderElement){
		key_ = _pRenderElement->Attribute("type");
		if(!makeRenderResource_[key_]){
			MessageBox(NULL, "Error in Render XML (Render Node)", "Error Message", MB_OK | MB_ICONERROR);
			exit(1);
		}
		RenderResource* pRenderResource = makeRenderResource_[key_](pRenderManager_, _pRenderElement);
		pRenderManager_->pCurrentRenderPocket->push_back(pRenderResource);
		_pRenderElement = _pRenderElement->NextSiblingElement("list");
	}
}

void ScriptManager::controlScript(){ //< command element와 control element 를 통한 script control fuction
	bool bEnd = true;
	while(pControlTable_->pCommandElement){
		key_ = pControlTable_->pCommandElement->Attribute("oper");
		int robject;
		if(pControlTable_->pCommandElement->Attribute("robject", &robject)){
			if(!actorCommand_[key_]){
				MessageBox(NULL, "Error in Render XML (Command Node)", "Error Message", MB_OK | MB_ICONERROR);
				exit(1);
			}
			actorCommand_[key_]( (*(pActionManager_->pCurrentActorPocket))[robject] );
		}else{
			if(!managerCommand_[key_]){
				MessageBox(NULL, "Error in Render XML (Command Node)", "Error Message", MB_OK | MB_ICONERROR);
				exit(1);
			}
			managerCommand_[key_](this);
		}
		pControlTable_->pCommandElement = pControlTable_->pCommandElement->NextSiblingElement("command");
		if(pControlTable_->runMode == ControlTable::PROCESS){
			bEnd = false;
			break;
		}
	}
	if(bEnd){loadControlElement_(pControlTable_->pControlElement);}
}

void ScriptManager::loadXmlFile_(const char* _fileName){
	if ( !xmlDoc_.LoadFile(_fileName) ){
		const char* errorMsg = xmlDoc_.ErrorDesc();
		MessageBox(NULL, errorMsg, "Error Message", MB_OK | MB_ICONERROR);
		exit( 1 );
	}
	loadScene_(0);
}

void ScriptManager::loadScene_(int _sceneNum){	
	pActionManager_->setCurrentActorPocket(ActionManager::PRIMARY);
	pActionManager_->clearCurrentActorPocket();
	pRenderManager_->setCurrentRenderPocket(RenderManager::PRIMARY);
	pRenderManager_->clearCurrentRenderPocket();
	pRenderManager_->clearSortedRenderPocket();

	TiXmlHandle docHandle( &xmlDoc_ );
	pControlTable_->aSceneHandle = docHandle.FirstChild("stage").Child( "scene", _sceneNum );
	TiXmlElement* pRenderElement = pControlTable_->aSceneHandle.FirstChild("Render").FirstChild("list").Element();
	assert(pRenderElement->Attribute("type"));
	putRenderPocket_(pRenderElement);

	TiXmlElement* pRObjectElement = pControlTable_->aSceneHandle.FirstChild("actor").FirstChild("list").Element();
	assert(pRObjectElement);
	putActorPocket_(pRObjectElement);
	pRenderManager_->sortRenderPocket();

	TiXmlElement* pControlElement = pControlTable_->aSceneHandle.FirstChild("control").Element();
	loadControlElement_(pControlElement);
}

void ScriptManager::loadControlElement_(TiXmlElement* _pControlElement){
	const char *strControl = _pControlElement->Attribute("mode");
	if(!strControl){
		MessageBox(NULL, "Error in Render XML (Control Node)", "Error Message", MB_OK | MB_ICONERROR);
		exit(1);
	}
	if(strcmp("process", strControl) == 0){
		pControlTable_->runMode = ControlTable::PROCESS;
	}else if(strcmp("script", strControl) == 0){
		int index; _pControlElement->Attribute("index", &index);
		TiXmlElement* pScriptElement = pControlTable_->aSceneHandle.FirstChild("script").Child("list", index).Element();
		assert(pScriptElement->Attribute("mode"));
		loadScript_(pScriptElement);
	}
}

void ScriptManager::loadScript_(TiXmlElement* _pScriptElement){
	//command
	if(strcmp("command", _pScriptElement->Attribute("mode")) == 0){
		pControlTable_->pControlElement = _pScriptElement->FirstChildElement("control");
		pControlTable_->setCommand(_pScriptElement->FirstChildElement("command"));
		controlScript(); //load command and load control element
	//load
	}else if(strcmp("load", _pScriptElement->Attribute("mode")) == 0){
		//robject
		if(strcmp("robject", _pScriptElement->Attribute("type")) == 0){
			pControlTable_->pControlElement = _pScriptElement->FirstChildElement("control");
			TiXmlElement* pRenderElement = _pScriptElement->FirstChildElement("Render");
			assert(pRenderElement->Attribute("type"));
			putRenderPocket_(pRenderElement);
			TiXmlElement* pRObjectElement = _pScriptElement->FirstChildElement("actor");
			assert(pRObjectElement->Attribute("type"));
			putActorPocket_(pRObjectElement);
			loadControlElement_(pControlTable_->pControlElement);
		//scene
		}else if(strcmp("scene", _pScriptElement->Attribute("type")) == 0){			
			int sceneIndex;
			_pScriptElement->Attribute("index" ,&sceneIndex);
			loadScene_(sceneIndex);
		//xml file
		}else if(strcmp("xml", _pScriptElement->Attribute("type")) == 0){
			loadXmlFile_(_pScriptElement->Attribute("file"));
		}
	}
}

void ScriptManager::process(){
	if(bScriptWait_){
		pControlTable_->aTimeController.applyElpasedTime(aScriptProcessTime_.rt);
		if(aScriptProcessTime_.rt > aScriptProcessTime_.dt){
			pControlTable_->runMode = ControlTable::SCRIPT;
			bScriptWait_ = false;
			aScriptProcessTime_.rt = 0;
		}
	}
}
