#include "stdafx.h"
#include "PVPManager.h"
#include "Protocol.h"
#include "UIMsgboxEvent.h"
#include "ChatManager.h"

#include "StageManager.h"
#include "ObjectManager.h"
#include "hero.h"
#include "GameUIManager.h"
#include "DMScoreWindow.h"
#include "Npc_Common.h"

#include "SceneManager.h"
#include "StaticSceneNode.h"

#include "InputSystem.h"

cPVPManager* cPVPManager::mpSingleton = 0;


cPVPManager::cPVPManager()
{
	assert( mpSingleton == 0 && "bad singleton!" );
	mpSingleton = this;

	mFightLeftTime = 0;

	mBattleState = eBattleState_None;

	mStaticDoor1 = ULONG_MAX;
	mStaticDoor2 = ULONG_MAX;

	mLeaderIdx = 0;
}

cPVPManager::~cPVPManager()
{
	if( mTeamInfoMap.GetSize() != 0 )
	{
		cMyTeamInfoMap::cIterator i = mTeamInfoMap.Begin();
		cMyTeamInfoMap::cIterator end = mTeamInfoMap.End();
		for( ; i != end; ++i )
		{
			sMyTeamInfo* info = (sMyTeamInfo*)(*i).mSecond;
			SAFE_DELETE( info );
		}
		mTeamInfoMap.Clear();
	}
}

int PvPRankSort( const void *arg1, const void *arg2 )
{
	sMyTeamInfo* score1 = (sMyTeamInfo*)arg1;
	sMyTeamInfo* score2 = (sMyTeamInfo*)arg2;

	if( score2->mKillCnt > score1->mKillCnt )
	{
		return 1;
	}
	else if( score2->mKillCnt < score1->mKillCnt )
	{
		return -1;
	}
	else
	{
		///
		return score1->mDeathCnt - score2->mDeathCnt;
	}
}


int PvPResultSort( const void *arg1, const void *arg2 )
{
	sMyTeamInfo* score1 = (sMyTeamInfo*)arg1;
	sMyTeamInfo* score2 = (sMyTeamInfo*)arg2;

	return score2->mScoreResult - score1->mScoreResult;
}

bool cPVPManager::Init()
{
	return true;
}


void cPVPManager::Exit()
{
}


void cPVPManager::Open()
{
	if( IsEnableBattle() == false )
		return;

	/// 점수판 보여주기
	cDMScoreWindow* win = GAMEUI->GetDMScoreWindow();
	if( win )
	{
		win->Clear();
		win->ShowTop();
	}

	cDMRankingListWindow* rankWin = GAMEUI->GetDMRankingListWindow();
	if( rankWin )
		rankWin->Clear();

	mUpdateRankInfo = true;

	CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 821 ) );
}

void cPVPManager::Close()
{
	mBattleState = eBattleState_None;

	mFightLeftTime = 0;
	mReadyPrintTime = ULONG_MAX;

	mLeaderIdx = 0;

	mStaticDoor1 = ULONG_MAX;
	mStaticDoor2 = ULONG_MAX;

	if( mTeamInfoMap.GetSize() != 0 )
	{
		cMyTeamInfoMap::cIterator i = mTeamInfoMap.Begin();
		cMyTeamInfoMap::cIterator end = mTeamInfoMap.End();
		for( ; i != end; ++i )
		{
			sMyTeamInfo* info = (sMyTeamInfo*)(*i).mSecond;
			SAFE_DELETE( info );
		}
		mTeamInfoMap.Clear();
	}
}

void cPVPManager::Process( unsigned long deltaTime, unsigned long accumTime )
{
	if( IsEnableBattle() == false )
		return;

	if( mBattleState < eBattleState_Result )
	{
		cKeyboardAgent* keyAgent = INPUTSYS->GetKeyboard();
		if( keyAgent->GetKeyPressed( KEY_SPACE ) == true )
		{
			OpenRank( mUpdateRankInfo );
			mUpdateRankInfo = false;
		}
		else
		{
			cDMRankingListWindow* win = GAMEUI->GetDMRankingListWindow();
			if( win )
				win->Hide( false );
		}
	}

	switch( mBattleState )
	{
	case eBattleState_Ready:
		{
			if( mFightLeftTime == 0 )
				return;

			if( mFightLeftTime < deltaTime )
			{
				mFightLeftTime = 0;
				return;
			}
			else
				mFightLeftTime -= deltaTime;

			if( mFightLeftTime <= mReadyPrintTime )
			{
				/// chat message
				cStringT Message;
				Message.Format( GAMERESOURCEMAN->GetGameText( 835 ), mReadyPrintTime/1000 );
				CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, Message.Cstr() );

				if( mReadyPrintTime == 30000 )
					mReadyPrintTime = 10000;
				else if( mReadyPrintTime <= 10000 )
					mReadyPrintTime -= 1000;
			}
		}
		break;
	}
}

bool cPVPManager::IsMyTeam( cPlayer* player )
{
	if( mBattleState == eBattleState_None )
		return true;

	if( player == 0 )
	{
		assert(0);
		return false;
	}

	if( HERO->GetPVPTeam() == player->GetPVPTeam() )
		return true;

	return false;
}

bool cPVPManager::IsEnableAttack( cPlayer* player )
{
	if( mBattleState != eBattleState_Fight )
		return false;

	if( player == 0 )
	{
		assert(0);
		return false;
	}

	if( HERO->GetPVPTeam() != player->GetPVPTeam() )
		return true;

	return false;
}

void cPVPManager::LinkPvpForceEffect( cPlayer* player, unsigned char forceType )
{
	if( player == 0 )
		return;

	if( IsEnableBattle() == true )
	{
		switch( forceType )
		{
		case eFORCETYPE_FIRE :	player->SetLinkdEffect( eLINK_FOOT, "./Data/Effect/Eff_PC_PVP_1.nif", 0, true, true ); break;
		case eFORCETYPE_WATER :	player->SetLinkdEffect( eLINK_FOOT, "./Data/Effect/Eff_PC_PVP_2.nif", 0, true, true ); break;
		case eFORCETYPE_WIND :	player->SetLinkdEffect( eLINK_FOOT, "./Data/Effect/Eff_PC_PVP_4.nif", 0, true, true ); break;
		case eFORCETYPE_EARTH :	player->SetLinkdEffect( eLINK_FOOT, "./Data/Effect/Eff_PC_PVP_3.nif", 0, true, true ); break;
		default:
			break;
		}
	}
}

void cPVPManager::AddTeamPlayerInfo( sMsgMemberInfo* memberInfo )
{
	if( memberInfo == 0 )
	{
		assert(0);
		return;
	}

	sMyTeamInfo* info = new sMyTeamInfo;
	info->mPlayerIdx = memberInfo->mCharacterIdx;
	::Sstrncpy( info->mName, MAX_NAME_BUFFER_SIZE, memberInfo->mName, MAX_NAME_SIZE );
	info->mForceType = memberInfo->mForceType;
	info->mKillCnt = 0;
	info->mDeathCnt = 0;
	info->mScoreResult = 0;

	if( mTeamInfoMap.Insert( memberInfo->mCharacterIdx, info ) == false )
	{
		assert(0);
		delete info;
		return;
	}

	mUpdateRankInfo = true;
}

void cPVPManager::DelTeamPlayerInfo( unsigned long playerIdx )
{
	sMyTeamInfo* info = (sMyTeamInfo*)mTeamInfoMap.GetAt( playerIdx );
	if( info == 0 )
	{
		assert(0);
		return;
	}

	delete info;
	mTeamInfoMap.Erase( playerIdx );

	mUpdateRankInfo = true;
}


void cPVPManager::UpdateTeamPlayerInfo( unsigned long playerIdx, unsigned long value, bool kill )
{
	sMyTeamInfo* info = (sMyTeamInfo*)mTeamInfoMap.GetAt(playerIdx);
	if( info == 0 )
	{
		assert(0);
		return;
	}

	if( kill )
		info->mKillCnt = value;
	else
		info->mDeathCnt = value;

	mUpdateRankInfo = true;
}

void cPVPManager::OpenRank( bool update )
{
	cDMRankingListWindow* win = GAMEUI->GetDMRankingListWindow();
	if( win == 0 )
		return;

	if( update == true )
	{
 		sMyTeamInfo teamResult[PVP_DM_TEAM_CNT];
		unsigned int resultCnt = 0;

		cMyTeamInfoMap::cIterator itr = mTeamInfoMap.Begin();
		cMyTeamInfoMap::cIterator itrEnd = mTeamInfoMap.End();
		for( ; itr != itrEnd; ++itr )
		{
			sMyTeamInfo* info = (sMyTeamInfo*)(*itr).mSecond;
			if( info )
			{
				teamResult[resultCnt].mPlayerIdx = info->mPlayerIdx;
				::Sstrncpy( teamResult[resultCnt].mName, MAX_NAME_BUFFER_SIZE, info->mName, MAX_NAME_SIZE );
				teamResult[resultCnt].mForceType = info->mForceType;
				teamResult[resultCnt].mKillCnt = info->mKillCnt;
				teamResult[resultCnt].mDeathCnt = info->mDeathCnt;

				resultCnt++;
			}
		}

		if( resultCnt > PVP_DM_TEAM_CNT )
		{
			assert(0);
			resultCnt = PVP_DM_TEAM_CNT;
		}

		::qsort( (void*)teamResult, resultCnt, sizeof(sMyTeamInfo), PvPRankSort );

		win->Clear();
		for( unsigned long i = 0; i < resultCnt; ++i )
		{
			win->AddPlayerRankInfo( &(teamResult[i]), (teamResult[i].mPlayerIdx == mLeaderIdx) );
		}
	}

	if( win->IsVisible() == false )
		win->ShowTop();
}


void cPVPManager::OpenResult( MSG_SYN_PVP_DM_FIGHTEND* pmsg, bool win )
{
	cDMResultWindow* resultWindow = GAMEUI->GetDMResultWindow();
	if( resultWindow == 0 )
		return;

	/// 
	sMyTeamInfo teamResult[PVP_DM_TEAM_CNT];
	unsigned int resultCnt = 0;
	for( unsigned long i=0; i<pmsg->mTeamCnt; ++i )
	{
		sPvPDMTeamScore& data = pmsg->mTeam[i];
		sMyTeamInfo* info = (sMyTeamInfo*)mTeamInfoMap.GetAt( data.mCharacterIdx );
		if( info )
		{
			teamResult[resultCnt].mPlayerIdx = info->mPlayerIdx;
			::Sstrncpy( teamResult[resultCnt].mName, MAX_NAME_BUFFER_SIZE, info->mName, MAX_NAME_SIZE );
			teamResult[resultCnt].mForceType = info->mForceType;
			teamResult[resultCnt].mKillCnt = info->mKillCnt;
			teamResult[resultCnt].mDeathCnt = info->mDeathCnt;
			teamResult[resultCnt].mScoreResult = data.mScore;

			resultCnt++;
		}
	}

	if( resultCnt > PVP_DM_TEAM_CNT )
	{
		assert(0);
		resultCnt = PVP_DM_TEAM_CNT;
	}

	::qsort( (void*)teamResult, resultCnt, sizeof(sMyTeamInfo), PvPResultSort );

	/// 1. 순위 출력
	resultWindow->Clear();
	for( unsigned long i = 0; i < resultCnt; ++i )
	{
		resultWindow->InsertRank( &teamResult[i], i );
	}

	/// 2. 결과 출력
	resultWindow->SetResult( win );

	/// 3. 보상 세팅
	resultWindow->SetRewardForce( pmsg->mFirePoint, pmsg->mFireFriendly );
	resultWindow->SetRewardForce( pmsg->mWaterPoint, pmsg->mWaterFriendly );
	resultWindow->SetRewardForce( pmsg->mWindPoint, pmsg->mWindFriendly );
	resultWindow->SetRewardForce( pmsg->mEarthPoint, pmsg->mEarthFriendly );

	resultWindow->SetReward( pmsg->mMoney, pmsg->mExp, pmsg->mSxp );
	resultWindow->ShowTop();

}

void cPVPManager::NetworkMsgParser( char* msg )
{
	MSGROOT* tempMsg = (MSGROOT*)msg;

	switch( tempMsg->Protocol )
	{
	case NM_PVP_DM_NOTICE_SYN:
		{
			MSG_SYN_PVP_DM_NOTICE* pmsg = (MSG_SYN_PVP_DM_NOTICE*)tempMsg;

			cStringT Message;
			Message.Format( GAMERESOURCEMAN->GetGameText( 838 ), pmsg->mLeftTime );
			CHATMANAGER->AddSystemMsg( eSYSTEM_PVP, Message.Cstr() );
		}
		break;
	case NM_PVP_DM_JOIN_SYN:
		{
			if( IsEnableBattle() == true )
			{
//				assert(0);
				return;
			}

			MSG_SYN_PVP_DM_JOIN* pmsg = (MSG_SYN_PVP_DM_JOIN*)tempMsg;

			mMinLevel = pmsg->mMinLevel;
			mMaxLevel = pmsg->mMaxLevel;

			GAMEUI->ShowDMMsgWindow( pmsg->mLeftTime );
		}
		break;
	case NM_PVP_DM_JOIN_RES:
		{
			MSG_PLAYERINFO* pmsg = (MSG_PLAYERINFO*)tempMsg;

			if( pmsg->ErrorCode == 0 )
			{
				STAGEMAN->SetMapIdx( pmsg->MapNum );
				STAGEMAN->ChangeStage( eStage_MapChange );
				PVPMAN->SetEnableBattle( true );

				/// 스테이지 변경후 HERO객체 생성
				OBJECTMANAGER->AddHeroFromServerMsg( pmsg );
			}
			else
			{
				assert(NULL);
			}

			/// 모달 처리
			UIMAN->ModalEventFromGameSystem( true );
		}
		break;
	case NM_PVP_DM_MEMBERIN_RES:
		{
			/// 동맹세력 분류
			MSG_RES_PVP_DM_MEMBERIN* pmsg = (MSG_RES_PVP_DM_MEMBERIN*)tempMsg;

			cDMScoreWindow* scoreWin = (cDMScoreWindow*)GAMEUI->GetDMScoreWindow();
			if( scoreWin )
			{
				scoreWin->SetTeamImage( pmsg->mFireForce, pmsg->mWaterForce, pmsg->mWindForce, pmsg->mEarthForce );
			}

			/// set member info
			for( unsigned int i=0; i<pmsg->mMemberCnt; i++ )
			{
				AddTeamPlayerInfo( &(pmsg->mMemberInfo[i]) );
			}
		}
		break;
	case NM_PVP_DM_MEMBERIN_SYN:
		{
			MSG_SYN_PVP_DM_MEMBERIN* pmsg = (MSG_SYN_PVP_DM_MEMBERIN*)tempMsg;

			AddTeamPlayerInfo( &(pmsg->mMemberInfo) );
		}
		break;
	case NM_PVP_DM_MEMBEROUT_SYN:
		{
			MSG_SYN_PVP_DM_MEMBEROUT* pmsg = (MSG_SYN_PVP_DM_MEMBEROUT*)tempMsg;

			DelTeamPlayerInfo( pmsg->mCharacterIdx );
		}
		break;
	case NM_PVP_DM_READY_SYN:
		{
			/// 1분 카운트 시작
			mBattleState = eBattleState_Ready;
			mFightLeftTime = PVP_DM_READY_TIME;
			mReadyPrintTime = PVP_DM_READY_PRINT_TIME;

			/// chat message
			cStringT Message;
			Message.Format( GAMERESOURCEMAN->GetGameText( 835 ), mFightLeftTime/1000 );
			CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, Message.Cstr() );
		}
		break;
	case NM_PVP_DM_NOTREADY_SYN:
		{
			/// 게임 진행 불가
			UIMAN->CreateModal(	eStage_Game,
				eMBEVENT_PVP_DM_NOTREADY, 
				(LPCTSTR)GAMERESOURCEMAN->GetGameText( 839 ),	// pvp out
				GAMERESOURCEMAN->GetGameText( 840 ),			// 알림
				eSKIN_OK
				, 0, PVP_DM_READY_OUT_TIME, false, true );
		}
		break;
	case NM_PVP_DM_FIGHT_SYN:
		{
			MSG_SYN_PVP_FIGHT* pmsg = (MSG_SYN_PVP_FIGHT*)msg;
			mBattleState = eBattleState_Fight;
			mReadyPrintTime = pmsg->mFightTime;			

			/// 전투 알림 시작
			cDMScoreWindow* win = GAMEUI->GetDMScoreWindow();
			if( win )
				win->ActiveTime();

			CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 822 ) );

			if( mStaticDoor1 != ULONG_MAX )
			{
				cStaticSceneNode* door1 = SCENEMAN->GetStaticSceneNode( mStaticDoor1 );
				if( door1 )
					door1->SetAlphaBlended( 0.0f );
			}

			if( mStaticDoor2 != ULONG_MAX )
			{
				cStaticSceneNode* door2 = SCENEMAN->GetStaticSceneNode( mStaticDoor2 );
				if( door2 )
					door2->SetAlphaBlended( 0.0f );
			}
		}
		break;
	case NM_PVP_DM_SCORE_SYN:
		{
			/// 점수 변동
			MSG_SYN_PVP_DM_SCORE* pmsg = (MSG_SYN_PVP_DM_SCORE*)msg;

			cDMScoreWindow* win = GAMEUI->GetDMScoreWindow();
			if( pmsg->mTeamType == ePVPDM_TEAMTYPE_A )
			{
				if( win )
					win->SetPointTeamA( pmsg->mTotalScore );
			}
			else
			{
				if( win )
					win->SetPointTeamB( pmsg->mTotalScore );
			}

			///
			if( HERO->GetPVPTeam() == pmsg->mTeamType )
				UpdateTeamPlayerInfo( pmsg->mPlayerIdx, pmsg->mPlayerScore, true );
			else
				UpdateTeamPlayerInfo( pmsg->mPlayerIdx, pmsg->mPlayerScore, false );
		}
		break;
	case NM_PVP_DM_LEADERSELECT_SYN:
		{
			MSG_SYN_PVP_DM_MEMBEROUT* pmsg = (MSG_SYN_PVP_DM_MEMBEROUT*)msg;
			mLeaderIdx = pmsg->mCharacterIdx;
		}
		break;
	case NM_PVP_DM_LEADERDIE_SYN:
		{
			CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 836 ) );

			mLeaderIdx = 0;
		}
		break;
	case NM_PVP_DM_ENEMYLEADERDIE_SYN:
		{
			CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 837 ) );
		}
		break;
	case NM_PVP_DM_WIN_SYN:
	case NM_PVP_DM_LOSE_SYN:
		{

			MSG_SYN_PVP_DM_FIGHTEND* pmsg = (MSG_SYN_PVP_DM_FIGHTEND*)msg;

			mBattleState = eBattleState_Result;

			/// 시간 정지
			cDMScoreWindow* win = GAMEUI->GetDMScoreWindow();
			if( win )
				win->DeActiveTime();

			/// Result window show
			OpenResult( pmsg, (tempMsg->Protocol == NM_PVP_DM_WIN_SYN) );

			/// 결과 출력
			if( tempMsg->Protocol == NM_PVP_DM_WIN_SYN )
			{
				/// 결투종료 - 승리
				switch( pmsg->mEndType )
				{
				case ePVPDM_ENDTYPE_POINT:				/// 포인트 달성
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 823 ) );
					break;
				case ePVPDM_ENDTYPE_TIME:				/// 시간 초과(포인트량)
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 825 ) );
					break;
				case ePVPDM_ENDTYPE_MEMBER:				/// 인원수
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 827 ) );
					break;
				case ePVPDM_ENDTYPE_LEADERDIE:			/// 수장 사망 횟수
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 829 ) );
					break;
				case ePVPDM_ENDTYPE_FASTJOIN:			/// 맵 입장 순서
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 831 ) );
					break;	
				}
			}
			else
			{
				/// 결투종료 - 패배
				switch( pmsg->mEndType )
				{
				case ePVPDM_ENDTYPE_POINT:				/// 포인트 달성
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 824 ) );
					break;
				case ePVPDM_ENDTYPE_TIME:				/// 시간 초과(포인트량)
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 826 ) );
					break;
				case ePVPDM_ENDTYPE_MEMBER:				/// 인원수
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 828 ) );
					break;
				case ePVPDM_ENDTYPE_LEADERDIE:			/// 수장 사망 횟수
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 830 ) );
					break;
				case ePVPDM_ENDTYPE_FASTJOIN:			/// 맵 입장 순서
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 832 ) );
					break;	
				}
			}
		}
		break;
	case NM_PVP_DM_END_SYN:
		{
			MSGROOT msg;
			msg.Category = NM_PVP;
			msg.Protocol = NM_PVP_DM_ENDACCEPT_REQ;
			NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
		}
	}
}
