/* -----------------------------------------------------------------------------
	GSFramework
	Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */


		#include "scene3d/mitem.h"
		#include "scene3d/mterrain.h"
		#include "scene3d/scene_ace_manager.h"
		#include "scene3d/item_automated_property_provider.h"
		#include "scene3d/mitem_event_interface.h"
		#include "scene3d/mitem_scripted_object.h"
		#include "scene3d/scene_message.h"
		#include "automation/automation_player.h"
		#include "script/script_engine_types.h"
		#include "rand/rand.h"

		using namespace GS::S3D;


//------------------------------------------------------------------------------
bool				MItem::ExecCommand(GS::ACE::Command *cmd, float dt)
{
	float k = dt / cmd->duration_left;
	Core::Item *i = GetBaseItem();

	switch (cmd->code)
	{
		case ACESN_toposition:
			i->SetPosition(i->GetPosition() + (Vector4(cmd->parm[0], cmd->parm[1], cmd->parm[2]) - i->GetPosition()) * k);
			return true;

		case ACESN_tooffset:
		{
			Matrix4 offset = i->GetPivot();
			offset.m[0][3] += (cmd->parm[0] - offset.m[0][3]) * k;
			offset.m[1][3] += (cmd->parm[1] - offset.m[1][3]) * k;
			offset.m[2][3] += (cmd->parm[2] - offset.m[2][3]) * k;
			i->SetPivot(offset);
		}
		return true;

		case ACESN_offsetposition:
			k = dt / cmd->duration;
			i->SetPosition(i->GetPosition() + Vector4(cmd->parm[0], cmd->parm[1], cmd->parm[2]) * k);
			return true;

		case ACESN_toscale:
			i->SetScale(i->GetScale() + (Vector4(cmd->parm[0], cmd->parm[1], cmd->parm[2]) - i->GetScale()) * k);
			return true;

		case ACESN_torotation:
			i->SetRotation(i->GetRotation() + (Vector4(Units::Deg(cmd->parm[0]), Units::Deg(cmd->parm[1]), Units::Deg(cmd->parm[2])) - i->GetRotation()) * k);
			return true;

		case ACESN_toalpha:
			i->opacity = Types::Clamp(i->opacity + Types::Clamp(i->opacity + (cmd->parm[0] - i->opacity) * k));
			return true;
	}
	return ACE::Unit::ExecCommand(cmd, dt);
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				MItem::SetInitialTransformation()
{
	// Note: We do not want to snapshot the pivot here.
	initial_matrix = GetBaseItem()->GetPivot().InversedFast() * GetBaseItem()->GetLocalMatrix();
	initial_state_set = true;
}
void				MItem::ResetToInitialTransformation()
{
	if	(initial_state_set)
		GetBaseItem()->SnapshotTransformation(initial_matrix, true);
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				MItem::Update(const GS::Time &dt)
{
	automation_player->Evaluate(dt);
	ACEManager::Get()->UpdateACEUnit(this, dt.toSec());
}
void				MItem::Setup(PhysicWorld *physic_world)
{
	item_event->OnSetup(this);

	// [EJ] must be done here for the time being as MItem base class cannot resolve the Item class.
	if	(automation_player->property_provider.IsNull())
		automation_player->property_provider = new Automation::ItemPropertyProvider(GetBaseItem());

	// Setup physics.
	if	(physic_world && physic_item)
	{
		if	(GetItemType() == MTerrain::GetMItemClassType())
			if	(MTerrain *t = (MTerrain *)this)
			{
				// If the terrain physic item has an heightmap shape, link it to our heightmap.
				ListForeachPtr(PhysicShape *, shape, physic_item_desc.shape_list)
					if	(shape->GetType() == PhysicShape::TypeHeightmap)
						shape->Set(t->GetHeightmap(), t->GetHeightmapPitch(), t->GetHeightmapHeight(), t->GetUnit());
			}

		physic_item->SetScale(GetBaseItem()->GetScale());
		physic_item->SetupBody(physic_item_desc, physic_world);
	}

	item_event->OnSetupDone(this);
}

void				MItem::ForceUpdateMassShapePhysic(PhysicWorld *physic_world)
{
	// update mass physics.
	if (physic_world && physic_item)
	{
		physic_item->ForceUpdateMassShapePhysic(physic_item_desc, physic_world);
	}
}


void				MItem::Reset()
{
	item_event->OnReset(this);

	// Update matrix.
	if	(physic_item)
	{
		physic_item->ResetBody();
		physic_item->SetMatrix(GetBaseItem()->GetMatrix());
	}
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
MItem::MItem()
{
	uid = uint(~0);

	global_alpha = 1.f;
	mitem_flags.Set(Flag_IsActive);

	initial_state_set = false;
	initial_matrix = Matrix4::IdentityMatrix();

	priority = 0.5;

	item_event = new IItemEvent;
	automation_player = new GS::Automation::Player;
}
//------------------------------------------------------------------------------
