#include "ShotManager.h"
#include "StaticData.h"
#include <cstdlib>

namespace MotionTest {
using namespace HPL;
using namespace E3D;
using namespace General;
using namespace MotionTestConsts;

ShotManager::ShotManager() {
}
ShotManager::~ShotManager() {
}

///////////////////
// オーバーライド
BOOL ShotManager::is_Skip( E3DObject* obj ) {
	return obj->get_Valid() == FALSE ? TRUE: FALSE;

}
int ShotManager::checkInView( E3DObject* obj ) {
	int status;
	// チェックイン
	if( E3DChkInView( staticData->get_SwapChainID(), obj->m_nSigID, &status ) ){
		_ASSERT( 0 );
		return 1;
	}
	return 0;
}
int ShotManager::move( E3DObject* obj ) {
	int ret= 0;

	ret = E3DPosForward( obj->m_nSigID, obj->m_Move.m_fSpeed );

	// 位置設定
	E3DGetPos( obj->m_nSigID, &obj->m_Move.m_vPosition );

	if( obj->m_Game.m_Counter->step() & General::CounterStateType::ALL_LOOP_END ) {
		// 死亡
		// 消える
		obj->set_Valid( FALSE) ;
		E3DSetValidFlag( obj->m_nSigID, -1, FALSE );
	}else {
		// チェックイン
		int status;
		//E3DLookAtQ( obj->m_Move.m_nQuoatanion, obj->m_Move.m_vVelocity, D3DXVECTOR3(0,0,1), 0, 1 );
		if( E3DChkInView( staticData->get_SwapChainID(), obj->m_nSigID, &status ) ){
			_ASSERT( 0 );
			return 1;
		}
	}

	return 0;
}
int ShotManager::checkHitToGround( E3DObject* obj ) {
	int ret = 0;

/*	ret = staticData->checkObjectOnGround( obj);
	if( ret ) {
		_ASSERT(0);
		return ret;
	}*/
	int nMode = 0;	//地を這う蛇

	// 結果
	int nResult = 0;

	D3DXVECTOR3 vAdjust;
	D3DXVECTOR3 n;
	float fDiffMaxY = 20000.f;
	ret = E3DChkConfGround( obj->m_nSigID, staticData->get_GroundSigID(), nMode, 
		fDiffMaxY, MAP_MIN, &nResult, &vAdjust, &n );
	if(ret ) {
		_ASSERT(0);
		return 1;
	}

	D3DXVECTOR3 vPosition;
	E3DGetPos( obj->m_nSigID, &vPosition );

	if( vPosition.y > vAdjust.y )	{
		// 空中
	} else {
		if( nResult ) {
			// 触れた

			// 消える
			obj->set_Valid( FALSE );
			if( obj->m_Game.m_nType == ShotType::BULLET ) {
				// 何もしない
			} else if( obj->m_Game.m_nType == ShotType::MISSILE ) {
				// 爆発する
			}
		}
	}

	return 0;
}
/*int ShotManager::checkHitToBillBoard( E3DObject* obj ) {

	// 当ったショットのSigIDリスト
	int nShotID[MotionTestConsts::SHOT_MAX];

	// 当ったショットの数
	int nConfNum;

	// 当ったかどうかの結果
	int confptr = 0;

	int ret = 0;

	// 全ビルボードとの当り判定をチェック
	ret = E3DChkConfBillboard( obj->m_nSigID,
		1.f, &confptr, nShotID, MotionTestConsts::SHOT_MAX, &nConfNum );

	if( confptr != 0 ) {
		// 何かに当った

		for(int i = 0; i < nConfNum; i ++ ) {
			// 弾を消す
			ret = E3DSetValidFlag( -1, nShotID[i] , FALSE);

			// 逆引きでビルボード情報を取得
			E3DBillBoard* billBoard = staticData->m_ShotBillBoardManager.m_mapSigIDToBillBoardMap[ nShotID[i] ];
			billBoard->set_Alive( FALSE );

			// 敵の体力を減らす
			float fNextHP = obj->m_Game.m_fHP - MotionTestConsts::SHOT_POWER;
			if( fNextHP <= 0) {
				fNextHP = 0;
				// 死亡
				obj->set_Valid( FALSE );
				E3DSetValidFlag( obj->m_nSigID, -1, FALSE );
			}
			obj->m_Game.m_fHP = fNextHP;
		}



	}
	return 0;
}*/
int ShotManager::checkHitToEnemy( E3DObject* obj ) {

	int ret = 0;
	int confptr = 0;		

	int inviewptr;

	for( std::map<int, std::list<E3DObject*> >::iterator mit = staticData->m_EnemyManager.m_mapObjectListMap.begin();
		mit != staticData->m_EnemyManager.m_mapObjectListMap.end();
		mit ++ ) 
	{
//		for( std::list<E3DObject*>::iterator it = mit->second.begin();
//			it != mit->second.end();
//			it ++ )
		for( std::list<E3DObject*>::iterator it = this->m_mapValidObjectListMap[mit->first].begin();
			it != this->m_mapValidObjectListMap[mit->first].end();
			it ++ )
		{
			E3DObject* enemy = *it;

			if( enemy->is_Valid() == FALSE ) {
				continue;
			}

			ret = E3DChkConflictOBB( enemy->m_nSigID, -1,
				obj->m_nSigID, -1, &confptr , &inviewptr);
			if( ret ) {
				_ASSERT( 0 );
				return 1;
			}
			if( confptr ) {
				// 当った

				// 弾を消す
				obj->set_Valid( FALSE);
				ret = E3DSetValidFlag( obj->m_nSigID, -1, FALSE );

				// 弾が向いている方向と逆方向に。
				D3DXVECTOR3 vDirection;
				E3DGetCharaDir( obj->m_nSigID, 0,0, &vDirection);

				D3DXVec3Normalize( &vDirection, &vDirection );

				// 血飛沫を出す(1つ)
				// ショットの位置から出す
				E3DBillBoard* billBoard = staticData->create_Blood( obj->m_Move.m_vPosition,
					vDirection);

				// 敵を気づかせる
				enemy->m_Game.m_bRecognized = TRUE;

				if( obj->m_Game.m_nType == EnemyType::ZOMBIE_B && obj->m_Move.get_Trigger( TriggerType::ON_THE_GROUND ) == FALSE &&
					enemy->m_nEventNumber != Motion::Zombie_B::AIR_DAMAGE)
				{
					// 空中にいる

					// やられモーションに移る
					enemy->m_nEventNumber = Motion::Zombie_B::AIR_DAMAGE;
				}

				// 敵の体力を減らす
				float fPower = MotionTestConsts::SHOT_POWER;
				if( obj->m_Game.m_nType == ShotType::MISSILE ) {
					fPower = MotionTestConsts::SHOT_MISSILE_POWER;
				}
				float fNextHP = enemy->m_Game.m_fHP - fPower;
				if( fNextHP <= 0) {
					fNextHP = 0;

					if( enemy->m_Game.m_nType == EnemyType::WORM_BIG)
					{ 
						// ワームである
						// 消えない

						// 死亡モーションに移る
						enemy->m_nEventNumber = Motion::Worm::DEAD;
					} else if( enemy->m_Game.m_nType == EnemyType::ZOMBIE)
					{ 
						// 死亡モーションに移る
						enemy->m_nEventNumber = Motion::Zombie::DEAD;
					} else if( enemy->m_Game.m_nType == EnemyType::ZOMBIE_B)
					{ 
						// 死亡モーションに移る
						enemy->m_nEventNumber = Motion::Zombie_B::DEAD;
					} else {
						// 死亡
						enemy->set_Valid( FALSE );
						E3DSetValidFlag( enemy->m_nSigID, -1, FALSE );

						// アイテム生成

						// 確率（差分）
						float ITEM_RATE_LIST[] = {
							5,	// MINI_GUN
							8,	// HAND_GUN			
							3,	// MEDI_KIT	
							20,	// AMMO		
							1,	// MEAT		
						};

						int nNeutralType = -1;
						float fRnd = MathTool::nextRandom<float>(0,100);
						float fRate = 0;
						for( int i = 0; i < 5; i ++ ) {
							fRate += ITEM_RATE_LIST[i];
							if( fRnd <= fRate ) {
								nNeutralType = NeutralType::MINI_GUN + i;
								break;
							}
						}

						if( nNeutralType == -1 ||
							nNeutralType == NeutralType::MINI_GUN && staticData->m_aryWeaponList[ WeaponType::MINI_GUN].is_Enable() ||
							nNeutralType == NeutralType::HAND_GUN && staticData->m_aryWeaponList[ WeaponType::HAND_GUN].is_Enable() )
						{
							// 生成しない
						} else {
							E3DObject* neutral = staticData->m_NeutralManager.search( nNeutralType );
							if( neutral ) {
								neutral->m_Move.m_vPosition = enemy->m_Move.m_vPosition;
								neutral->m_Move.m_vPosition.y = BasicStaticDataConsts::PLAYER_EYE_HEIGHT_FROM_CENTER;
								E3DSetPos( neutral->m_nSigID, neutral->m_Move.m_vPosition );

								const float ITEM_JUMP_SPEED = 100.f;
								neutral->m_Move.m_vVelocity = D3DXVECTOR3(0,ITEM_JUMP_SPEED, 0 );
							}

						}
					}

				}
				enemy->m_Game.m_fHP = fNextHP;


				if( static_cast<int>(staticData->m_lstEnemyLifeBarList.size() ) < MotionTestConsts::ENEMY_LIFE_BAR_STACK_NUM_MAX ) {
					// 敵の体力表示リストにキュー有り。

					// 
					BOOL bFound = FALSE;

					for(std::list<EnemyLifeBar*>::iterator bit = staticData->m_lstEnemyLifeBarList.begin();
						bit != staticData->m_lstEnemyLifeBarList.end();
						bit ++ )
					{
						EnemyLifeBar* lifeBar = *bit;
						if( lifeBar->m_nSigID == enemy->m_nSigID ) {
							// 既に登録済み
							// →情報更新
							lifeBar->m_fHP = enemy->m_Game.m_fHP;
							lifeBar->m_Counter.reset();
							bFound = TRUE;
							break;
						}
					}
					if( bFound == FALSE ) {
						// 新規追加
						EnemyLifeBar* lifeBar = new EnemyLifeBar();
						lifeBar->m_fHP = enemy->m_Game.m_fHP;
						lifeBar->m_fHPMax = enemy->m_Game.m_fHPMax;
						lifeBar->m_strName = std::string( "Cyclops");
						if( obj->m_Game.m_nType == EnemyType::WORM_BIG ){
							lifeBar->m_strName = std::string( "Big worm");
						} else if( obj->m_Game.m_nType == EnemyType::WORM_SMALL ){
							lifeBar->m_strName = std::string( "Worm");
						} else if( obj->m_Game.m_nType == EnemyType::ZOMBIE ) {
							lifeBar->m_strName = std::string( "Zombie");
						} else if( obj->m_Game.m_nType == EnemyType::ZOMBIE_B ) {
							lifeBar->m_strName = std::string( "ZombieB");
						} else if( obj->m_Game.m_nType == EnemyType::MOSUKO ||
							obj->m_Game.m_nType == EnemyType::MOSUKO_LONG )
						{
							lifeBar->m_strName = std::string( "Mosuko");
						} else if( obj->m_Game.m_nType == EnemyType::TROL )
						{
							lifeBar->m_strName = std::string( "Trol");
						}
						lifeBar->m_Counter.set_FrameCounterMax( MotionTestConsts::ENEMY_LIFE_BAR_REMAIN_COUNT );
						lifeBar->m_Counter.set_LoopNumMax( 1 );
						lifeBar->m_nSigID = enemy->m_nSigID;
						lifeBar->m_Counter.reset();
						staticData->m_lstEnemyLifeBarList.push_back(lifeBar );
					}

				} //
			}
		}
	}

	return 0;
}
int ShotManager::render( E3DObject* obj ) {

	// sig id取得
	int hsid = obj->m_nSigID;

	// 通常描画
	if( E3DRender( staticData->get_SwapChainID(), hsid, 0, 1, 0, 0 ) ){
		_ASSERT( 0 );
		return 1;
	}

	// αブレンド描画
	if( E3DRender( staticData->get_SwapChainID(), hsid, 1, 1, 0, 0 ) ){
		_ASSERT( 0 );
		return 1;
	}
	int ret = E3DSetBeforePos( obj->m_nSigID) ;
	return 0;
}

int ShotManager::createObjects( int nType, int nNum ) {
	int ret = 0;

	char lpszSigFilePath[MAX_PATH];

	if( nType == ShotType::BULLET ) {
		strcpy_s( lpszSigFilePath, MAX_PATH, "Media\\model_madogen\\bullet.sig");
	}else if( nType == ShotType::MISSILE ){
		strcpy_s( lpszSigFilePath, MAX_PATH, "Media\\Weapon\\Missile.sig");
	} else {
		_ASSERT( 0 );
		return 1;
	}

	// 有効一覧に追加
	this->m_mapValidObjectListMap[nType] = std::list<E3DObject*>();

	// コピー元となるマスタSIGID
	int nMasterSigID = 0;

	/////////////////
	// Sigファイル読み込み
	ret = E3DSigLoad( lpszSigFilePath, 0, 1.f, &nMasterSigID );
	if( ret ) {
		_ASSERT( 0 );
		return ret;
	}

	// 追加処理
	ret = this->add_Object( nType, nMasterSigID );

	// クローンマネージャに登録
	ret = this->m_CloneManager.add_MasterBuffer( nType, nMasterSigID);

	// 予約一個消化
	nNum --;

	if( nNum >= 1 ) {
		// まだ作成すべきものがある
		// バッファにコピーしてSigを複製

		// テクスチャパス
		char lpszTextureDirPath[MAX_PATH];
		if( nType == ShotType::BULLET ) {
			strcpy_s( lpszTextureDirPath, MAX_PATH, "Media\\model_madogen\\");
		}else if( nType == ShotType::MISSILE ) {
			strcpy_s( lpszTextureDirPath, MAX_PATH, "Media\\Weapon\\");
		} else {
			_ASSERT( 0 );
			return 1;
		}

		for(int i = 0; i < nNum; i ++ ) {
			E3DSigBufferData* bfSigBufferData = this->m_CloneManager.get_MasterBuffer(nType);
			// コピー
			int nSigID = 0;
			ret = E3DSigLoadFromBuf( lpszTextureDirPath,
				bfSigBufferData->m_lpczBuffer,
				bfSigBufferData->m_nBufferSize,
				0, 1.f, &nSigID );
				
			// 登録作業
			ret = this->add_Object( nType, nSigID );
		}

	}
	return 0;
}

int ShotManager::add_Object(int nType, int nSigID ) {
	int ret = 0;

	// オブジェクト生成
	E3DObject* obj = new E3DObject();

	//! オブジェクトタイプ
	obj->m_Game.m_nObjectType = ObjectType::NEUTRAL;

	//! タイプ
	obj->m_Game.m_nType = nType;

	// sig id 登録
	obj->m_nSigID = nSigID;

	// 逆引きに登録
	this->m_mapSigIDToObjectMap[ nSigID ] = obj;

	// リストに追加
	this->m_mapObjectListMap[nType].push_back( obj );

	// クォータニオン
	ret = E3DCreateQ( &obj->m_Move.m_nQuoatanion );

	/////
	// 状態
	obj->m_Game.m_Counter = new HPLCounter( SHOT_LIFE_COUNT, 1);

	float fSpeed = SHOT_SPEED;
	if( nType == ShotType::MISSILE ) {
		fSpeed = 150.f;
	}
	obj->m_Move.m_fSpeed = fSpeed;

	return 0;
}

/** MOAファイル読み込み
  *
  */
int ShotManager::loadMOAFile( const char* lpszFilePath, E3DObject* obj ) {

	return 1;
	/**
	int ret = 0;
	// 読み込み
	ret = E3DLoadMOAFile( obj->m_nSigID,
		lpszFilePath,
		5, 1.f);
	if( ret ){
		_ASSERT( 0 );
		return 1;
	}

	int nNumberOfMotion = 0;
	ret = E3DGetMoaInfo( obj->m_nSigID, MAX_MOTION,
		obj->m_moaMOAArray , &nNumberOfMotion);
	if( ret ){
		_ASSERT( 0 );
		return 1;
	}
	return 0;*/

}
/** 待機しているオブジェクトを呼び出します。
  * @retval NULL	既に全て埋まっていて存在しない場合
  */
E3DObject* ShotManager::search( int nType ) {
	for(std::list<E3DObject*>::iterator it = this->m_mapObjectListMap[nType].begin();
		it != this->m_mapObjectListMap[nType].end(); it ++ )
	{
		E3DObject* obj = *it;
		if( obj->get_Valid() == FALSE ) {

			// 有効リストに追加
			this->m_mapValidObjectListMap[nType].push_back(obj);

			obj->set_Valid( TRUE );
			E3DSetValidFlag( obj->m_nSigID, -1, TRUE );
			//obj->m_Game.m_fHP = obj->m_Game.m_fHPMax;
			//obj->m_Game.m_fDamage = ENEMY_DAMAGE;
			//obj->m_Game.m_fDamageError = ENEMY_DAMAGE / 2.f;

			//////////////////////
			// test 場所配置
			/*float MAX_DISTANCE = 15000;
			float ERR = 5000;

			float DEG = MathTool::nextRandom<float>(0, 360 );
			float fDistance = MAX_DISTANCE + MathTool::nextRandom<float>(-ERR,ERR);

			E3DSetPosOnGround( obj->m_nSigID, 
				staticData->get_GroundSigID(),
				MAP_HEIGHT, MAP_MIN, 
				fDistance * cos(D3DXToRadian( DEG )),
				fDistance * sin(D3DXToRadian( DEG )));*/

			return obj;
		}
	}
	return NULL;
}


}
