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


		#include "motion/scene_motion.h"
		#include "log/log.h"

		using namespace GS;
		using namespace GS::Core;
		using GS::NML::Tag;


//------------------------------------------------------------------------------
Motion				*SceneMotion::GetItemMotion(uint uid, bool create_if_missing)
{
	ListForeachPtr(ItemMotion *, m, item_motions)
		if	(m->uid == uid)
			return m->motion;

	if	(!create_if_missing)
		return NULL;

	ItemMotion *item_motion = new ItemMotion;
	if	(!item_motion)
		__ERR__(__LOG_E__ << "Failed to allocate item motion.\n", NULL)

	item_motion->uid = uid;
	item_motion->motion = new Motion;

	item_motions.Add(item_motion);
	return item_motion->motion;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				SceneMotion::Clone(const SceneMotion &src, const TimeRange &range, bool enforce_loop)
{
	// Clone item motions.
	item_motions.Clear();

	ListForeachPtr(ItemMotion *, m, src.item_motions)
	{
		ItemMotion *c = new ItemMotion;
		if	(c == NULL)
			continue;

		c->uid = m->uid;
		c->motion = new Motion;
		c->motion->Clone(*m->motion, range, enforce_loop);

		item_motions.Add(c);
	}
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
TimeRange			SceneMotion::GetTimeRange() const
{
	List <ItemMotion *> ::Item *i = item_motions.GetRoot();
	if	(i == NULL)
		return TimeRange();

	TimeRange range = i->Object()->motion->GetTimeRange();
	for	(i = i->Next(); i; i = i->Next())
		range = TimeRange::Union(range, i->Object()->motion->GetTimeRange());

	return range;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
bool				SceneMotion::FromMetaTag(Tag &tag, const Map <uint, uint> *uid_map)
{
	if	(tag.name != "SceneMotion")
		__ERR__(__LOG_E__ << "Could not parse scene motion, incorrect root tag (" << tag.name << ").\n", false)

	item_motions.Clear();

	// Parse root tags.
	NMLTagForeach(pt, tag)
	{
		if	(pt->name == "Name")
			name = pt->GetString();

		else if	(pt->name == "ItemMotions")
		{
			NMLTagForeach(it, *pt)
			{
				if	(it->name == "ItemMotion")
				{
					Tag *uid_tag = it->GetTypedTag("UId", Variant::VariantInteger),
						*motion_tag = it->GetTag("Motion");

					if	(uid_tag && motion_tag)
					{
						uint uid = uid_tag->GetUnsigned();
						if	(uid_map && !uid_map->HasKey(uid))
							continue;	// item got lost, don't load

						ItemMotion *item_motion = new ItemMotion;

						item_motion->uid = uid_map ? (*uid_map)[uid] : uid;
						item_motion->motion = new Motion;
						item_motion->motion->FromMetaTag(*motion_tag);

						item_motions.Add(item_motion);
					}
					else
						__LOG_W__ << "Mangled item motion tag.\n";
				}
			}
		}
		else
			__LOG_W__ << "Unknown tag '" << pt->name << "' in <SceneMotion>.\n";
	}
	return true;
}
Tag					*SceneMotion::AsMetaTag()
{
	Tag *root = new Tag("SceneMotion");
	if	(!root)
		__ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL)

	root->AddChild("Name", name);

	if	(Tag *pim = root->AddChild("ItemMotions"))
		ListForeachPtr(ItemMotion *, m, item_motions)
			if	(Tag *pm = pim->AddChild("ItemMotion"))
			{
				pm->AddChild("UId", m->uid);
				pm->AddChild(m->motion->AsMetaTag());
			}

	return root;
}
//------------------------------------------------------------------------------
