#ifndef __C4DBASELIST_H
#define __C4DBASELIST_H

#include "ge_math.h"
#include "operatingsystem.h"
#include "c4d_string.h"
#include "c4d_basecontainer.h"
#include "c4d_gedata.h"

// macros for instanceof
#define INSTANCEOFROOT(X)                
#define INSTANCEOF(X,Y)                  \
	public:                                \
		typedef Y SUPER;                     \
	private:
// macros for instanceof

#define COPY_NO_HIERARCHY					(1<<2)
#define COPY_NO_ANIMATION					(1<<3)
#define COPY_NO_BITS							(1<<4)
#define COPY_NO_BRANCHES					(1<<7)
#define COPY_NO_INTERNALS					(1<<8)
#define COPY_DOCUMENT							(1<<10) // this flag is read-only, set when a complete document is copied

struct VariableChanged
{
	VariableChanged(void);

	LONG old_cnt,new_cnt,*map;
	Bool safety;
};

struct DocumentImported
{
	BaseDocument *doc;
	LONG c4dversion;
};

struct MarkMaterials
{
	BaseMaterial *omat;
	BaseMaterial *nmat;
};

struct DescriptionInitUndo // MSG_DESCRIPTION_INITUNDO
{
	BaseDocument *doc;
};

struct DescriptionCheckUpdate // MSG_DESCRIPTION_CHECKUPDATE
{
	BaseDocument *doc;
	LONG drawflags;
};

struct DescriptionValidate
{
	LONG flags;
};

struct RetrievePrivateData
{	
	LONG	flags;
	void	*data;
};

#define MSG_POINTS_CHANGED										 1
#define MSG_POLYGONS_CHANGED									 2
#define MSG_UPDATE														 5
#define MSG_SMALLUPDATE												 6
#define MSG_CHANGE														 7
#define MSG_BASECONTAINER											 9
#define MSG_SEGMENTS_CHANGED									10
#define MSG_FILTER														14
#define MSG_TRANSFERGOALS											15
#define MSG_DESCRIPTION_INITUNDO							16
#define MSG_DESCRIPTION_CHECKUPDATE						17
	#define	MSG_DESCRIPTION_CHECKUPDATE_ACTIVE		(1<<0)
	#define MSG_DESCRIPTION_CHECKUPDATE_DOCUMENT	(1<<1)
	#define MSG_DESCRIPTION_CHECKUPDATE_AUTOKEY		(1<<2)
#define MSG_DESCRIPTION_COMMAND								18 // data contains the id
#define MSG_DESCRIPTION_VALIDATE							20
#define MSG_EDIT															21
#define MSG_MENUPREPARE												22
#define MSG_RETRIEVEPRIVATEDATA								23
#define MSG_DESCRIPTION_REMOVE_ENTRY					24 // data contains DescriptionCommand
#define MSG_DESCRIPTION_EDIT_ENTRY						25 // data contains DescriptionCommand
#define MSG_DESCRIPTION_CHECKDRAGANDDROP			26 
#define MSG_DESCRIPTION_GETBITMAP							27
#define MSG_DESCRIPTION_GETOBJECTS            30

#define MSG_MULTI_MARKMATERIALS								(4|(1<<30)) 
#define MSG_MULTI_DOCUMENTCLONED							11
#define MSG_MULTI_DOCUMENTIMPORTED						13 

class NodeData;
class GeListNode;

struct MessageFilter
{
	LONG	type,flags;
	void	*data;
};

#define MULTIMSG_UP					1
#define MULTIMSG_ROOT				2
#define MULTIMSG_DOWN				3
#define MULTIMSG_BROADCAST	4
#define MULTIMSG_MASK				0x07

#define BRANCHINFO_ANIMATE		(1<<0)
#define BRANCHINFO_HEADISATOM	(1<<1)

struct BranchInfo
{
	Atom		*head;
	String	*name;
	LONG		id;
	LONG		flags;
};

#define AtCall(fnc) (this->*C4DOS.At->fnc)

class Atom
{
	private:
		Atom() {}
	public:
 		LONG GetType(void) { return AtCall(GetType)(); }
 		LONG GetDiskType(void) { return C4DOS.Bl->GetDiskType(this); }
		Bool IsInstanceOf(LONG id) { return AtCall(IsInstanceOf)(id); }

		Bool Message(LONG type, void *data=NULL) { return AtCall(Message)(type,data); }
		Bool MultiMessage(LONG flags, LONG type, void *data) { return AtCall(MultiMessage)(flags,type,data); }

		Atom *GetClone(LONG flags, AliasTrans *trn) { return AtCall(GetClone)(flags,trn); }
		Bool CopyTo(Atom *dst, LONG flags, AliasTrans *trn) { return AtCall(CopyTo)(dst,flags,trn); }

		Bool Read(HyperFile *hf, LONG id, LONG level);
		Bool Write(HyperFile *hf);
		Bool ReadObject(HyperFile *hf, Bool readheader);
		Bool WriteObject(HyperFile *hf);

		Bool GetDescription(Description *description,LONG flags);
		Bool GetParameter(const DescID &id,GeData &t_data,LONG flags);
		Bool SetParameter(const DescID &id,const GeData &t_data,LONG flags);
		DynamicDescription *GetDynamicDescription();
		Bool GetEnabling(const DescID &id,GeData &t_data,LONG flags,const BaseContainer *itemdesc);
};

class AtomArray
{
	private:
		AtomArray() {}
	public:
		static AtomArray* Alloc()											{	return (*C4DOS.At->AtomArrayAlloc)();	}
		static void Free(AtomArray *&obj)							{ (*C4DOS.At->AtomArrayFree)(obj); }

		LONG GetCount() const													{ return AtCall(GetCount)(); }
		Atom *GetIndex(LONG idx) const								{ return AtCall(GetIndex)(idx); }
		Bool Append(Atom *obj)												{ return AtCall(Append)(obj); }
		void Flush()																	{ AtCall(Flush)(); }

		Bool CopyTo(AtomArray *dest) const						{ return AtCall(AACopyTo)(dest); }

		LONG GetUserID() const												{ return AtCall(AAGetUserID)(); }
		void SetUserID(LONG t_userid)									{ AtCall(AASetUserID)(t_userid); }
		
		void *GetUserData() const											{ return AtCall(AAGetUserData)(); }
		void SetUserData(void *t_userdata)						{ AtCall(AASetUserData)(t_userdata); }

		Atom *GetPreferred() const										{ return AtCall(AAGetPreferred)(); }
		void SetPreferred(Atom *t_preferred)					{ AtCall(AASetPreferred)(t_preferred); }
};

class GeListNode : public Atom
{
	public:
		GeListNode *GetNext(void) { return AtCall(GetNext)(); }
		GeListNode *GetPred(void) { return AtCall(GetPred)(); }
		GeListNode *GetDown(void) { return AtCall(GetDown)(); }
		GeListNode *GetUp  (void) { return AtCall(GetUp)(); }
		GeListNode *GetDownLast(void) { return AtCall(GetDownLast)(); }

		void InsertBefore		(GeListNode *bl) { AtCall(InsertBefore)(bl); }
		void InsertAfter	  (GeListNode *bl) { AtCall(InsertAfter)(bl); }
		void InsertUnder    (GeListNode *bl) { AtCall(InsertUnder)(bl); }
		void InsertUnderLast(GeListNode *bl) { AtCall(InsertUnderLast)(bl); }
		void Remove(void) { AtCall(Remove)(); }

		GeListHead *GetListHead(void) { return AtCall(GetListHead)(); }

		LONG			GetNodeID	 (LONG index=0) const { return C4DOS.Bl->GetNodeID((GeListNode*)this,index); }
		NodeData* GetNodeData(LONG index=0) const { return C4DOS.Bl->GetNodeData((GeListNode*)this,index); }

		void				SetCustomData(GeListNode *node);
		GeListNode*	GetCustomData(void);

		BaseDocument *GetDocument(void) { return AtCall(GetDocument)(); }
		LONG GetBranchInfo(BranchInfo *info, LONG max) { return AtCall(GetBranchInfo)(info,max); }
};

class GeListHead : public Atom
{
	public:
		void				SetParent(GeListNode *parent) { AtCall(SetParent)(parent); }
		GeListNode*	GetParent(void) { return AtCall(GetParent)(); }
		GeListNode*	GetFirst(void) { return AtCall(GetFirst)(); }
		GeListNode*	GetLast(void)  { return AtCall(GetLast)(); }
		void				FlushAll(void) { AtCall(FlushAll)(); }
		void				InsertFirst(GeListNode *bn) { AtCall(InsertFirst)(bn); }
		void				InsertLast(GeListNode *bn) { AtCall(InsertLast)(bn); }

		static GeListHead *Alloc(void);
		static void Free(GeListHead *&v);
};

class BaseList2D : public GeListNode
{
	public:
		BaseList2D *GetNext(void) { return (BaseList2D*)AtCall(GetNext)(); }
		BaseList2D *GetPred(void) { return (BaseList2D*)AtCall(GetPred)(); }

		void SetBit   (LONG mask) { C4DOS.Bl->SetAllBits(this,C4DOS.Bl->GetAllBits(this)|mask); }
		Bool GetBit   (LONG mask) { return (C4DOS.Bl->GetAllBits(this)&mask)==mask;	}
		void DelBit   (LONG mask) { C4DOS.Bl->SetAllBits(this,C4DOS.Bl->GetAllBits(this) & ~mask); }
		void ToggleBit(LONG mask);
		LONG GetAllBits(void) { return C4DOS.Bl->GetAllBits(this);	}
		void SetAllBits(LONG bits) { C4DOS.Bl->SetAllBits(this,bits); }

		BaseContainer GetData(void) { BaseContainer bc; C4DOS.Bl->GetData(this,&bc); return bc; }
		void SetData(const BaseContainer &bc, Bool add=TRUE) { C4DOS.Bl->SetData(this,&bc,add); }
		BaseContainer* GetDataInstance(void) { return C4DOS.Bl->GetDataInstance(this); }

		LONG GetColor  (void);
		void SetColor  (LONG c);

		const String& GetName(void) { return AtCall(GetName)(); }
		void	SetName(const String &name) { AtCall(SetName)(name); }

		String GetBubbleHelp(void) { return C4DOS.Bl->GetBubbleHelp(this); }

		Bool TransferGoal(BaseList2D *dst) { return AtCall(TransferGoal)(dst); }

		Bool SetAnimatedParameter(const DescID &id,const GeData &t_data1,const GeData &t_data2,Real mix,LONG flags);
		Bool GetAnimatedParameter(const DescID &id,GeData &t_data1,GeData &t_data2,Real &mix,LONG flags);
		
		Bool Edit(void);

		LONG GetInfo(void);
		void GetIcon(IconData *dat);

		BaseTrack*	GetFirstTrack(void);  
		BaseTrack*	GetTrack(LONG type);
		void				KillAllTracks(void);
		void				InsertTrack(BaseTrack *track, BaseTrack *pred=NULL);
		void				InsertTrackLast(BaseTrack *track);
		BaseTrack*	FindTrack(const DescID &id);
};

GeListNode *AllocListNode(LONG id);
GeListNode *AllocSmallListNode(LONG id);
GeListNode *AllocMultiNode(LONG *id_array, LONG id_cnt);
#define FreeListNode(v) { if (v) C4DOS.Bl->Free(v); v=NULL;}
#define blDelete(v) { if (v) C4DOS.Bl->Free(v); v=NULL;}

class BaseLink
{
	private:
		BaseLink(void);
	public:
		BaseList2D*	GetLink(BaseDocument *doc, LONG instanceof=0) { return C4DOS.Ln->GetLink(this,doc,instanceof); }
		void				SetLink(BaseList2D *list)  { C4DOS.Ln->SetLink(this,list); }
		Bool				Read(HyperFile *hf) { return C4DOS.Ln->Read(this,hf); }
		Bool				Write(HyperFile *hf) { return C4DOS.Ln->Write(this,hf); }
		BaseLink*		GetClone(LONG flags, AliasTrans *trn) { return C4DOS.Ln->GetClone(this,flags,trn); }
		Bool				CopyTo(BaseLink *dst, LONG flags, AliasTrans *trn) { return C4DOS.Ln->CopyTo(this,dst,flags,trn); }

		BaseList2D*	ForceGetLink(void) { return C4DOS.Ln->ForceGetLink(this); }

		static BaseLink	 *Alloc(void);
		static void			 Free(BaseLink *&link);
};

class AliasTrans
{
	private:
		AliasTrans(void);
	public:
		Bool Init(BaseDocument *doc) { return C4DOS.Ln->TrnInit(this,doc); }
		void Translate(Bool connect_oldgoals) { C4DOS.Ln->TrnTranslate(this,connect_oldgoals); }

		static AliasTrans *Alloc(void);
		static void				Free(AliasTrans *&link);
};

class PluginSceneLoader : public BaseList2D {};
class PluginSceneSaver  : public BaseList2D {};

#endif
