#include "AirPlane.h"
#include "ShadowApp.h"

#include "ShadowScene.h"

#include "DynOctTree.h"

AirPlane::AirPlane(ShadowScene* const pScene, CMesh* const mesh, const float size, const float speed) : MeshObject(pScene, mesh, DXMatrix::IDENTITY())
{
	m_Size = size;
	m_Speed = speed;

	m_RoutePos = 0;
	m_RouteDist = 0;
	m_LastWayPoint = NULL;

	Update();
}

AirPlane::~AirPlane(void)
{
	m_Route.Clear();
}

void AirPlane::Update(void)
{
	if(!m_Route.GetElementCount())
		return;

	if(!m_LastWayPoint)
		m_LastWayPoint = m_Route.GetHead();

	float dt = m_pScene->GetShadowApp()->GetClock().AnimMultiplier();
	m_RoutePos = fmod(m_RoutePos + dt * m_Speed, m_RouteDist);

	if(m_RoutePos < m_LastWayPoint->GetInfo()->Distance)
		m_LastWayPoint = m_Route.GetHead();

	ListElement<STWayPoint>* next = NULL;

	while(!next)
	{
		next = m_LastWayPoint->GetNext();
		if(!next)
		{
			next = m_Route.GetHead();

			if(m_RoutePos <= m_RouteDist)
				break;
		}
		else if(m_RoutePos <= next->GetInfo()->Distance)
		{
			break;
		}

		m_LastWayPoint = next;
		next = NULL;
	}

	float nextdist = m_LastWayPoint != m_Route.GetTail() ? next->GetInfo()->Distance : m_RouteDist;
	float s = (m_RoutePos - m_LastWayPoint->GetInfo()->Distance) / (nextdist - m_LastWayPoint->GetInfo()->Distance);
	
	if(s < 0 || s > 1)
		s = s;

	ListElement<STWayPoint>* v0 = m_LastWayPoint->GetPrev();
	if(!v0)
		v0 = m_Route.GetTail();
	ListElement<STWayPoint>* v1 = m_LastWayPoint;
	ListElement<STWayPoint>* v2 = next;
	ListElement<STWayPoint>* v3 = next->GetNext();
	if(!v3)
		v3 = m_Route.GetHead();

	DXVector3 pos;
	D3DXVec3CatmullRom(pos, v0->GetInfo()->Point, v1->GetInfo()->Point, v2->GetInfo()->Point, v3->GetInfo()->Point, s);

	//DXMatrix matTrans;
	//D3DXMatrixTranslation((D3DXMATRIX*)&matTrans, pos.x, pos.y, pos.z);

	DXMatrix matScale;
	D3DXMatrixScaling((D3DXMATRIX*)&matScale, m_Size, m_Size, m_Size);

	DXMatrix matRotate;
	D3DXMatrixRotationX((D3DXMATRIX*)&matRotate, D3DX_PI/2);

	DXVector3 lastpos(m_CombinedTransformation._41, m_CombinedTransformation._42, m_CombinedTransformation._43);
	
	DXVector3 dir = pos - lastpos;
	D3DXVec3Normalize(dir, dir);
	DXVector3 up(0,0,1);
	DXVector3 right;
	D3DXVec3Cross(right, up, dir);

	D3DXMatrixIdentity((D3DXMATRIX*)&m_matWorld);
	m_CombinedTransformation._11 = right.x;
	m_CombinedTransformation._12 = right.y;
	m_CombinedTransformation._13 = right.z;
	m_CombinedTransformation._21 = dir.x;
	m_CombinedTransformation._22 = dir.y;
	m_CombinedTransformation._23 = dir.z;
	m_CombinedTransformation._31 = up.x;
	m_CombinedTransformation._32 = up.y;
	m_CombinedTransformation._33 = up.z;
	m_CombinedTransformation._41 = pos.x;
	m_CombinedTransformation._42 = pos.y;
	m_CombinedTransformation._43 = pos.z;

	m_CombinedTransformation = matScale * matRotate * m_CombinedTransformation;
	m_SubTransformation = m_CombinedTransformation;

	m_Bound = m_Mesh->GetBound();
	D3DXVec3TransformCoord((D3DXVECTOR3*)&m_Bound.Center, (D3DXVECTOR3*)&m_Bound.Center, (D3DXMATRIX*)&m_CombinedTransformation);
 
	if (m_pSPTNode)
	{
		//DynOctTree* dot = dynamic_cast<DynOctTree*>(m_pScene->GetSpatialPartitioningTree());
		DynOctTree* dot = (DynOctTree*)m_pScene->GetSpatialPartitioningTree();
		if (dot)
		{
			dot->ObjectMoved(this);
		}
	}
}

/*
void AirPlane::Render(const bool depthmap)
{
	if(m_Mesh && m_Mesh->GetMesh() && m_FX && m_FX->IsCompiled())
	{
		if(depthmap)
		{
			m_FX->SetMatrix("SM_matWorld", m_matWorld);
			m_FX->SetMatrix("SM_matSM", m_App->GetShadowMapping()->GetSMMatrix());

			m_FX->SetTechnique("RenderShadowDepth");

			RENDERFX(m_FX,
				for( DWORD i=0; i<m_Mesh->GetMaterialCount(); i++ )
				{
					m_Mesh->GetMesh()->DrawSubset(i);
				}
			);
		}
		else
		{
			m_FX->SetMatrix("matViewProj", m_App->GetActiveCam()->GetViewProjMatrix());

			if(!m_App->UseDeferred())
			{
				m_FX->SetVector("LightColor", static_cast<DXVector4>(m_App->GetSunColor()));
				m_FX->SetVector("AmbientColor", static_cast<DXVector4>(m_App->GetAmbientColor()));
				m_FX->SetFloatArray("LightDir", (float*)&m_App->GetSunDir(), 3);

				//m_FX->SetMatrix("SM_matSMTex", m_App->GetShadowMapping()->GetSMTexMatrix());  
				m_FX->SetMatrix("SM_matSM", m_App->GetShadowMapping()->GetSMMatrix()); 
				m_FX->SetTexture("SM_ShadowMap",m_App->GetShadowMapping()->GetShadowMap()->GetSurface());  
				m_FX->SetFloat("SM_ShadowMapSize", m_App->GetShadowMapping()->GetShadowMapSize());  
			}

			m_FX->SetMatrix("matWorld", m_matWorld);

			m_FX->SetInt("TexFilter", D3DTEXF_LINEAR);
			m_FX->SetInt("TexAnisotropy", 1);
		
			for( DWORD i=0; i<m_Mesh->GetMaterialCount(); i++ )
			{
				if(m_Mesh->GetMaterials()[i].GetTexture() && m_Mesh->GetMaterials()[i].GetTexture()->GetSurface())
				{
					if(m_App->UseDeferred())
						m_FX->SetTechnique("RenderTexturedDS");
					else
						m_FX->SetTechnique("RenderTextured");
					
					m_FX->SetTexture("Texture", m_Mesh->GetMaterials()[i].GetTexture());
				}
				else
				{
					if(m_App->UseDeferred())
						m_FX->SetTechnique("RenderDS");
					else
						m_FX->SetTechnique("Render");
				}
				
				//m_FX->SetFloatArray("Ambient", (float*)&m_Mesh->GetMaterials()[i].GetAmbient(), 4);
				m_FX->SetFloatArray("Diffuse", (float*)&m_Mesh->GetMaterials()[i].GetDiffuse(), 4);
			
				RENDERFX(m_FX,
					m_Mesh->GetMesh()->DrawSubset(i);
				);
			}
		}
	}
}*/

void AirPlane::AddPoint(const DXVector3& point, const float declination)
{
	STWayPoint* wp = new STWayPoint();
	wp->Point =  point;
	wp->Declination = declination;

	float lastdist = 0;
	float segdist = 0;
	float finalsegdist = 0;
	DXVector3 last = point;
	if(m_Route.GetElementCount())
	{
		last = m_Route.GetTail()->GetInfo()->Point;
		lastdist = m_Route.GetTail()->GetInfo()->Distance;
		segdist = D3DXVec3Length((D3DXVECTOR3*)&(point - last));
		finalsegdist = D3DXVec3Length((D3DXVECTOR3*)&(point - m_Route.GetHead()->GetInfo()->Point));
	}
	
	wp->Distance = lastdist + segdist;
	m_Route.AddTail(wp, 0);

	m_RouteDist = lastdist + segdist + finalsegdist;
}