/*
    Copyright (C) 2004 by Jorrit Tyberghein
                          Hristo Hristov
                          Boyan Hristov
                          Vladimir Ivanov
                          Simeon Ivanov

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifndef __CS_GENMESHSKELANIM_H__
#define __CS_GENMESHSKELANIM_H__

#include "csgeom/quaternion.h"
#include "csgeom/transfrm.h"
#include "csgeom/vector3.h"
#include "csutil/array.h"
#include "csutil/cscolor.h"
#include "csutil/csstring.h"
#include "csutil/flags.h"
#include "csutil/hash.h"
#include "csutil/parray.h"
#include "csutil/refarr.h"
#include "csutil/strhash.h"
#include "csutil/stringarray.h"
#include "imesh/genmesh.h"
#include "imesh/gmeshskel2.h"
#include "iutil/comp.h"
#include "iutil/eventh.h"
#include "iutil/virtclk.h"
#include "iutil/strset.h"
#include "csgfx/shadervar.h"
#include <imesh/object.h>
#include "iengine/mesh.h"
#include "iutil/plugin.h"
#include "imap/loader.h"
#include "imesh/skeleton.h"
#include <imap/reader.h>
#include <csutil/xmltiny.h>
#include <iutil/vfs.h>
#include <iutil/databuff.h>

class csGenmeshSkelAnimationControlFactory;
class csGenmeshSkelAnimationControlType;
class csSkelAnimControlRunnable;
struct iEvent;

/**
 * This is a bone of vertices. Every bone has
 * a set of vertices (with weights), children, and a transform
 * relative to a parent. Script operations operate on bones of vertices.
 */

/**
 * Genmesh animation control.
 */

class csGenmeshSkelAnimationControl :
  public scfImplementation2<csGenmeshSkelAnimationControl,
    iGenMeshAnimationControl, iGenMeshSkeletonControlState>
{
private:
	iObjectRegistry* object_reg;

	iSkeleton *skeleton;

	csRef<csGenmeshSkelAnimationControlFactory> factory;
	csStringID bones_name;
	iMeshObject *mesh_obj;
	csArray<csReversibleTransform> in_trs;
	csArray<int> used_bones;

	int num_animated_verts;
	csVector3* animated_verts;
	csVector3* transformed_verts;
	csColor4* animated_colors;
	csVector3* animated_tangents;
	csVector3* animated_bitangents;

	int num_animated_vert_norms;
	csVector3* animated_vert_norms;
	int num_animated_face_norms;
	csVector3* animated_face_norms;
	bool* updated_face_norms;

	csTicks last_update_time;
	uint32 last_version_id;
	csTicks elapsed;

	// Work tables.
	static csArray<csColor4> bone_colors;

	// Copied from the factory.
	bool animates_vertices;
	bool animates_texels;
	bool animates_colors;
	bool animates_normals;
	bool animates_tangents;
	bool animates_bitangents;

	// Set to true if the animated version of that array needs updating.
	bool dirty_vertices;
	bool dirty_texels;
	bool dirty_colors;
	bool dirty_normals;

	// Update the arrays to have correct size. If a realloc was
	// needed then last_version_id will be forced to ~0.
	void UpdateArrays (int num_verts);
	void UpdateVertNormArrays (int num_norms);

	// Update animation state. Set the 'dirty_XXX' flags to true if
	// the arrays need updating too.
	//void UpdateAnimation (csTicks current, int num_verts, uint32 version_id);
	bool vertices_mapped;
	bool normals_mapped;
	bool tangents_mapped;
	bool bitangents_mapped;

	bool initialized;
	void Initialize ();
	bool use_parent;
	csArray<csString> v_bones;

public:

	/// Constructor.
	csGenmeshSkelAnimationControl (csGenmeshSkelAnimationControlFactory* fact, 
		iMeshObject *mesh, iObjectRegistry* object_reg);
	/// Destructor.
	virtual ~csGenmeshSkelAnimationControl ();

	// --- For iGenMeshAnimationControl --------------------------------
	virtual bool AnimatesVertices () const { return animates_vertices; }
	virtual bool AnimatesTexels () const { return animates_texels; }
	virtual bool AnimatesNormals () const { return animates_normals; }
	virtual bool AnimatesColors () const { return animates_colors; }
	virtual bool AnimatesTangents () const { return animates_tangents; }
	virtual bool AnimatesBiTangents () const { return animates_bitangents; }
	virtual void Update (csTicks current);
	virtual const csVector3* UpdateVertices (csTicks current,
		const csVector3* verts, int num_verts, uint32 version_id);
	virtual const csVector2* UpdateTexels (csTicks current,
		const csVector2* texels, int num_texels, uint32 version_id);
	virtual const csVector3* UpdateNormals (csTicks current,
		const csVector3* normals, int num_normals, uint32 version_id);
	virtual const csColor4* UpdateColors (csTicks current,
		const csColor4* colors, int num_colors, uint32 version_id);
	virtual const csVector3* UpdateTangents (csTicks current,
		const csVector3* tangents, int num_tangents, uint32 version_id);
	virtual const csVector3* UpdateBiTangents (csTicks current,
		const csVector3* bitangents, int num_bitangents, uint32 version_id);

	virtual int GetAnimatedVerticesCount()
	{ return num_animated_verts; }

	virtual csVector3 *GetAnimatedVertices()
	{ return animated_verts; }

	virtual csVector3 *GetAnimatedFaceNormals()
	{
		return animated_face_norms; 
	}

	virtual int GetAnimatedFaceNormalsCount()
	{
		return num_animated_face_norms; 
	}

	virtual csVector3 *GetAnimatedVertNormals()
	{
		return animated_vert_norms; 
	}

	virtual int GetAnimatedVertNormalsCount()
	{
		return num_animated_vert_norms; 
	}

	virtual csVector3* GetAnimatedTangents()
	{
		return animated_tangents;
	}

	virtual csVector3* GetAnimatedBiTangents()
	{
		return animated_bitangents;
	}

	virtual iSkeleton *GetSkeleton() { return skeleton; }
};

/**
 * Genmesh animation control factory.
 */
class csGenmeshSkelAnimationControlFactory :
  public scfImplementation1<csGenmeshSkelAnimationControlFactory,
    iGenMeshAnimationControlFactory>
{
private:
	csGenmeshSkelAnimationControlType* type;
	iObjectRegistry* object_reg;

	csStringArray autorun_scripts;

	csRef<iSkeletonFactory> skeleton_factory;

	csArray<size_t> parent_bones;

	csArray<int> used_bones;
	//csArray<csString> vert_bones;

	// These flags are set during script compilation to see if
	// the script can possibly affect the given attributes.
	bool animates_vertices;
	bool animates_texels;
	bool animates_colors;
	bool animates_normals;

	// This flag is set to true if there are hierarchical bones.
	bool has_hierarchical_bones;

	csFlags flags;

	csStringHash xmltokens;

#define CS_TOKEN_ITEM_FILE "plugins/mesh/genmesh/skelanim2/gmeshskelanim.tok"
#include "cstool/tokenlist.h"

	csString error_buf;
	iMeshObjectFactory *mesh_fact;

	bool use_parent;
public:
    csArray<int> & GetUsedBones() { return used_bones; }
	iSkeletonGraveyard *gr;
    virtual bool GetUseParent() { return use_parent; }
    virtual iSkeletonFactory* GetSkelFact() { return skeleton_factory; }

	//csAnimationUpdateLevel & GetAULevel() { return always_update_level; }
	iSkeletonFactory * GetSkeletonFactory() {return skeleton_factory; }
	const csFlags & GetFlags() {return flags; }
	/// Constructor.
	csGenmeshSkelAnimationControlFactory (csGenmeshSkelAnimationControlType* type,
		iObjectRegistry* object_reg);
	/// Destructor.
	virtual ~csGenmeshSkelAnimationControlFactory ();

	virtual csPtr<iGenMeshAnimationControl> CreateAnimationControl (iMeshObject *mesh);

	csGenmeshSkelAnimationControlType* GetType () { return type; }

	bool AnimatesVertices () const { return animates_vertices; }
	bool AnimatesTexels () const { return animates_texels; }
	bool AnimatesNormals () const { return animates_normals; }
	bool AnimatesColors () const { return animates_colors; }
	bool HasHierarchicalBones () const { return has_hierarchical_bones; }

	// --- For iGenMeshAnimationControlFactory -------------------------
	virtual const char* Load (iDocumentNode* node);
	virtual const char* Save (iDocumentNode* parent);
};

/**
 * Genmesh animation control type.
 */
class csGenmeshSkelAnimationControlType :
  public scfImplementation2<csGenmeshSkelAnimationControlType,
    iGenMeshAnimationControlType, iComponent>
{
private:
	iObjectRegistry* object_reg;
	csRef<iVirtualClock> vc;
	csEventID PreProcess;
	csArray<csGenmeshSkelAnimationControl*> always_update_animations;

public:
	/// Constructor.
	csGenmeshSkelAnimationControlType (iBase*);
	/// Destructor.
	virtual ~csGenmeshSkelAnimationControlType ();
	/// Initialize.
	bool Initialize (iObjectRegistry* object_reg);

	virtual csPtr<iGenMeshAnimationControlFactory> CreateAnimationControlFactory ();
};

#endif // __CS_GENMESHSKELANIM_H__
