#include "stdafx.h"
#include "BaseObject.h"
#include "ObjectManager.h"
#include "DynamicSceneNode.h"
#include "SceneManager.h"

#include "WorldManager.h"
#include "CameraManager.h"
#include "StatusCalc_Client.h"
#include "ChatManager.h"
#include "DamagePrintManager.h"

#include "SkillManager.h"
#include "Hero.h"
#include "GameUIManager.h"
#include "TargetWindow.h"
#include "PartyManager.h"

cBaseObject::cBaseObject( unsigned char type )
: mpObjectSceneNode(0)
, mObjectType(type)
{
	mTarget.type = eOBJECTTYPE_NONE;
	mTarget.index = 0;

	mReadyUseSkill = true;

	mStatureValue = 0.0f;

	mIdleTime = 0;
	mRevisionEventTime = 0.0f;
}

cBaseObject::~cBaseObject()
{
	RemoveObjectSceneNode();

	ClearAllBuff();
	ClearAllDeBuff();
}

cBaseObject* cBaseObject::GetTargetObject()
{
	return OBJECTMAN->GetObject( mTarget.type, mTarget.index );
}

void cBaseObject::SetTargetObject( unsigned char type, unsigned long idx )
{
	mTarget.type = type;
	mTarget.index = idx;
}


/// buff 처리
void cBaseObject::AddBuff( unsigned long uniqueIdx, cInfluenceObject* p )
{
	if( p == 0 )
		return;

	if( mBuffMap.Insert( uniqueIdx, p ) == false )
	{
		assert(0);
		return;
	}

	if( HERO->GetTargetObject() == this )
	{
		cTargetWindow* targetWindow = GAMEUI->GetTargetWindow();
		if( targetWindow )
		{
			/// 모든 버프류 삽입( 버프, 디버프 내부 구별 )
			targetWindow->AddBuff( uniqueIdx, p->GetInfluenceIdx() );
		}
	}
}

void cBaseObject::DelBuff( unsigned long uniqueIdx )
{
	mBuffMap.Erase( uniqueIdx );

	/// 대상타겟이 동일하면 버프아이콘 삭제
	if( HERO->GetTargetObject() == this )
	{
		cTargetWindow* targetWindow = GAMEUI->GetTargetWindow();
		if( targetWindow )
		{
			targetWindow->DelBuff( uniqueIdx );
		}
	}
}

void cBaseObject::AddDeBuff( unsigned long uniqueIdx, cInfluenceObject* p )
{
	if( p == 0 )
		return;

	if( mDeBuffMap.Insert( uniqueIdx, p ) == false )
	{
		assert(0);
		return;
	}

	if( HERO->GetTargetObject() == this )
	{
		cTargetWindow* targetWindow = GAMEUI->GetTargetWindow();
		if( targetWindow )
		{
			/// 모든 버프류 삽입( 버프, 디버프 내부 구별 )
			targetWindow->AddBuff( uniqueIdx, p->GetInfluenceIdx() );
		}
	}
}

void cBaseObject::DelDeBuff( unsigned long uniqueIdx )
{
	mDeBuffMap.Erase( uniqueIdx );

	/// 대상타겟이 동일하면 버프아이콘 삭제
	if( HERO->GetTargetObject() == this )
	{
		cTargetWindow* targetWindow = GAMEUI->GetTargetWindow();
		if( targetWindow )
		{
			targetWindow->DelDeBuff( uniqueIdx );
		}
	}
}

void cBaseObject::RemoveObjectSceneNode()
{
	try {
		if( mpObjectSceneNode )
		{
			/// 등록된 그래픽 객체 삭제
			SCENEMAN->DestroyDynamic( mpObjectSceneNode );
			mpObjectSceneNode = NULL;
		}
	} catch(...){
		GameErrorLog( "cBaseObject::RemoveObjectSceneNode %d, %d", GetObjectID(), GetObjectType() );
		throw;
	}
}

cEffectSceneNode* cBaseObject::SetLinkdEffect( unsigned int num, const char* nif, NiTransform* trans, bool bLoop, bool bFollow ) 
{ 
	if( ::strlen(nif) == 0 )
		return 0;

	return mpObjectSceneNode->LinkEffect( num, nif, trans, bLoop, bFollow ); 
}

cEffectSceneNode* cBaseObject::SetLinkdDamage( unsigned int num, const char* nif, NiTransform* trans, bool IsMiss, bool zFalse )
{
	if( mpObjectSceneNode && mpObjectSceneNode->IsViewNode() == false )
		return 0;

	if( ::strlen(nif) == 0 )
		return 0;

	return mpObjectSceneNode->LinkDamage( num, nif, trans, IsMiss, zFalse ); 
}

/*
bool cBaseObject::IsLinkedEffect( cEffectSceneNode* pNode )
{
	if( mpObjectSceneNode == 0 )
	{
		assert(0);
		return false;
	}

	return mpObjectSceneNode->IsLinkedEffect( pNode );
}
*/

cSoundSceneNode* cBaseObject::SetLinkdSound( unsigned long soundIdx, bool bLoop )
{
	if( mpObjectSceneNode == 0 )
	{
		assert(0);
		return false;
	}

	return mpObjectSceneNode->LinkSound( soundIdx, bLoop );
}

/*
bool cBaseObject::IsLinkedSound( cSoundSceneNode* pNode )
{
	if( mpObjectSceneNode == 0 )
		return false;

	return mpObjectSceneNode->IsLinkedSound( pNode );
}
*/

float cBaseObject::GetXPos()
{
	assert(mpObjectSceneNode);
	return mpObjectSceneNode->GetTranslate().x;
}

float cBaseObject::GetYPos()
{
	assert(mpObjectSceneNode);
	return mpObjectSceneNode->GetTranslate().y;
}

float cBaseObject::GetZPos()
{
	assert(mpObjectSceneNode);
	return mpObjectSceneNode->GetTranslate().z;
}

NiPoint3 cBaseObject::GetPos()
{
	assert(mpObjectSceneNode);
	return mpObjectSceneNode->GetTranslate();
}

void cBaseObject::SetPos( NiPoint3& pos )
{
	assert(mpObjectSceneNode);
	mpObjectSceneNode->SetTranslate( pos );
}

void cBaseObject::FixPos( float x, float y, bool resetCamera )
{
	NiPoint3 oldPos;
	oldPos = GetPos();
	oldPos.z = 0.0f;

	NiPoint3 newPos;
	newPos.x = x;
	newPos.y = y;
	newPos.z = 0.0f;

	if( (oldPos - newPos).Length() > SYNC_MOVE_RANGE )
	{
		if( WORLDMAN->CalcHeight( &newPos.z, newPos.x, newPos.y ) )
		{		
			SetPos( newPos );
			cCamera* cam = CAMERAMAN->GetCurrent();

			if( resetCamera && cam )
			{
				cam->ResetLookAt( newPos );
			}

			//TCHAR tempmsg[255] = {0,};
			//if( mObjectType == eOBJECTTYPE_MONSTER )
			//	_stprintf( tempmsg, _T("\n몬스터 좌표보간[%.0f,%.0f] => [%.0f,%.0f]"), oldPos.x, oldPos.y, newPos.x, newPos.y );
			//else if( mObjectType == eOBJECTTYPE_PLAYER )
			//	_stprintf( tempmsg, _T("\n플레이어 좌표보간[%.0f,%.0f] => [%.0f,%.0f]"), oldPos.x, oldPos.y, newPos.x, newPos.y );
			//else if( mObjectType == eOBJECTTYPE_HERO )
			//	_stprintf( tempmsg, _T("\n히어로 좌표보간[%.0f,%.0f] => [%.0f,%.0f]"), oldPos.x, oldPos.y, newPos.x, newPos.y );
			//OutputDebugString( tempmsg );
		}
		else
		{
			assert(NULL);
			return;
		}
	}

}

void cBaseObject::SetPos( float x, float y, float z )
{
	NiPoint3 pos = NiPoint3(x, y, z);
	SetPos( pos );
}

NiMatrix3 cBaseObject::GetModelRot() 
{ 
	if( mpObjectSceneNode )
		return mpObjectSceneNode->GetRotate();
	else
		return NiMatrix3::IDENTITY;
}

bool cBaseObject::GetDummyPos( unsigned int dummyId, NiPoint3& pos )
{
	if( mpObjectSceneNode == 0 )
	{
		assert(0);
		return false;
	}

	NiAVObject* pObj = NiDynamicCast( NiAVObject, mpObjectSceneNode->GetDummyObject( dummyId ) );
	if( pObj )
	{
		pos = pObj->GetWorldTransform().m_Translate;
		return true;
	}
	return false;
}

void cBaseObject::UpdateAnimationSpeed(float val)
{
	assert(mpObjectSceneNode);
	mpObjectSceneNode->UpdateAniScaleFactor( val );
}

float cBaseObject::GetAnimationSpeed()
{
	if( mpObjectSceneNode )
		return mpObjectSceneNode->GetAniScaleFactor();

	return 1.0f;
}


/// 이 함수는 skillobject에서만 호출 된다.
void cBaseObject::UpdateSkillAnimation( unsigned int aniIdx, bool /*checkWeapon*/ )
{
	if( aniIdx == UINT_MAX )
		return;

	assert(mpObjectSceneNode);
	if( mpObjectSceneNode->UpdateTargetAnimation( aniIdx ) == false )
	{
		//assert(0 && "Not have animation");
		if( IsReadyUseSkill() == false )
		{
			SetReadyUseSkill( true );
			ResetState();
		}
	}
}

void cBaseObject::ApplyDamageDrama( unsigned int damage, unsigned int damageType, cBaseObject* pAttacker )
{
	bool heroOwner = false;
	if( GetObjectType() == eOBJECTTYPE_HERO )
	{
		heroOwner = true;
	}
	else
	{
		if( pAttacker && pAttacker->GetObjectType() == eOBJECTTYPE_HERO )
		{
			heroOwner = true;
		}
	}
	DAMAGEPRINTMAN->PrintDamage( this, damage, (eDAMAGEPRINT_TYPE)damageType, heroOwner );
}

void cBaseObject::SetOverFlag( bool over ) 
{ 
	mpObjectSceneNode->SetSelectLightFlag( over ); 
}

void cBaseObject::ClearAllBuff()
{
	cInfluenceMap::cIterator i = mBuffMap.Begin();
	cInfluenceMap::cIterator end = mBuffMap.End();

	for( ; i != end; ++i )
	{
		cInfluenceObject* p = (cInfluenceObject*)(*i).mSecond;
		if( p )
			SKILLMAN->DeleteInfluenceObject( p );
	}
	mBuffMap.Clear();
}

void cBaseObject::ClearAllDeBuff()
{
	cInfluenceMap::cIterator i = mDeBuffMap.Begin();
	cInfluenceMap::cIterator end = mDeBuffMap.End();

	for( ; i != end; ++i )
	{
		cInfluenceObject* p = (cInfluenceObject*)(*i).mSecond;
		if( p )
			SKILLMAN->DeleteInfluenceObject( p );
	}
	mDeBuffMap.Clear();
}

void cBaseObject::HPChange( sTargetDamageHP* damage, cBaseObject* attacker  )
{
	assert(0);
}

sTrailInfo* cBaseObject::CreateTrailEffect( cString str, unsigned long lifeTime, unsigned int link1, unsigned int link2, float lenPer, float factor )
{
	if( mpObjectSceneNode == 0 )
	{
		assert(0);
		return 0;
	}

	return mpObjectSceneNode->LinkTrailEffect( str, lifeTime, link1, link2, lenPer, factor );
}

void cBaseObject::DeleteTrailEffect( sTrailInfo* pInfo )
{
	mpObjectSceneNode->UnLinkTrailEffect( pInfo );
}

float cBaseObject::GetStatureValue()
{
	return mStatureValue * mpObjectSceneNode->GetWorldScale();
}

void cBaseObject::FadeOutObject()
{
	if( mpObjectSceneNode )
		mpObjectSceneNode->SetAlphaBlended( 0.01f );
}