#ifndef __ANIMATION_MANAGER_H__
#define __ANIMATION_MANAGER_H__

/*
	Animation Sets
	-------------------
	Fairly self explanatory--this is a structure that contains data for a collection of animations.  The actual allocation/de-allocation
	of the structure is done by an Animator object, although the animation sets and animator objects themselves are managed by the AnimationManager.
	
	Each AnimationSet inherits from the AnimationSet structure.  The AnimationSet structure does not contain any methods,
	only member variables, as should each of its child structures.

	Animators
	--------------------
	Responsible for allocating, de-allocating, and computing vertices on a mesh.  Each Animator object inherits from the IAnimator interface,
	and is stored in a map based on a hash value. This hash value is returned by the Animator object.  By default, no animators are stored on the
	AnimationManager--these have to be set up using the registerAnimator method, presumably by the main Game object or somewhere similar.

	Animation Nodes
	-------------------
	The AnimationManager contains a list of header nodes per animator object.  New nodes can be allocated as needed by a mesh. 
	Each header node has an animation tree attached:

	Animation Tree:

	                         /----- Walk
	          /--- Jog    --|       (w=0.5)
	         /     (w=1.0)   \----- Run
	Header -|                       (w=0.5)
	         \
	          \--- Shoot
	               (w=1.0)


	On each update, the manager collapses each tree, calculating actual weights that will be used during calculation
	of vertices.  What results is a stack of nodes that each contain an animation:

	Animation Stack:
	
	+------------------+
	| Shoot (w=0.50)   |
	+------------------+
	| Walk  (w=0.25)   |
	+------------------+
	| Run   (w=0.25)   |
	+------------------+

	Each stack is passed to an Animator object which pops each animation, calculating vertex positions for rendering.  These stacks
	are stored on their respective header nodes.
*/


#include <string>
#include <map>

#include "Util/Singleton.h"
#include "Util/Hash.h"
#include "Records/AnimationSet.h"
#include "Records/AnimationNode.h"

class IAnimator;

class AnimationManager : public Singleton<AnimationManager>
{
public:

	typedef AnimationSet::Map AnimationSetMap;
	typedef AnimationSet::MapIterator AnimationSetIterator;

	typedef AnimationNode::List AnimationNodeList;
	typedef AnimationNode::ListIterator AnimationNodeIterator;

	typedef std::map<hash32,AnimationNodeList*> NodeListMap;
	typedef NodeListMap::iterator NodeListMapIterator;

	typedef std::map<hash32,IAnimator*> AnimatorMap;
	typedef AnimatorMap::iterator AnimatorIterator;

public:

	AnimationManager();
	~AnimationManager();

	int initiate();

	int update();

	int shutdown();

	// if animation set with correspondig filename is found, that animation set is returned,
	// otherwise, appropriate structure based on animatorHash argument is allocated, stored, then returned.
	// (the data variable is a structure specific to the animator object that will be doing the allocating.
	//  it will most likely be a structure that has already been loaded somewhere else to create a model.  For
	//  example, when creating an md2 animation set, data will be a pointer to an md2 structure containg file data.)
	AnimationSet *createAnimationSet(std::string fileName, hash32 animatorHash, void *data);

	// decreases animation set reference count, destroying it if reference count is 0
	void destroyAnimationSet(AnimationSet *set);

	// allocates an animation node for a mesh
	AnimationNode *createAnimationNode(AnimationNode *parent, Mesh *mesh, int flags, float weight);

	// deallocates an animation node and recursively destroys its chidlren
	void destroyAnimationNode(AnimationNode *node);

	// allocates/adds an animator to the animator map.
	// (an animator is only added if an animator with the same hash is not found.
	// over writing an animator is not allowed as it might disrupt an animation node list)
	template <class TYPE>
	int registerAnimator()
	{
		IAnimator *animator = new TYPE;
		hash32 hash = animator->getHash();
		pair<AnimatorIterator,bool> insertResult;
		int result = 1;

		insertResult = m_animators.insert( pair<hash32,IAnimator*>(hash,animator) );
		
		if(insertResult.second == false)
		{
			delete animator;
			result = 0;
		}
		
		else
			m_animationNodeLists[ hash ] = new AnimationNodeList();

		return result;
	}

private:

	// used by update to collapse trees attached to a list of header nodes
	void collapseNodes(AnimationNodeList *nodes); 

	// used by collapseNodes to collapse an individual tree attached to a header node
	void collapseTree(AnimationNode *header, float elapsed);

	// used by destroyAnimationNode to recursively destroy nodes
	void _destroyAnimationNode(AnimationNode *node);

private:

	// map of loaded animation sets
	AnimationSetMap m_animationSets;

	// map of node lists, each node in list is a header node, one list per animator object
	NodeListMap m_animationNodeLists;

	// map animator objects which responsible for allocation/de-allocation of a particular animation set,
	// as well as actual vertex calculation
	AnimatorMap m_animators;

};

#endif
