#include "BattleSystem.h"
#include "mof/KeyFrameAnimation.h"
#include "mof/ConsoleIO.h"
#include <sstream>
#include <iomanip>
#include "mof/GraphicsDevice.h"
#include "MyFrame.h"
#include "mof/System.h"
#include "BattlerBindAnimation.h"
#include "AttackAction.h"
#include "BattlerGroup.h"
#include "mof/DataBasedAnimation.h"




mof::GraphicsSchedule* createNumbersEffect(int numbers , mof::Vector2D& position);
mof::GraphicsSchedule* createAPEffect(int dActionPoint , mof::Vector2D& position);
mof::GraphicsSchedule* createMessage(const mof::tstring& message , mof::TextureManager* pTextureManager);
mof::GraphicsSchedule* createChanceDisplay(int beginFrame , int endFrame  , et::BattleData* pBattleData);




bool compareTo( et::BattlerFacade* &a ,   et::BattlerFacade* &b){
		return (*a).getParameter().speed < (*b).getParameter().speed;
	}


et::BattleSystem::BattleSystem(et::BattleData* pBattleData , mof::AnimationScheduler* pScheduler , et::Common& common)
: m_common(common){
	m_pBattleData = pBattleData;
	m_pScheduler = pScheduler;
	m_pChanceScheduler = NULL;

	m_finalized = false;
	m_state = et::BattleSystem::READY;
	m_pAction = NULL;
	m_succeeded = false;
	
	//バトラーを速度の昇順にソートして格納
	m_battlerQueue = m_pBattleData->getBattlerGroup()->getEnemyBattlerListAlive();
	m_battlerQueue.push_back(m_pBattleData->getBattlerGroup()->getHeroBattler());
	std::sort(m_battlerQueue.begin() , m_battlerQueue.end() , compareTo);
}

et::BattleSystem::~BattleSystem(){
	for(std::list<mof::GraphicsSchedule*>::iterator itr = m_scheduleList.begin() ; itr != m_scheduleList.end() ; ){
		delete *itr;
		itr = m_scheduleList.erase(itr);
	}
	delete m_pAction;
}





void et::BattleSystem::update(){

	/*{
		
		switch(m_state){
			case MAIN: DEBUG_PRINT("MAIN");
				break;
			case EXECUTE: DEBUG_PRINT("EXECUTE");
				break;
			case HIT: DEBUG_PRINT("HIT");
				break;
			default: DEBUG_PRINT("OTHER");
		}
	}*/
	

	bool flag = false;
	for(std::list<mof::GraphicsSchedule*>::iterator itr = m_scheduleList.begin() ; itr != m_scheduleList.end() ; ){
		(*itr)->update();
		if((*itr)->isFinalized()){
			if(m_state == SECESSION || m_state == FINAL){//エフェクトは途中で終わらない
				delete *itr;
				itr = m_scheduleList.erase(itr);
				continue;
			}
		}
		else flag = true;
		++itr;
	}
	if(flag)return;

	
	if(m_state != HIT){
		
		if(!m_pScheduler->isFinalized())return;
	}
	if(m_pScheduler->isFinalized())m_pScheduler->clear();

	
	
	BattlerGroup* pGroup = m_pBattleData->getBattlerGroup();

	if(m_state == et::BattleSystem::READY){
		//次のアクションを得る
		if(m_battlerQueue.empty())assert(0);
		et::BattlerFacade* pBattler = m_battlerQueue.back();
		m_pAction = pBattler->createAction(pGroup);
		if(m_pAction == NULL){
			//何もしない
			m_state = et::BattleSystem::SECESSION;
			return;
		}

		//ターゲットは生存しているかをチェック
		if(m_pAction->getTargetList().size() == 1 && !m_pAction->getTargetList().front()->getParameter().alive){
			if(pBattler->getType() == et::HERO){
				//生存していなければ、次のモンスターを選ぶ
				et::BattlerFacade* pNextTarget = NULL;
				for(std::vector<et::BattlerFacade*>::const_iterator itr = pGroup->getEnemyBattlerList().begin() ; itr != pGroup->getEnemyBattlerList().end() ; ++itr){
					if((*itr)->getParameter().alive){
						pNextTarget = *itr;
						break;
					}
				}
				if(pNextTarget == NULL){
					//生存しているモンスターがいなかった
					m_state = et::BattleSystem::SECESSION;
					return;
				}
				else {
					//ターゲットを更新
					std::vector<et::BattlerFacade*> targetList;
					targetList.push_back(pNextTarget);
					m_pAction->setTargetList(targetList);
				}
			}
			else {//味方は１人しかいないので
				m_state = et::BattleSystem::SECESSION;
				return;
			}
		}
		

		m_pScheduler->add(10 , m_pAction->createApproachAnimation());
		mof::tstring message = m_pAction->getActionMessage();
		if(message.length() > 0)m_scheduleList.push_back(createMessage(message  , m_pBattleData->getTextureManager()));
		//スペシャルアクションの生成
		if((rand()%100 < 20) && m_pAction->isDirectAttack()){
			m_pChanceScheduler = createChanceDisplay(10 , 30 , m_pBattleData);
			m_scheduleList.push_back(m_pChanceScheduler);
			m_succeeded = false;
		}
		m_state = et::BattleSystem::EXECUTE;
	}
	else if(m_state == et::BattleSystem::EXECUTE){
		et::BattlerFacade* pBattler = m_battlerQueue.back();
		if(!m_succeeded){
			m_pScheduler->add(0 , m_pAction->createExecuteAnimation());
			//std::vector<int> resultList = m_pAction->doAction();
			/*int index = 0;
			for(std::vector<BattlerFacade*>::iterator itr = m_pAction->getTargetList().begin() ; itr != m_pAction->getTargetList().end() ; ++itr){
				//エフェクト
				mof::Vector2D position = mof::GraphicsDevice::getInstance()->to2DPosition((*itr)->getPosition());
				m_scheduleList.push_back(createNumbersEffect(resultList.at(index) , position));
				index++;
			}*/
			m_scheduleList.push_back(m_pAction->createEffect(m_common));
			
			/*index = 0;
			for(std::vector<BattlerFacade*>::iterator itr = m_pAction->getTargetList().begin() ; itr != m_pAction->getTargetList().end() ; ++itr){
				if(resultList.at(index) > 0)continue;
				int level = ((*itr)->getParameter().alive) ? 0 : 1;
				m_pScheduler->add(20 , (*itr)->setDamagedAnimation(level));
			}*/
		}
		else if(pBattler == pGroup->getHeroBattler()){
			//クリティカル成功！
			m_pScheduler->add(0 , m_pAction->createExecuteAnimation());
			m_scheduleList.push_back(m_pAction->createEffect(m_common));
			m_scheduleList.push_back( createMessage(_T("クリティカル") , m_pBattleData->getTextureManager()));
		}
		else {
			//カウンター成功！
			//相手の攻撃キャンセル　ノーコストで攻撃できる
			m_battlerQueue.pop_back();//攻撃キャンセル
			et::BattlerFacade* pTarget = m_pAction->getTargetList().front();
			m_battlerQueue.push_back(pTarget);
			//APだけ消費させる
			et::BattlerParameter parameter = pBattler->getParameter();
			parameter.dActionPoint -= m_pAction->getAPCost();
			pBattler->setParameter(parameter);
			delete m_pAction;
			
			m_pAction = new et::AttackAction(pTarget , pBattler , 0);//ノーコストで攻撃
			m_pScheduler->add(0 , m_pAction->createExecuteAnimation());
			m_scheduleList.push_back(m_pAction->createEffect(m_common));
			/*std::vector<int> resultList = m_pAction->doAction();
			int index = 0;
			for(std::vector<BattlerFacade*>::iterator itr = m_pAction->getTargetList().begin() ; itr != m_pAction->getTargetList().end() ; ++itr){
				//エフェクト
				mof::Vector2D position = mof::GraphicsDevice::getInstance()->to2DPosition((*itr)->getPosition());
				m_scheduleList.push_back(createNumbersEffect(resultList.at(index) , position));
				index++;
			}
			
			index = 0;
			for(std::vector<BattlerFacade*>::iterator itr = m_pAction->getTargetList().begin() ; itr != m_pAction->getTargetList().end() ; ++itr){
				if(resultList.at(index) > 0)continue;
				int level = ((*itr)->getParameter().alive) ? 0 : 1;
				m_pScheduler->add(20 , (*itr)->setDamagedAnimation(level));
			}*/

			m_scheduleList.push_back( createMessage(_T("カウンター") , m_pBattleData->getTextureManager()));
			
			
		}
		m_state = et::BattleSystem::HIT;
	}
	else if(m_state == et::BattleSystem::HIT){
		et::BattlerFacade* pBattler = m_battlerQueue.back();
		if(!m_succeeded){
			//m_pScheduler->add(0 , m_pAction->createExecuteAnimation());
			std::vector<int> resultList = m_pAction->doAction();
			int index = 0;
			for(std::vector<BattlerFacade*>::iterator itr = m_pAction->getTargetList().begin() ; itr != m_pAction->getTargetList().end() ; ++itr){
				//エフェクト
				mof::Vector2D position = mof::GraphicsDevice::getInstance()->to2DPosition((*itr)->getPosition());
				m_scheduleList.push_back(createNumbersEffect(resultList.at(index) , position));
				index++;
			}
			//m_scheduleList.push_back(m_pAction->createEffect(m_common));
			
			index = 0;
			for(std::vector<BattlerFacade*>::iterator itr = m_pAction->getTargetList().begin() ; itr != m_pAction->getTargetList().end() ; ++itr){
				if(resultList.at(index) > 0)continue;
				int level = ((*itr)->getParameter().alive) ? 0 : 1;
				m_pScheduler->add(0 , (*itr)->setDamagedAnimation(level));
			}
		}
		else if(pBattler == pGroup->getHeroBattler()){
			//クリティカル成功！
			//相手の防御力無視　相手のAPを0にする

			//一時的にクリティカル状態にする
			et::BattlerParameter parameter = pBattler->getParameter();
			parameter.critical = true;
			pBattler->setParameter(parameter);
			//m_pScheduler->add(0 , m_pAction->createExecuteAnimation());
			std::vector<int> resultList = m_pAction->doAction();
			int index = 0;
			for(std::vector<BattlerFacade*>::iterator itr = m_pAction->getTargetList().begin() ; itr != m_pAction->getTargetList().end() ; ++itr){
				//エフェクト
				mof::Vector2D position = mof::GraphicsDevice::getInstance()->to2DPosition((*itr)->getPosition());
				m_scheduleList.push_back(createNumbersEffect(resultList.at(index) , position));
				index++;
			}
			
			index = 0;
			for(std::vector<BattlerFacade*>::iterator itr = m_pAction->getTargetList().begin() ; itr != m_pAction->getTargetList().end() ; ++itr){
				if(resultList.at(index) > 0)continue;
				int level = ((*itr)->getParameter().alive) ? 0 : 1;
				m_pScheduler->add(20 , (*itr)->setDamagedAnimation(level));
			}

			//クリティカル状態をなおす
			parameter = pBattler->getParameter();
			parameter.critical = false;
			pBattler->setParameter(parameter);

			//ターゲットのdAPを十分に減らす
			parameter = m_pAction->getTargetList().front()->getParameter();
			parameter.dActionPoint -= 100;
			m_pAction->getTargetList().front()->setParameter(parameter);
			m_succeeded = false;
			//m_scheduleList.push_back( createMessage(_T("クリティカル") , m_pBattleData->getTextureManager()));
		}
		else {
			//カウンター成功！
			//相手の攻撃キャンセル　ノーコストで攻撃できる
			/*m_battlerQueue.pop_back();//攻撃キャンセル
			et::BattlerFacade* pTarget = m_pAction->getTargetList().front();
			m_battlerQueue.push_back(pTarget);
			//APだけ消費させる
			et::BattlerParameter parameter = pBattler->getParameter();
			parameter.dActionPoint -= m_pAction->getAPCost();
			pBattler->setParameter(parameter);
			delete m_pAction;
			m_pAction = new et::AttackAction(pTarget , pBattler , 0);//ノーコストで攻撃
			m_pScheduler->add(0 , m_pAction->createExecuteAnimation());*/
			
			
			std::vector<int> resultList = m_pAction->doAction();
			int index = 0;
			for(std::vector<BattlerFacade*>::iterator itr = m_pAction->getTargetList().begin() ; itr != m_pAction->getTargetList().end() ; ++itr){
				//エフェクト
				mof::Vector2D position = mof::GraphicsDevice::getInstance()->to2DPosition((*itr)->getPosition());
				m_scheduleList.push_back(createNumbersEffect(resultList.at(index) , position));
				index++;
			}
			
			index = 0;
			for(std::vector<BattlerFacade*>::iterator itr = m_pAction->getTargetList().begin() ; itr != m_pAction->getTargetList().end() ; ++itr){
				if(resultList.at(index) > 0)continue;
				int level = ((*itr)->getParameter().alive) ? 0 : 1;
				m_pScheduler->add(20 , (*itr)->setDamagedAnimation(level));
			}

			//m_scheduleList.push_back( createMessage(_T("カウンター") , m_pBattleData->getTextureManager()));
			m_succeeded = false;
			
		}
		m_state = et::BattleSystem::MAIN;
	}
	else if(m_state == et::BattleSystem::MAIN ){
		et::BattlerFacade* pBattler = m_battlerQueue.back();
		m_pScheduler->add(0 , pBattler->setMovingAnimation(pBattler->getBasePosition() , 15));
		for(std::vector<BattlerFacade*>::iterator itr = m_pAction->getTargetList().begin() ; itr != m_pAction->getTargetList().end() ; ++itr){
			if(pBattler == (*itr) )continue;
			if((*itr)->getPosition() == (*itr)->getBasePosition())(*itr)->setAidlingAnimation((*itr)->getPosition());
			else if((*itr)->getParameter().alive)(*itr)->setMovingAnimation((*itr)->getBasePosition() , 15);
		}
		m_state = et::BattleSystem::SECESSION;
	}
	else if(m_state == et::BattleSystem::SECESSION){
		m_state = et::BattleSystem::READY;
		et::BattlerFacade* pBattler = m_battlerQueue.back();
		pBattler->setAidlingAnimation(pBattler->getBasePosition() );
		if(m_pAction != NULL && m_pAction->getTargetList().size() == 1){
			//カウンターされて戻ってきたバトラーをアイドリングにする
			m_pAction->getTargetList().front()->setAidlingAnimation(m_pAction->getTargetList().front()->getPosition());
		}
		m_battlerQueue.pop_back();
		while(!m_battlerQueue.empty() && !m_battlerQueue.back()->getParameter().alive)m_battlerQueue.pop_back();
		delete m_pAction;
		m_pAction = NULL;
		if(m_battlerQueue.empty()){
			for(std::vector<et::BattlerFacade*>::const_iterator itr = pGroup->getBattlerList().begin() ; itr != pGroup->getBattlerList().end() ; ++itr){
				if(!(*itr)->getParameter().alive)continue;
				et::BattlerParameter parameter = (*itr)->getParameter();
				int dActionPoint = parameter.dActionPoint + 2;
				int tmpActionPoint = parameter.actionPoint;
				parameter.actionPoint += dActionPoint;
				if(parameter.actionPoint > 7)parameter.actionPoint = 7;
				else if(parameter.actionPoint < 0)parameter.actionPoint = 0;
				parameter.dActionPoint = 0;
				(*itr)->setParameter(parameter);
				mof::Vector2D position = mof::GraphicsDevice::getInstance()->to2DPosition((*itr)->getPosition());
				m_scheduleList.push_back(createAPEffect(parameter.actionPoint - tmpActionPoint , position));
			}
			m_state = et::BattleSystem::FINAL;
		}
	}
	else if(m_state == et::BattleSystem::FINAL && m_scheduleList.empty()){
		m_finalized = true;
	}
	
}

bool et::BattleSystem::isFinalized(){
	return m_finalized;
}



void et::BattleSystem::notifyPushKey(){
	if(m_pChanceScheduler == NULL)return;
	for(std::list<mof::GraphicsSchedule*>::iterator itr = m_scheduleList.begin() ; itr != m_scheduleList.end() ; ++itr){
		if((*itr) == m_pChanceScheduler){
			if((*itr)->isFinalized() || !(*itr)->isPlaying())return;
			m_succeeded = true;
			return;
		}
		
	}
	//既に削除されている
	m_pChanceScheduler = NULL;

}


std::list<mof::GraphicsModelPtr>& et::BattleSystem::getModelList( std::list<mof::GraphicsModelPtr>& modelList){
	for(std::list<mof::GraphicsSchedule*>::iterator itr = m_scheduleList.begin() ; itr != m_scheduleList.end();  ++itr){
		(*itr)->appendModelList(modelList);
	}
	return modelList;
}


mof::GraphicsSchedule* createNumbersEffect(int numbers , mof::Vector2D& position){
	std::basic_ostringstream<TCHAR> stream;
	stream << abs(numbers);
	mof::Sprite* pModel = mof::Sprite::createSpriteFromText(stream.str() , 20);

	mof::CascadeAnimation* pCascadeAnimation = new mof::CascadeAnimation();
	{
		mof::DataBasedAnimation* pAnimation;
		if(numbers > 0)pAnimation = new mof::DataBasedAnimation(_T("data/motion/heel.csv") );
		else pAnimation = new mof::DataBasedAnimation(_T("data/motion/damage.csv") );
		mof::AnimationResource resource(pAnimation);
		pCascadeAnimation->setElement(1 , resource);
	}

	{
		mof::KeyFrameAnimation* pAnimation = new mof::KeyFrameAnimation();
		pAnimation->setPosition(0 , mof::Vector2D(-200 , -200 ));
		pAnimation->setPosition(1 , position);
		pAnimation->setPosition(40 , position);
		
		
		mof::AnimationResource resource(pAnimation);
		pCascadeAnimation->setElement(0 , resource);
	}
	
	mof::AnimationResource animation(pCascadeAnimation);
	pModel->setAnimation(0 , animation);
	
	mof::GraphicsSchedule* pSchedule = new mof::GraphicsSchedule();
	pSchedule->add(0 , mof::GraphicsModelPtr(pModel) , animation);
	return pSchedule;


}

mof::GraphicsSchedule* createAPEffect(int dActionPoint , mof::Vector2D& position){
	std::basic_ostringstream<TCHAR> stream;
	stream << _T("AP");
	if(dActionPoint >= 0)stream << _T("+");
	stream << dActionPoint;
	mof::Sprite* pModel = mof::Sprite::createSpriteFromText(stream.str() , 20);


	mof::CascadeAnimation* pCascadeAnimation = new mof::CascadeAnimation();
	{
		mof::DataBasedAnimation* pAnimation = new mof::DataBasedAnimation(_T("data/motion/ap.csv") );
		mof::AnimationResource resource(pAnimation);
		pCascadeAnimation->setElement(1 , resource);
	}

	{
		mof::KeyFrameAnimation* pAnimation = new mof::KeyFrameAnimation();
		pAnimation->setPosition(0 , mof::Vector2D(-200 , -200 ));
		pAnimation->setPosition(1 , position);
		pAnimation->setPosition(40 , position);

		mof::AnimationResource resource(pAnimation);
		pCascadeAnimation->setElement(0 , resource);
	}
	
	mof::AnimationResource animation(pCascadeAnimation);
	pModel->setAnimation(0 , animation);

	mof::GraphicsSchedule* pSchedule = new mof::GraphicsSchedule();
	pSchedule->add(20 , mof::GraphicsModelPtr(pModel) , animation);
	return pSchedule;

}


mof::GraphicsSchedule* createMessage(const mof::tstring& message , mof::TextureManager* pTextureManager){
	
	et::MyFrame* pModel = new et::MyFrame(mof::Line2D( 0 , 0 , 200 , 300) , true , pTextureManager->getResource(_T("image/frame0.png")));
	//pModel->setMargin(2);
	mof::Sprite* pMessage = mof::Sprite::createSpriteFromText(message , 17);
	pModel->add(pMessage);

	//センタリングする
	int centerizedX = (mof::System::getInstance()->getWindowWidth() - pModel->getWidth()) * 0.5;

	mof::KeyFrameAnimation* pAnimation = new mof::KeyFrameAnimation();
	pAnimation->setPosition(0 , mof::Vector2D(centerizedX , -50 ));
	pAnimation->setPosition(10 , mof::Vector2D(centerizedX , 5 ));
	pAnimation->setPosition(60 , mof::Vector2D(centerizedX , 5 ));
	pAnimation->setPosition(70 , mof::Vector2D(centerizedX , -50 ));
	pAnimation->setFinalKey(0);
	mof::AnimationResource resource(pAnimation);
	pModel->setAnimation(0 , resource);


	mof::GraphicsSchedule* pSchedule = new mof::GraphicsSchedule();
	pSchedule->add(20 , mof::GraphicsModelPtr(pModel) , resource);
	return pSchedule;
}


mof::GraphicsSchedule* createChanceDisplay(int beginFrame , int endFrame , et::BattleData* pBattleData){
	et::MyFrame* pModel = new et::MyFrame(mof::Line2D( 0 , 0 , 200 , 300) , true , 
		pBattleData->getTextureManager()->getResource(_T("image/frame0.png")));
	pModel->setMargin(5);
	mof::Sprite* pMessage = mof::Sprite::createSpriteFromText("Chance!" , 13);
	pModel->add(pMessage);

	et::BattlerBindAnimation* pAnimation = new et::BattlerBindAnimation(pBattleData->getBattlerGroup()->getHeroBattler());
	pAnimation->setFinalKey(endFrame - beginFrame);
	
	mof::AnimationResource resource(pAnimation);
	pModel->setAnimation(0 , resource);


	mof::GraphicsSchedule* pSchedule = new mof::GraphicsSchedule();
	pSchedule->add(beginFrame , mof::GraphicsModelPtr(pModel) , resource);
	return pSchedule;

}