#include "GPlayerManager.h"

#ifdef _DXLIB
#include "GStaticDataDX.h"
#else
#include "GStaticData.h"
#endif

#include <vector>
#include <string>
using namespace std;
using namespace GEnum;

GPlayerManager::GPlayerManager(){
	// 設定読み込み
	vector<string> vList = HPLFile::loadStringLinesFromFile("data/image/Player/SettingList.txt",
		TRUE);
	for( vector<string>::const_iterator cit = vList.begin();
		cit != vList.end();
		cit ++ ) 
	{
		// <ID>;<ファイルパス>
		vector<string> vItems = HPLString::split( *cit, ";" );
		HPLError::assertIt( vItems.size() == 2 ,
			"プレイヤー設定リストの書式エラー[%s]", cit->c_str());

		GPlayerSetting playerSetting;
		playerSetting.load( vItems[1].c_str());
		this->m_mapPlayerSettingMap[ atoi(vItems[0].c_str())] = playerSetting;
	}
}
GPlayerManager::~GPlayerManager(){
}


/**
	移動関連の処理
	・PlayerInputへの振り分け。
	・自然発生的現象の処理
*/
void GPlayerManager::move(GPlayer* player, HPLVector* velocityAngle){
	HPLVector center = player->getCenter();
//	GPlayerState* state = player->getState();

//	加速度による移動
//		float ACCEL = 0.07f;

	if(player->getState()->getState() == StateType::DISAPPEAR){
		return;
	}

	bool down = player->isPressed(GEnum::KeyMap::DOWN);
	////////////////
	// タンク状態で下キーを押すと降車
/*	if((player->getType() == PlayerType::Tank
			|| player->getType() == PlayerType::Robogen)
		&& down){

		// 降りる
		player->takeOut();
	}*/


	HPLMatrix<int>* matrix = getStaticData()->getBlockManager()->getBlockMatrix();

	int tileSize = getStaticData()->m_CommonWork.m_Setting.tileSize;

	// 限界領域
	HPLRect limitArea(0,0,
		(float)(matrix->getColumnSize() * tileSize),
		(float)(matrix->getRowSize() * tileSize));
		
	////////////
	// 限界範囲は超えないようにする
	// 横方向
	/*if(player->getCenter().getX() < limitArea.getX()){
		player->setCenter(limitArea.getX(), player->getCenter().getY());
	}else if(player->getCenter().getX() > limitArea.getRight()){
		player->setCenter(limitArea.getRight(), player->getCenter().getY());
	}*/

	// 縦方向
	//if(player->getCenter().getY() < limitArea.getY()){
	//	player->setCenter(player->getCenter().getX(), limitArea.getY());
	//}

	// 画面外へ出た
	if( limitArea.isShare( player->getHitArea() ) == false) {
		// 死亡
		//player->setCenter(player->getCenter().getX(), limitArea.getBottom());

		player->die(NULL);//setAlive(false);

	}
	/////////////


	// 状態遷移
	int st = player->getState()->getState();

	// アニメーション状態
	HPLSequenceState seqState = player->getSequence()->getState();

	///////
	// 無敵時間
	if(player->isInvinsible()){
		player->invinsibleProcess();
	}


	if(player->isAlive() == true){

		if(player->isBind()){
			////////////
			// バインド状態
//			doBind(player);
		}else{
			if(player->isHeld() == true){
				/*********
					ホールドされている状態は、
					・左右移動
					・ジャンプ
					・しゃがみ
					・攻撃

					が出来ない。ただし、レバガチャでのダメージは敵に与えられる
				*/
				HPLSequence* seq = player->getSequence();
				HPLSequenceState seqState = seq->getState();
				if(seqState.isFinishAnimation == true){
					// ループ
					HPLSequence* seq = player->getSequence();
					seq->resetCounter();
				}
			}else{
				////////////////////////////////////////////////////
				if(getStaticData()->m_CommonWork.m_Game.isGameOver() ||
					player->getState()->isDamageState() ||
					player->getState()->isAttackState())
				{
				}else{
					// 立ち→歩き の遷移（あれば）
					this->standToWalk(player, velocityAngle);

					//////
					// 近くにヒール状態のアンデルセン/いつでも状態のとりらまがいる場合回復する
/*					float HEAL_AIBO = 0.3f;
					if(player->isIMAibo() == false &&
						player->isWithAibo() && player->aibo != NULL){
						
						float dx = player->getCenter().getX() - player->aibo->getCenter().getX();
						float dy = player->getCenter().getY() - player->aibo->getCenter().getY();
						HPLVector dir(dx,dy);

						float HEAL_THRESHOLD = 200.f;

						if(dir.getLength() < HEAL_THRESHOLD){
							if(player->aibo->isHeal()){
									/////
									//
								player->setHP(player->getHP() + HEAL_AIBO);

								getStaticData()->getScore()->addFloatScore(
									FloatScore::HEAL_OTHER,
									HEAL_AIBO);
								
							}else if(player->isHeal()){
								player->aibo->setHP(player->getHP() + HEAL_AIBO);
							}
						}
					}*/
				}

				if( player->getState()->isDamageState() ||
					player->getState()->isAttackState() ||
					player->isNoPlayerControllableState() )
				{
					// 特殊状態
					// →ジャンプ/移動/しゃがみが出来ない
				} else {
					// 歩き→立ち の遷移（あれば）
					this->walkToStand(player, velocityAngle);
					if(getStaticData()->m_CommonWork.m_Game.isGameOver()){

					}else{

						jump(player, velocityAngle);
						crouch(player, velocityAngle);
					}
				}


				////////
				// 一定周期で瞬きをする(アンデルのみ)
/*				if(player->getType() == PlayerType::Undelsen){
					player->processMabataki();
				}*/

				HPLSequence* seq = player->getSequence();
				HPLSequenceState seqState = seq->getState();

				////////
				// ダメージモーション終了
				if(player->getState()->isDamageState()){
					
					if(seqState.isFinishAnimation == true
						//||
	//					player->isErogenDamage()
							)
					{
						// ダメージモーション終了

						if(player->isHeld()){
							// 捕まっている
						} else if( player->m_DamageRecoveryCounter.getState().isFinishAnimation == false ) {
							// ダメージモーションカウンタがまだ終わっていない
							// 続行
							player->m_DamageRecoveryCounter.step();
							player->getSequence()->resetCounter();

						} else {
							// 捕まれていない
							// 立ち(飛び)状態に戻る
							//player->changeState(StateType::STAND);
							player->rollBackState();

							//player->setErogenDamage(false);
						}
					}
				}
				if( player->getState()->getState() == StateType::CAKE ) {
					if( player->getSequence()->getState().isFinishAnimation ) {
						player->rollBackState();
					}
				}
			}
			//////
			// 毒状態のとき
			// ・毒マークを表示する
			// ・ある確率でダメージを受ける
/*			if(player->isPoison() || player->isErogen()){
				doPosion(player, player->isErogen());
			}*/

			//
			///////



		}
	}else{// if(player->isAlive() == false)

		///////////
		// 死んでる
		///////
		// 進行方向を向く
		if(player->getVelocityAngle().getX() > 0){
			player->setFaceDirection(FaceDirection::RIGHT);
		}else if(player->getVelocityAngle().getX() < 0){
			
			player->setFaceDirection(FaceDirection::LEFT);
		}

	}
	//
	//////
}

void GPlayerManager::collisionCheck(GPlayer* player, HPLVector* center, HPLVector* velocityAngle){

	if(player->isHeld()){
		return;
	}

	HPLRect area = player->getArea();

	HPLRect hitArea = player->getHitRect();
	hitArea.setX(hitArea.getX() + area.getX());
	hitArea.setY(hitArea.getY() + area.getY());

//	BBPlayerState* state = player->getState();

	AbstractBlockManager* blockManager = getStaticData()->getBlockManager();

	/////////////
	// common collision check and adjustment
	//CollisionState states[2];


	///////
	// 衝突前の速度を記憶
	HPLVector prevVelocityAngle = HPLVector(velocityAngle->getX(), velocityAngle->getY());

	bool isOnTheGroundBefore = player->getTrigger()->getTrigger(TriggerType::ON_THE_GROUND);

	float fResist = getStaticData()->m_CommonWork.m_Setting.resist;
	if( player->getState()->isDamageState() || player->getState()->isDeadState() ) {
		fResist *= 0.2f;
	}

	CollisionState stateX;
	CollisionState stateY;
	HPLCollisionTool::commonCollision((HPLShootingObject*)player,//this->getArea(), this->getHitRect(),
//		&center, &vel, width, height,
		getStaticData()->getBlockManager()->getBlockMatrix(), 
		getStaticData()->m_CommonWork.m_Setting.tileSize,
		getStaticData()->getBlockManager()->getBlockMap(),
//		this->getTrigger(),
		stateX, stateY,
		getStaticData()->m_CommonWork.m_Setting.gravity,
		fResist,
		getStaticData()->m_CommonWork.m_Setting.fallMaxSpeed);

	int st = player->getState()->getState();
	////////
	// ダメージモーション中
	bool isDamageMotion = 
		player->getState()->isDamageState();
	//|| st == StateType::DEAD;

	//////
	// トリガによる動作
	HPLTrigger* trigger = player->getTrigger();


	///////
	//
	if(trigger->getTrigger(TriggerType::HIT_TO_THE_LEFT) ||
		trigger->getTrigger(TriggerType::HIT_TO_THE_RIGHT)){
		///////
		// 横方向にブロックにぶつかった
		//  →ダメージ中：はねる
		//  →通常時：とまる(通常止まる)

		if(isDamageMotion){
			/////
			// ダメージ中
			float a = -1 * HPLMath::getSgn(prevVelocityAngle.getX());
/*			if(trigger->getTrigger(TriggerType::HIT_TO_THE_LEFT)){
				a = 1;
			}*/
			HPLVector vel = player->getVelocityAngle();
			vel.setX(
				a * 
				getStaticData()->m_CommonWork.m_Setting.wallBoundRefrection *
				fabs(prevVelocityAngle.getX()));

			/*if(prevVelocityAngle.getX() < getStaticData()->m_CommonWork.m_Setting.player.airMaxSpeed / 2){
				/////
				// ゆっくり当たったら
				vel.set(0,0);
			}*/
			player->setVelocityAngle(vel);
		}else{
			HPLVector vel = player->getVelocityAngle();
			vel.setX(0);
			player->setVelocityAngle(vel);
		}

	}

	//////
	// 縦方向


	float FLYDOWN_SPEED_THRESHOLD = getStaticData()->m_CommonWork.m_Setting.flydownSpeedThreshold;
/*	if(player->getType() == PlayerType::Robogen){
		FLYDOWN_SPEED_THRESHOLD /= 2.f;
	}*/

	if(player->isHeld()){

	}else{
/*		if(player->getType() == PlayerType::Durandana &&
			player->getSwordType() == SwordType::Katana &&
			st == StateType::ATTACK_4){

				// デュランダナが刀を持っている。接地は問わない
				// 抜刀中である
				const float KATANA_RESIST_RATE = 4;
				float RESIST = getStaticData()->m_CommonWork.m_Setting.resist;
				// 減速
				float x = HPLActionMoveTool::reduceSpeed(RESIST * KATANA_RESIST_RATE, velocityAngle->getX());
				velocityAngle->setX(x);
		}*/
		if(trigger->getTrigger(TriggerType::ON_THE_GROUND)){
			//////
			// 接地した

			if(player->isAlive()){
				/////
				// 生きてる
				// 立ち状態にする
				if(st == StateType::FLYDOWN ||
					st == StateType::FLYUP){
						if(st != StateType::BORING){
							player->changeState(StateType::STAND);
						}
				}

				if(st == StateType::DAMAGE_FLYDOWN ||
					st == StateType::DAMAGE_FLYDOWN_REVERSE){
						// ダメージ中地面についたら通常立ち
						//player->changeState(StateType::STAND);

						// ではなく、倒れ状態にする。
						//player->changeState(StateType::DEAD);
						player->changeState(StateType::LYING);
				}


				// ジャンプ回数をリセットする
				player->getJumpManager()->resetJumpNumMax();

			}else if(st != StateType::DISAPPEAR 
				&& st != StateType::BROKEN && player->getState()->isDamageState() == false){// && player->isDamageMotion() == false){
				/////
				// 死んでる
				player->changeState(StateType::DEAD);
			}
		}else{
			////////
			// 空中に居る
			if(player->isAlive() == false && st != StateType::DISAPPEAR &&
				st != StateType::BROKEN && player->isHeld() == false){
				//&&player->isDamageMotion() == false){
				////////////
				// 死んでる…
				// 　→速度の方向で状態を変える

				// 落下速度が一定以上になったら下降モーションに移る
				if(velocityAngle->getY() >= FLYDOWN_SPEED_THRESHOLD && st != StateType::DEAD_FLYDOWN){
					player->changeState(StateType::DEAD_FLYDOWN);
				}else if(velocityAngle->getY() < FLYDOWN_SPEED_THRESHOLD &&
					st != StateType::DEAD_FLYUP){
	//					if(velocityAngle->getY() < 0 && ){
					player->changeState(StateType::DEAD_FLYUP);
				}
			}else{

				if(st != StateType::DAMAGE_ELEC &&
					/////
					// 電気！
					player->getState()->isDamageState()){

						if(player->isHeld() == false){
							/////////
							// ダメージ中空中にいる場合、のけぞりとかさせる
							getStaticData()->m_CommonWork.setDamageFlyingState(player);
						}
				}else{
					/////
					// 通常時
					if(player->isHeld() == false &&
						(st == StateType::STAND ||
						st == StateType::WALK ||
						st == StateType::CROUCH ||
						st == StateType::BORING_CROUCH ||
						st == StateType::FLYDOWN ||
						st == StateType::FLYUP
						)&& player->getTrigger()->getTrigger(TriggerType::ON_THE_GROUND) == false 
						)
					{


						if(velocityAngle->getY() >= FLYDOWN_SPEED_THRESHOLD){
							if(st != StateType::FLYDOWN){
 								player->changeState(StateType::FLYDOWN);
							}
						}else if(
							st != StateType::FLYUP){
							player->changeState(StateType::FLYUP);
						}
					}


					//////
					// もし地面にいて飛び降りたとしたら、ジャンプ回数を一回減らす
					if(player->getVelocityAngle().getY() > 0 &&
						isOnTheGroundBefore && 
						player->isPressed(GEnum::KeyMap::B))
					{
						player->getJumpManager()->jump();

					}
				}
			}
		}
	}

}

