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


		#include "scene3d/group.h"
		#include "scene3d/mitem.h"
		#include "motion/motion_automation_source.h"
		#include "automation/automation_source_group.h"

		using namespace GS::Core;
		using namespace GS::S3D;


//------------------------------------------------------------------------------
bool				Group::AppendGroup(const Group &group)
{
	ListForeachPtr(MItem *, i, group.item_list)
		if	(!Add(i))
			return false;
	return true;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				Group::SetInvisible(bool v)
{
	ListForeachPtr(MItem *, i, item_list)
		i->GetBaseItem()->item_flags.Raise(ItemFlagInvisible, v);
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
bool				Group::IsMember(const MItem *i) const
{
	ListForeachPtr(MItem *, item, item_list)
		if	(item == i)
			return true;
	return false;
}
bool				Group::IsMember(const Group *g) const
{
	ListForeachPtr(Group *, group, group_list)
		if	(group == g)
			return true;
	return false;
}
void				Group::SetRootItem(MItem *i)
{
	if	(root)
		if	(Core::Item *base_root = root->GetBaseItem())
			ListForeachPtr(MItem *, item, item_list)
				if	(Core::Item *b = item->GetBaseItem())
					if	(b->GetParent() == base_root)
							b->SetParent(NULL);

	ListForeachPtr(MItem *, item, item_list)
		if	(Core::Item *b = item->GetBaseItem())
			if	(!b->GetParent())
				b->SetParent(i ? i->GetBaseItem() : NULL);

	root = i;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				Group::Offset(const GS::Matrix4 &m)
{
	ListForeachPtr(MItem *, item, item_list)
		if	(Core::Item *b = item->GetBaseItem())
			if	(!b->GetParent())
				b->SnapshotTransformation(m * b->GetMatrix());
}
void				Group::Translate(float x, float y, float z)
{
	Vector4 translation(x, y, z);
	ListForeachPtr(MItem *, item, item_list)
		if	(Core::Item *b = item->GetBaseItem())
			if	(!b->GetParent())
				b->SetPosition(b->GetPosition() + translation);
}
void				Group::Rotate(float x, float y, float z)
{
	Vector4 rotation(x, y, z);
	ListForeachPtr(MItem *, item, item_list)
		if	(Core::Item *b = item->GetBaseItem())
			if	(!b->GetParent())
				b->SetRotation(b->GetRotation() + rotation);
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
MItem				*Group::Item(const char *item_id) const
{
	String seek(item_id);
	ListForeachPtr(MItem *, item, item_list)
		if	(item->name == seek)
			return item;
	__ERR__(__LOG_W__ << "No item '" << item_id << "' in group '" << name << "'.\n", NULL)
}
MItem				*Group::ItemFromUid(uint uid) const
{
	ListForeachPtr(MItem *, item, item_list)
		if	(item->GetUid() == uid)
			return item;
	__ERR__(__LOG_W__ << "No item with uid '" << uid << "' in group '" << name << "'.\n", NULL)
}
Group				*Group::GetGroup(const char *_name) const
{
	ListForeachPtr(Group *, group, group_list)
		if	(group->name == _name)
			return group;
	__ERR__(__LOG_W__ << "Could not find group '" << _name << "' in group '" << name << "'.\n", NULL)
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
MItem				*Group::Add(MItem *i, bool block_duplicate)
{
	if	(!i || (block_duplicate && IsMember(i)))
		return NULL;

	item_list.Add(i);
	return i;
}
bool				Group::Remove(MItem *i)
{
	return item_list.Remove(i);
}
Group				*Group::Add(Group *g, bool block_duplicate)
{
	if	(!g || (block_duplicate && IsMember(g)))
		return NULL;

	group_list.Add(g);
	return g;
}
bool				Group::Remove(Group *g)
{	return group_list.Remove(g);	}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				Group::RenderSetup(GS::Core::ResourceFactories *f)
{
	ListForeachPtr(MItem *, i, item_list)
		if	(Core::Item *b = i->GetBaseItem())
			b->RenderSetup(f);
}
void				Group::Setup()
{
	ListForeachPtr(MItem *, i, item_list)
		i->Setup(NULL);
}
void				Group::Reset()
{
	ListForeachPtr(MItem *, i, item_list)
		i->Reset();
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				Group::SetMotion(const char *name, GS::Automation::SourceGroup **group, float blend, GS::Automation::Player::AddSourceMode mode, float weight)
{
	if	(group)
		*group = new Automation::SourceGroup;

	SceneMotion *scene_motion = NULL;

	ListForeachPtr(SceneMotion *, m, motion.motions)
		if	(m->name == name)
		{
			scene_motion = m;
			break;
		}

	if	(scene_motion)
	{
		// Start item motions.
		ListForeachPtr(SceneMotion::ItemMotion *, m, scene_motion->item_motions)
			if	(MItem *i = ItemFromUid(m->uid))
				i->automation_player->StartAutomation(new Automation::MotionSource(m->motion, group ? *group : NULL), blend, mode, weight);
	}
	else
		ListForeachPtr(MItem *, i, item_list)
			if	(Motion *motion = i->automation_player->GetMotion(name))
				i->automation_player->StartAutomation(new Automation::MotionSource(motion, *group), blend, mode, weight);
}
//------------------------------------------------------------------------------
