#include "stdafx.h"
#include "gamesrv.h"
#include "PVPManager.h"


cPVPManager* cPVPManager::mpPVPManager = NULL;


cPVPManager::cPVPManager()
{
	if(mpPVPManager)
	{
		MessageBox(NULL,"cSkillManager : 이 클래스는 객체가 유일한객체(singleton)이어야 합니다.\
			이전 객체를 사용하던지 이전 객체를 지우고 생성하십시오.","경고",MB_OK);
	}
	else
	{
		mpPVPManager = this;
	}

	mNoticeCount = 0;
}


cPVPManager::~cPVPManager()
{
	Release();
}


bool cPVPManager::Init()
{
	mDMObjectPool.Reserve(100,10);
	mStartTime = NETWORK2->GetAccumTime() + PVP_DM_NEWGAME_TIME;
	mProcess = ePVPPROCESS_WAIT;

	NETWORK2->PostPVPStatus( _E_PVP_CLOSED_ );

	return true;
}


void cPVPManager::Release()
{
	cPHashMap::cIterator start = mDMMap.Begin();
	cPHashMap::cIterator end = mDMMap.End();

	NETWORK2->PostPVPStatus( _E_PVP_CLOSING_ );

	cDeathMatchObject* pDM = NULL;
	while( start != end )
	{
		pDM = (cDeathMatchObject*)(*start++).mSecond;
		SAFE_DELETE( pDM );
	}
	mDMMap.Clear();
}


void cPVPManager::Process( unsigned long elapsedTime, unsigned long accumTime )
{
	/// pvp 진행상태가 아니면 리턴한다.
	switch( mProcess )
	{
	case ePVPPROCESS_WAIT:
		{
			if( mStartTime <= accumTime )
			{
				/// 공지 발송 시작 설정
				mProcess = ePVPPROCESS_NOTICE;
				/// 공지발송 끝나는 시간
				mNextEventTime = accumTime + PVP_DM_NOTICE_TIME;

				mNoticeCount = PVP_DM_NOTICE_TIME / MINUTE;
				mNoticeSendTime = 0;

				/// 다음 시작시간 설정
				mStartTime += PVP_DM_NEWGAME_TIME;

				NETWORK2->PostPvPNotice( mNoticeCount );
				mDMObjectIdx = 0;				
			}
			else
				return;
		}
		break;
	case ePVPPROCESS_NOTICE:
		{
			if( mNextEventTime <= accumTime )
			{
				/// 공지끝 - 레디 상태 설정
				NETWORK2->PostPVPStatus( _E_PVP_RUNABLE_ );
				mProcess = ePVPPROCESS_OBJECTRUN_OPEN;
				mNextEventTime = accumTime + PVP_DM_JOIN_TIME;
			}
			else
			{
				/// pvp 공지 발송
				mNoticeSendTime += elapsedTime;
				if( mNoticeSendTime > MINUTE )
				{
					mNoticeCount--;
					mNoticeSendTime = mNoticeSendTime-MINUTE;
					NETWORK2->PostPvPNotice( mNoticeCount );
				}
			}
		}
		break;
	case ePVPPROCESS_OBJECTRUN_OPEN:
		{
			ObjectProcess( elapsedTime, accumTime );

			if( mNextEventTime <= accumTime )
			{
				Ready();
				NETWORK2->PostPVPStatus( _E_PVP_RUNNING_ );
				mProcess = ePVPPROCESS_OBJECTRUN_CLOSE;
			}
		}
		break;
	case ePVPPROCESS_OBJECTRUN_CLOSE:
		{
			ObjectProcess( elapsedTime, accumTime );

			/// 진행중인 객체가 없으면 상태 바꿈
			if( mDMMap.GetSize() == 0 )
			{
				mProcess = ePVPPROCESS_WAIT;
				NETWORK2->PostPVPStatus( _E_PVP_CLOSED_ );
			}
			//else
			//{
			//	/// 버그 체크 코드
			//	if( mStartTime <= accumTime )
			//	{
   //                 NETWORK2->PostServerEvent("cPVPManager::Process mStartTime[%d] <= accumTime[%d]", mStartTime, accumTime );
			//		mProcess = ePVPPROCESS_WAIT;
			//		NETWORK2->PostPVPStatus( _E_PVP_CLOSED_ );
			//	}
			//}
		}
		break;
	}
}


void cPVPManager::ObjectProcess( unsigned long elapsedTime, unsigned long accumTime )
{
	cDeathMatchObject* pDMObject = NULL;

	/// 개별 오브젝트 프로세스
	cPHashMap::cIterator start = mDMMap.Begin();
	cPHashMap::cIterator end = mDMMap.End();
	while( start != end )
	{
		pDMObject = (cDeathMatchObject*)(*start++).mSecond;
		if( pDMObject == NULL )
		{
			NETWORK2->PostServerEvent("cPVPManager::Process Process pDMObject == NULL");
			continue;
		}

		pDMObject->Process( elapsedTime, accumTime );
	}

	/// 삭제 예약 오브젝트 삭제
	for( unsigned long i = 0 ; i < mDelDMAry.GetSize() ; ++i )
	{
		pDMObject = (cDeathMatchObject*)mDMMap.GetAt( mDelDMAry[i] );
		if( pDMObject == NULL )
		{
			NETWORK2->PostServerEvent( "cPVPManager::Process mDelDMAry[i] pDMObject == NULL", i );
			continue;
		}

		SAFE_DELETE( pDMObject );
		mDMMap.Erase( mDelDMAry[i] );
	}
	mDelDMAry.Clear();	
}


unsigned char cPVPManager::JoinDeathMatch( unsigned long playerIdx, ePVPDM_TEAM_TYPE teamType, sDMInfo* pDMInfo )
{
	if( pDMInfo == NULL )
		return 0;

	cDeathMatchObject* pDMObject = NULL;

	unsigned char DMIdx = 0;
	cPHashMap::cIterator start = mDMMap.Begin();
	cPHashMap::cIterator end = mDMMap.End();
	while( start != end )
	{
		pDMObject = (cDeathMatchObject*)(*start++).mSecond;
		if( pDMObject == NULL )
		{
			NETWORK2->PostServerEvent("cPVPManager::JoinDeathMatch pDMObject == NULL");
			continue;
		}

		DMIdx = pDMObject->JoinTeam( playerIdx, teamType, pDMInfo );
		if( DMIdx != 0 )
			return DMIdx;
	}

	pDMObject = new cDeathMatchObject;
	++mDMObjectIdx;
	DMIdx = mDMObjectIdx;
	if( DMIdx > 50 )
	{
		NETWORK2->PostServerEvent("cPVPManager::JoinDeathMatch DMIdx > 50");
		return 0;
	}

	if( pDMObject->Init( DMIdx, pDMInfo ) == false )
	{
		delete pDMObject;
		NETWORK2->PostServerEvent("cPVPManager::JoinDeathMatch pDMObject->Init( %d ) == false", DMIdx );
		return 0;
	}

	if( mDMMap.Insert( DMIdx, pDMObject ) == false )
	{
		delete pDMObject;
		NETWORK2->PostServerEvent("cPVPManager::JoinDeathMatch mDMMap.Insert( %d ) == false", DMIdx );
		return 0;
	}

	DMIdx = pDMObject->JoinTeam( playerIdx, teamType, pDMInfo );
	if( DMIdx == 0 )
	{
		assert(NULL);
		delete pDMObject;
		NETWORK2->PostServerEvent("cPVPManager::JoinDeathMatch pDMObject->JoinTeam DMIdx == 0" );
		return 0;
	}

	return DMIdx;
}


void cPVPManager::Ready()
{
	cDeathMatchObject* pDMObject = NULL;

	cPHashMap::cIterator start = mDMMap.Begin();
	cPHashMap::cIterator end = mDMMap.End();
	while( start != end )
	{
		pDMObject = (cDeathMatchObject*)(*start++).mSecond;
		if( pDMObject == NULL )
		{
			NETWORK2->PostServerEvent("cPVPManager::Process Process pDMObject == NULL");
			continue;
		}

		pDMObject->Ready();
	}
}


void cPVPManager::DelAryInsertPVP( unsigned long pvpDMIdx )
{
	mDelDMAry.PushBack( pvpDMIdx );
}


void cPVPManager::MemberOut( unsigned long pvpIdx, unsigned long playerIdx, ePVPDM_TEAM_TYPE teamType )
{
	cDeathMatchObject* pPvPDM = (cDeathMatchObject*)mDMMap.GetAt( pvpIdx );
	if( pPvPDM != NULL )
	{
		pPvPDM->OutMember( playerIdx, teamType );
	}
}


bool cPVPManager::IsAttack( unsigned long playerIdx, unsigned long targetIdx )
{
	cPlayer* pAttacker = OBJECTMANAGER->GetPlayer( playerIdx );
	if( pAttacker == NULL )
		return false;

	cPlayer* pTarget = OBJECTMANAGER->GetPlayer( targetIdx );
	if( pTarget == NULL )
		return false;
 
	 cDeathMatchObject* pPvPDM = (cDeathMatchObject*)mDMMap.GetAt( pAttacker->GetPvPDMIdx() );
	 if( pPvPDM == NULL )
		return false;

	 if( pPvPDM->IsFight() == false )
		return false;

	if( pAttacker->GetPvPDMIdx() == pTarget->GetPvPDMIdx() && pAttacker->GetPvPDMTeam() != pTarget->GetPvPDMTeam() )
		return true;

	return false;
}