#ifndef __C4DCANIMATION_H
#define __C4DCANIMATION_H

#include "c4d_basetime.h"
#include "c4d_gedata.h"
#include "c4d_baselist.h"
#include "ge_mtools.h"

#define CaCall(fnc) (this->*C4DOS.CA->fnc)

class CAnimInfo
{
	private:
		CAnimInfo(void);
		~CAnimInfo(void);

	public:
		BaseDocument *doc;   // document
		BaseList2D	 *op;	   // original object
		BaseTime  	 otime;  // original time
		LReal     	 xtime;  // remapped time
		LReal        fac;    // factor of time compared to length of sequence
		LReal        rel;    // factor between two keys, only !=0.0 if k1!=NULL && k2!=NULL
		CKey         *k1;    // last key <= time ATTENTION can be NULL
		CKey         *k2;    // next key > time ATTENTION can be NULL
		LONG				 k1idx,k2idx; // indices for k1 & k2
		LONG         cycle;  // 0 for the range from first key to last key, after last key it is +1,+2... before first key -1,-2,...
};

class CKey : public GeListNode
{
	private:
		CKey(void);
		~CKey(void);
		const CKey& operator = (const CKey &key);

	public:

		// general
		BaseTime GetTime(void) const															{ return CaCall(GetTime)(); }
		BaseTime GetTimeLeft(void) const													{ return CaCall(GetTimeLeft)(); }
		BaseTime GetTimeRight(void) const													{ return CaCall(GetTimeRight)(); }
		Real GetValue(void) const																	{ return CaCall(GetValue)(); }
		Real GetValueLeft(void) const															{ return CaCall(GetValueLeft)(); }
		Real GetValueRight(void) const														{ return CaCall(GetValueRight)(); }
		CInterpolation GetInterpolation(void) const               { return CaCall(GetInterpolation)(); }

		void SetTime(CCurve *seq, const BaseTime &t)							{ CaCall(SetTime)(seq,t); }
		void SetTimeLeft(CCurve *seq, const BaseTime &t)					{ CaCall(SetTimeLeft)(seq,t); }
		void SetTimeRight(CCurve *seq, const BaseTime &t)					{ CaCall(SetTimeRight)(seq,t); }
		void SetValue(CCurve *seq, Real v)												{ CaCall(SetValue)(seq,v); }
		void SetGeData(CCurve *seq, const GeData &d)							{ CaCall(SetGeData)(seq,d); }
		void SetValueLeft(CCurve *seq, Real v)										{ CaCall(SetValueLeft)(seq,v); }
		void SetValueRight(CCurve *seq, Real v)										{ CaCall(SetValueRight)(seq,v); }
		void SetInterpolation(CCurve *seq, CInterpolation inter)	{ CaCall(SetInterpolation)(seq,inter); }

		// functions
		Bool CopyDataTo(CCurve *destseq, CKey *dest, AliasTrans *trans) const { return CaCall(CopyDataTo)(destseq,dest,trans); }
		CTrack *GetTrack(void)   																	{ return CaCall(GetTrackCKey)(); }
		CCurve *GetCurve(void)                                    { return CaCall(GetSequenceCKey)(); }
		const GeData &GetGeData(void)                             { return CaCall(GetGeData)(); }
		void FlushData(void)	  																	{        CaCall(FlushData1)(); }

		CKey *GetClone(AliasTrans *trans) const
		{
			CKey *key = CKey::Alloc();
			if (!key) return NULL;
			CopyDataTo(NULL,key,trans);
			return key;
		}

		static CKey *Alloc() { return C4DOS.CA->CKey_Alloc(); }
		static void Free(CKey *&key) { C4DOS.CA->CKey_Free(key); }
};

class CCurve : public BaseList2D
{
	private:
		CCurve(void);
		~CCurve(void);
		const CCurve& operator = (const CCurve &seq);

	public:
		LONG	       GetKeyCount(void) const															{ return CaCall(GetKeyCount)(); }
		const CKey*  GetKey(LONG index) const												     	{ return CaCall(GetKey2)(index); }
		CKey*        GetKey(LONG index)																		{ return CaCall(GetKey1)(index); }
		CKey*        FindKey(const BaseTime &time, LONG *idx=NULL, FINDANIM_TYPE match=FINDANIM_EXACT) { return CaCall(FindKey1)(time,idx,match); }
		const CKey*  FindKey(const BaseTime &time, LONG *idx=NULL, FINDANIM_TYPE match=FINDANIM_EXACT) const { return CaCall(FindKey2)(time,idx,match); }

		CKey*	 AddKey(const BaseTime &time, LONG *nidx=NULL)					    { return CaCall(AddKey)(time,nidx); }
		Bool   InsertKey(CKey *ckey)																	    { return CaCall(InsertKey)(ckey); }
		Bool	 DelKey(LONG index)																			    { return CaCall(DelKey)(index); }
		LONG   MoveKey(const BaseTime &time, LONG idx, CCurve *dseq=NULL) { return CaCall(MoveKey)(time, idx, dseq); }
		void	 FlushKeys(void)																						{        CaCall(FlushKeys)(); }
		void   SortKeysByTime(void)																				{        CaCall(SortKeysByTime)(); }
		Real   GetValue(const BaseTime &time,LONG fps) const					    { return CaCall(GetValue1)(time,fps); }
		void   CalcSoftTangents(LONG kidx, Real *vl, Real *vr, BaseTime *tl, BaseTime *tr) { CaCall(CalcSoftTangents)(kidx,vl,vr,tl,tr); } 
		LReal  CalcHermite(LReal time, LReal t1, LReal t2, LReal val1, LReal val2, LReal tan1_val, LReal tan2_val, LReal tan1_t, LReal tan2_t, Bool deriv) const { return CaCall(CalcHermite)(time,t1,t2,val1,val2,tan1_val,tan2_val,tan1_t,tan2_t,deriv); } 
		void	 GetTangents(LONG kidx, LReal *vl, LReal *vr, LReal *tl, LReal *tr) { CaCall(GetTangents)(kidx,vl,vr,tl,tr); } 

		void   SetKeyDirty() { SetDirty(DIRTY_CHILDREN); }
		void   SetDirty(LONG flags) { BaseList2D::SetDirty(flags); }
		ULONG	 GetDirty(LONG flags) const { return BaseList2D::GetDirty(flags); }

		CTrack *GetTrack()              { return CaCall(GetTrackCSeq)(); }

		void SetKeyDefault(BaseDocument *doc, LONG kidx);
};

#define CTRACK_CATEGORY_VALUE		1
#define CTRACK_CATEGORY_DATA		2
#define CTRACK_CATEGORY_PLUGIN	3

class CTrack : public BaseList2D
{
	private:
		CTrack(void);
		~CTrack(void);
	public:
		// ******** from BaseList2D *********
		CTrack *GetNext() const { return (CTrack*)AtCall(GetNext)(); }
		CTrack *GetPred() const { return (CTrack*)AtCall(GetPred)(); }

		BaseList2D *GetObject() const { return (BaseList2D*)AtCall(GetMain)(); }

		const DescID &GetDescriptionID() const { return CaCall(GetDescriptionID)(); }
		Bool SetDescriptionID(BaseList2D *object, const DescID &id)  { return CaCall(SetDescriptionID)(object,id); }
		const BaseContainer * GetParameterDescription(BaseContainer &temp) const{ return CaCall(GetParameterDescription)(temp); }

		LONG GetTrackCategory() const { return CaCall(GetTrackCategory)(); }
	
		static CTrack *Alloc(BaseList2D *bl, const DescID &id);
		static void Free(CTrack *&bl);

		// functions
		CLoopType GetBefore(void) const                    { return CaCall(GetBefore)(); }
		CLoopType GetAfter (void) const                    { return CaCall(GetAfter)(); }
		CTrack   *GetTimeTrack(BaseDocument *doc)          { return CaCall(GetTimeTrack)(doc); }
		CCurve *GetCurve(CCurveType type=CC_CURVE)         { return CaCall(GetCurve)(type); }
		void SetBefore(CLoopType type)                     {        CaCall(SetBefore)(type); }
		void SetAfter (CLoopType type)                     {        CaCall(SetAfter)(type); }
		void SetTimeTrack(CTrack *track)                   {        CaCall(SetTimeTrack)(track); }
		Bool AnimateTrack(BaseDocument *doc, BaseList2D *op, const BaseTime &tt, const LONG flags, Bool *chg, void *data=NULL) { return CaCall(AnimateTrack)(doc,op,tt,flags,chg,data); }
		Bool Animate(const CAnimInfo *info, Bool *chg, void *data=NULL)     { return CaCall(Animate)(info,chg,data); }
		void FlushData(void)                               {        CaCall(FlushData)(); } 
		Bool Draw(GeClipMap *map, const BaseTime &clip_left, const BaseTime &clip_right) const { return CaCall(Draw)(map,clip_left,clip_right); }
		Real GetValue(BaseDocument *doc, const BaseTime &time,LONG fps) { return CaCall(GetValue3)(doc,time,fps); }
		Bool Remap(LReal time, LReal *ret_time, LONG *ret_cycle) { return CaCall(Remap)(time,ret_time,ret_cycle); }
		Bool FillKey(BaseDocument *doc, BaseList2D *bl, CKey *key) { return CaCall(FillKey)(doc,bl,key); }

		LONG GuiMessage(const BaseContainer &msg,BaseContainer &result) { return CaCall(GuiMessage)(msg,result); }
		LONG GetHeight() { return CaCall(GetHeight)(); }
		Bool TrackInformation(BaseDocument *doc, CKey *key, String *str, Bool set) { return CaCall(TrackInformation)(doc,key,str,set); }
		LONG GetUnit(Real *step) { return CaCall(GetUnit)(step); }
};

#endif
