#include "stdafx.h"

#include "MW4GameEd.h"
#include "AddCommand.h"
#include "TransDlg.h"
#include <Adept\Player.hpp>
#include <Adept\Interface.hpp>
#include <Adept\Entity.hpp>
#include <Adept\EntityManager.hpp>
#include <Adept\Map.hpp>
#include <Adept\VideoRenderer.hpp>
#include <mw4\NavPoint.hpp>
#include <Adept\CameraComponent.hpp>
#include "InstanceWindow.h"
#include "DisplayWindow.h"
#include "OverviewWindow.h"
#include "EditorWaypoint.h"

extern CMW4GameEdApp theApp;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AddCommand::AddCommand(Entity *object)
				: Command()
{
	Check_Object(object);
	addedObject = object;

	Check_Pointer(theApp.instanceWindow);

	if (!object->IsDerivedFrom(EditorPathNode::DefaultData))
		theApp.instanceWindow->ResetInstanceLists();

	if (object->IsDerivedFrom(NavPoint::DefaultData))
	{
		NavPoint*node = Cast_Object(NavPoint*,object);
		node->SetToDisplay();
	}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AddCommand::~AddCommand()
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void 
	AddCommand::Execute()
{
	Move();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	AddCommand::Undo()
{
	Check_Object(addedObject);

	if (addedObject->IsDerivedFrom(EditorPathNode::DefaultData))
	{
		EditorPathNode* node;
		node = Cast_Object(EditorPathNode*,addedObject);

		node->pathSlot.GetCurrent()->pathSlot.GetCurrent()->ErasePoint(node->index);

		if (node->prevnode)
		{
			node->prevnode->m_PathLinkPointData[1] = node->prevnode->m_PathLinkPointData[0];
			node->prevnode->nextnode = NULL;
			node->prevnode->UpdateLinkPointData();
		}

		if(node->m_PathLinkLineCloud) 
		{
				Unregister_Pointer(node->m_PathLinkLineCloud);
				delete node->m_PathLinkLineCloud;
				node->m_PathLinkLineCloud=NULL;
		}

	if(node->pathSlot.GetCurrent()->pathSlot.GetCurrent()->pathPoints.size() == 0)
		{
			Check_Object(NameTable::Instance);
			NameTable::Instance->RemoveEntry(node->pathSlot.GetCurrent()->objectID);
Map::Instance->RemoveChild(node->pathSlot.GetCurrent()->pathSlot.GetCurrent());
			NameTable::Instance->RemoveEntry(node->pathSlot.GetCurrent()->pathSlot.GetCurrent()->objectID);
			theApp.instanceWindow->RemoveInstance(node->pathSlot.GetCurrent());
			theApp.instanceWindow->RemoveInstance(node->pathSlot.GetCurrent()->pathSlot.GetCurrent());
			node->pathSlot.GetCurrent()->pathSlot.GetCurrent()->SentenceToDeathRow();
			node->pathSlot.GetCurrent()->SentenceToDeathRow();
		NameTable::Instance->IsValid();

		}

		node->SentenceToDeathRow();

		theApp.m_CurPath = NULL;
	}
	else if (addedObject->IsDerivedFrom(EditorLatticeNode::DefaultData))
	{
		EditorLatticeNode* latticeNode;
		latticeNode = Cast_Object(EditorLatticeNode*,addedObject);
		if (latticeNode->railNode)
			MW4AI::g_MissionGraph->DeleteNode(latticeNode->railNode->ID());
	}
	else if (addedObject->IsDerivedFrom(EditorDropNode::DefaultData))
	{
		EditorDropNode* node;
		node = Cast_Object(EditorDropNode*,addedObject);
		Check_Object(NameTable::Instance);
		NameTable::Instance->RemoveEntry(node->dropZone->objectID);
		NameTable::Instance->IsValid();

		node->dropZone->SentenceToDeathRow();
	}
	else if (addedObject->IsDerivedFrom(EditorDropZonePoint::DefaultData))
	{
		EditorDropZonePoint* node;
		node = Cast_Object(EditorDropZonePoint*,addedObject);
		node->dropNode->pointChain.Remove(node);
		node->dropNode->UpdatePoints();
	}
	else if (addedObject->IsDerivedFrom(EditorObjectiveMarker::DefaultData))
	{
		theApp.m_NumObjectives--;
		EditorObjectiveMarker* node;
		node = Cast_Object(EditorObjectiveMarker*,addedObject);
		Check_Object(NameTable::Instance);
		NameTable::Instance->RemoveEntry(node->objective->objectID);
		NameTable::Instance->IsValid();
		node->objective->SentenceToDeathRow();
	}
	else if (addedObject->IsDerivedFrom(EditorCameraShip::DefaultData))
	{
		EditorCameraShip* node;
		node = Cast_Object(EditorCameraShip*,addedObject);
		Check_Object(NameTable::Instance);
		NameTable::Instance->RemoveEntry(node->cameraShip->objectID);
		Verify(NameTable::Instance->IsValid());
		node->cameraShip->SentenceToDeathRow();
		Map::Instance->RemoveChild(node->cameraShip);	
	}

	Check_Object(NameTable::Instance);
	Entity *parent=addedObject->GetParentEntity();

	parent->RemoveChild(addedObject);
	NameTable::Instance->RemoveEntry(addedObject->objectID);
	NameTable::Instance->IsValid();
	Check_Pointer(theApp.instanceWindow);
//	theApp.instanceWindow->RemoveInstance(addedObject);
	theApp.instanceWindow->ResetInstanceLists();

	theApp.overviewWindow->DrawWindow();

}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	AddCommand::Move()
{
	Check_Object(addedObject);
	Check_Object(Map::Instance);
	Check_Pointer(this);

	Point3D	target_in_world;
	YawPitchRoll current_rotation;
	LinearMatrix4D new_local_to_world = LinearMatrix4D::Identity;
	Point3D translation = Point3D::Identity, lastPoint;

	lastPoint = addedObject->GetLocalToWorld();

	int x_down = GetAsyncKeyState(KEY_X) & 0x8000;
	int y_down = GetAsyncKeyState(KEY_Y) & 0x8000;
	int z_down = GetAsyncKeyState(KEY_Z) & 0x8000;

	Check_Object(Player::Instance);
	Check_Object(Player::Instance->playerInterface);
	Entity *reticule;
	reticule = Player::Instance->playerInterface->reticuleEntity.GetCurrent();
	if(reticule && reticule == Map::Instance)
	{
		Point3D world_offset = Player::Instance->playerInterface->reticuleOffset; 
		LinearMatrix4D new_local_to_parent = LinearMatrix4D::Identity;
		new_local_to_parent.Multiply(reticule->GetLocalToParent(), world_offset);
		translation = new_local_to_parent;

		if (theApp.gridOn)
			theApp.GetGridCoords(translation);
	}
	else if (!y_down)
		return;		// must be pointing at the sky

	bool x_blocked = false, y_blocked = true, z_blocked = false;

	if (x_down || y_down || z_down)
	{
		x_blocked = !x_down;
		y_blocked = !y_down;
		z_blocked = !z_down;
	}

	if (x_blocked)
		translation.x = lastPoint.x;
	if (z_blocked)
		translation.z = lastPoint.z;

	if (!y_blocked)
	{
		Vector2DOf<Scalar> cursor;
		gos_GetMouseInfo(&cursor.x, &cursor.y, NULL, NULL, NULL, NULL);

		// Clean out the interface data

		Check_Object(VideoRenderer::Instance);
		EntityComponentWeb *web =
			Cast_Object(EntityComponentWeb*,VideoRenderer::Instance->GetSceneCamera()->GetComponentWeb());
		Interface *intface = Cast_Object(Interface*, web->GetEntity());
		intface->reticuleEntity.Remove();

		// Figure out the eyeline

		Line3D world_line;
		VideoRenderer::Instance->GetSceneCamera()->ComputeEyeLine(&world_line, cursor);

		Point3D point,y_offset;
		point = addedObject->GetLocalToWorld();
		Vector3D vector(world_line.m_direction.x,0,world_line.m_direction.z);
		Normal3D plane_normal;
		plane_normal.Normalize(vector);

		Stuff::Plane plane(plane_normal,plane_normal * point);

		Scalar axis;
		Scalar length = world_line.GetDistanceTo(plane,&axis);
		world_line.Project(length,&y_offset);

		translation.y = y_offset.y;
	}

	current_rotation = addedObject->GetLocalToParent();

	new_local_to_world.BuildTranslation(translation);
	new_local_to_world.BuildRotation(current_rotation);

	addedObject->SetNewLocalToParent(new_local_to_world);
	addedObject->SyncMatrices(true);
//	EntityManager::Instance->RequestPostCollisionExecution(addedObject);
	Map::Instance->UpdateZone(addedObject);

	if (addedObject->GetCollisionMask() == Entity::EditorIsMovingFlag)
	{
		if (addedObject->IsMultiZone())
			addedObject->GetElement()->SetCallbackIndex(ElementRenderer::Element::DrawRedBounds);
		else if (addedObject->IsMultiTile())
			addedObject->GetElement()->SetCallbackIndex(ElementRenderer::Element::DrawYellowBounds);
		else
			addedObject->GetElement()->SetCallbackIndex(ElementRenderer::Element::DrawGreenBounds);
	}
	else
		addedObject->GetElement()->SetCallbackIndex(ElementRenderer::Element::DrawGreenBounds);

	if (addedObject->IsDerivedFrom(EditorLatticeNode::DefaultData))
	{
		EditorLatticeNode* node;
		node = Cast_Object(EditorLatticeNode*,addedObject);
		target_in_world = new_local_to_world;
		node->railNode->Location(target_in_world);
		node->railNode->UpdateRadiusPointData();
	}
	else if (addedObject->IsDerivedFrom(EditorPathNode::DefaultData))
	{
		EditorPathNode* node;
		node = Cast_Object(EditorPathNode*,addedObject);
		target_in_world = new_local_to_world;
		Check_Object(node->pathSlot.GetCurrent());
		node->pathSlot.GetCurrent()->pathSlot.GetCurrent()->pathPoints[node->index] = target_in_world;
		node->UpdateLinkPointData();
		node->SetLinkColor(Stuff::RGBAColor(1.0f,1.0f,0.0f,0.0f));
	}
	else if (addedObject->IsDerivedFrom(EditorDropNode::DefaultData))
	{
		EditorDropNode* node;
		node = Cast_Object(EditorDropNode*,addedObject);
		node->dropZone->SetNewLocalToParent(new_local_to_world);
		node->dropZone->SyncMatrices(true);
	}
	else if (addedObject->IsDerivedFrom(EditorDropZonePoint::DefaultData))
	{
		EditorDropZonePoint* node;
		node = Cast_Object(EditorDropZonePoint*,addedObject);
		node->SetNewLocalToParent(new_local_to_world);
		node->SyncMatrices(true);
		node->UpdateLinkPointData();

		Point3D newPoint;
		newPoint = new_local_to_world;
		node->offset = node->dropNode->GetLocalToWorld();
		node->offset -=  newPoint;

		node->dropNode->UpdatePoints();
	}
	else if (addedObject->IsDerivedFrom(EditorObjectiveMarker::DefaultData))
	{
		EditorObjectiveMarker* node;
		node = Cast_Object(EditorObjectiveMarker*,addedObject);
		node->objective->SetNewLocalToParent(new_local_to_world);
		node->objective->SyncMatrices(true);
	}
	else if (addedObject->IsDerivedFrom(EditorPointLight::DefaultData) ||
			 addedObject->IsDerivedFrom(EditorSpotLight::DefaultData))
	{
		EditorLight* light;
		light = Cast_Object(EditorLight*,addedObject);

		light->SetLightToWorldMatrix(light->GetLocalToWorld());
	}
	else if (addedObject->IsDerivedFrom(EditorCameraShip::DefaultData))
	{
		EditorCameraShip* node;
		node = Cast_Object(EditorCameraShip*,addedObject);
		node->cameraShip->SetNewLocalToParent(new_local_to_world);
		node->cameraShip->SyncMatrices(true);
	}
}

