/****************************************************************************************************

		MouseActions.cpp
		Copyright: (c) 2001 Eovia Corp. All rights reserved.

		Author:	Arnaud
		Date:	12/1/2004

****************************************************************************************************/

#include "MouseActions.h"


#include "COMUtilities.h"
#include "COMSafeUtilities.h"
#include "I3DEditorHostPart.h"
#include "I3dShFacetMesh.h"
#include "I3DShObject.h"
#include "IShUtilities.h"
#include "MCCountedPtrHelper.h"


#include "Modeler.h"
#include "SimpleModelerDef.h"
#include "PanePart.h"



TMoveMouseAction::TMoveMouseAction(TModeler* inModeler, TPanePart* inPane)
{
	fModeler	= inModeler;
	fPanePart	= inPane;
}


TMoveMouseAction::~TMoveMouseAction()
{
}


void TMoveMouseAction::Create(IShMouseAction** outAction, TModeler* inModeler, TPanePart* inPane)
{
	TMCCountedCreateHelper<IShMouseAction> result(outAction);
	result = new TMoveMouseAction(inModeler, inPane);
}


MCCOMErr TMoveMouseAction::GetName(TMCString& name)
{
	return gResourceUtilities->GetIndString(kRID_ModuleFamilyID, kModelerClassID, name, kModelerActionsNames, kModelerActionsNames_MoveMesh);
}


MCCOMErr TMoveMouseAction::Do()
{
	return MC_S_OK;
}

MCCOMErr TMoveMouseAction::Undo()
{
	if (fOriginalMesh)
	{
		I3DShFacetMeshPrimitive* meshPrimitive= fModeler->GetFacetMeshPrimitive();
		ThrowIfNil(meshPrimitive);
		
		meshPrimitive->SetNbrLOD(1);
		meshPrimitive->SetFacetMesh(0, 0.0f, fOriginalMesh);
		
		fModeler->GetPrimitive()->ChangedData();
	}

	return MC_S_OK;
}

MCCOMErr TMoveMouseAction::Redo()
{
	if (fModifiedMesh)
	{
		I3DShFacetMeshPrimitive* meshPrimitive= fModeler->GetFacetMeshPrimitive();
		ThrowIfNil(meshPrimitive);
		
		meshPrimitive->SetNbrLOD(1);
		meshPrimitive->SetFacetMesh(0, 0.0f, fModifiedMesh);
		
		fModeler->GetPrimitive()->ChangedData();
	}
	return MC_S_OK;
}


//Sends a ray from the given pixel of our pane part and intersect it with the active plane
void TMoveMouseAction::PixelToActivePlane(const TMCPoint& inPixelPos, TVector3& outPoint)
{
	outPoint= TVector3::kZero;

	IWorkingBoxPlane* activePlane= fModeler->GetWorkingPlane();
	if (MCVerify(activePlane))
	{
		TVector3 origin, direction;
		fPanePart->Get3DEditorHostPanePart()->PixelRay(inPixelPos, origin, direction);

		const TPlane* plane= activePlane->GetPlane();
		ThrowIfNil(plane);
		plane->ProjectAlong(origin, direction, outPoint);
	}
}


void TMoveMouseAction::Track(	IMCGraphicContext* gd, int16 stage, TMCPoint& first, 
								TMCPoint &prev, TMCPoint &cur,boolean moved, IShMouseAction**	nextAction)
{
	switch(stage)	
	{
	case kBeginTracking:	
		{
			ThrowIfNil(fModeler);
			fModeler->GetCurrentFacetMesh(0.0f, &fOriginalMesh);
			ThrowIfNil(fOriginalMesh);

			fModeler->BeginImmediateUpdate();
		}
		break;

		case kContinueTracking:	
		{
			if (moved)
			{
				fOriginalMesh->Clone(&fModifiedMesh);

				//This is not accurate as we don't select the mesh, 
				//but just use the relative deplacement over the active plane to move the whole mesh
				TVector3 firstPoint, curPoint;
				PixelToActivePlane(first, firstPoint);
				PixelToActivePlane(cur, curPoint);

				TVector3 deltaP= curPoint - firstPoint;

				TMCArray<TVector3>& vertices= fModifiedMesh->fVertices;
				const int32 verticesCount= vertices.GetElemCount();
				for (int32 vertexNdx= 0; vertexNdx < verticesCount; vertexNdx++)
				{
					vertices[vertexNdx] += deltaP;
				}

				//Note we should edit and render our own mesh and update the primitive when we're done tracking...
				I3DShFacetMeshPrimitive* meshPrimitive= fModeler->GetFacetMeshPrimitive();
				ThrowIfNil(meshPrimitive);

				meshPrimitive->SetNbrLOD(1);
				meshPrimitive->SetFacetMesh(0, 0.0f, fModifiedMesh);

				fModeler->GetPrimitive()->ChangedData();

				fModeler->PostImmediateUpdate(true);
			}
		}
		break;

		case kFinishTracking:	
		{
			fModeler->EndImmediateUpdate();
		}
		break;
	}

	TBasicMouseAction::Track(gd, stage, first, prev, cur, moved, nextAction);
}
