/////////////////////////////////////////////////////////////
// CINEMA 4D SDK                                           //
/////////////////////////////////////////////////////////////
// (c) 1989-2004 MAXON Computer GmbH, all rights reserved  //
/////////////////////////////////////////////////////////////

#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"

class DescID;

// 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
#define COPY_NONGONS							(1<<11)

struct VariableChanged
{
	VariableChanged(void);

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

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

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

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

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

struct DescriptionValidate // MSG_DESCRIPTION_VALIDATE
{
	LONG flags;
};

struct DescriptionPostSetValue
{
	const DescID *descid;
};

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

struct MaterialDragAndDrop // MSG_MATERIALDRAGANDDROP
{
	BaseDocument	*doc;
	BaseObject		*op;
	BaseTag			*result;
};

#define DRAGANDDROP_FLAG_RECEIVE	1
#define DRAGANDDROP_FLAG_DROP	2
#define DRAGANDDROP_FLAG_ACCEPT	4

struct DragAndDrop // MSG_DRAGANDDROP
{
	BaseDocument	*doc;
	C4DAtom 			*sender;
	ULONG			    flags;
	LONG			    type;
	void    		  *data;
};

struct RenderNotificationData
{
	BaseDocument	*doc;
	Bool					start,animated,external;
	Render				*render;
};

struct DocumentInfoData
{
	LONG					type;
	LONG					fileformat;
	BaseDocument 	*doc;
	Filename			filename;
};

struct GetCustomIconData
{
	IconData	*dat;
	Bool			filled;
};

#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_DOCUMENT			(1<<1)
	#define MSG_DESCRIPTION_CHECKUPDATE_AUTOKEY				(1<<2)
	#define MSG_DESCRIPTION_CHECKUPDATE_SYNC					(1<<4)
	#define MSG_DESCRIPTION_CHECKUPDATE_NOSCENEUPDATE	(1<<23)
#define MSG_DESCRIPTION_COMMAND								18 // data contains the id
#define MSG_DESCRIPTION_POSTSETPARAMETER			19
#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_DESCRIPTION_USERINTERACTION_END		31
#define	MSG_MOVE_FINISHED											32
#define MSG_GETCUSTOMICON											1001090			
#define MSG_MATERIALDRAGANDDROP								1001069 
#define MSG_DRAGANDDROP   										1018756
#define MSG_INITIALCHANNEL										1001073
#define MSG_DOCUMENTINFO											1001078
	#define MSG_DOCUMENTINFO_TYPE_SETACTIVE						1000
	#define MSG_DOCUMENTINFO_TYPE_LOAD								1001
	#define MSG_DOCUMENTINFO_TYPE_MERGE								1002
	#define MSG_DOCUMENTINFO_TYPE_SAVE_BEFORE					1004
	#define MSG_DOCUMENTINFO_TYPE_SAVE_AFTER					1005
	#define MSG_DOCUMENTINFO_TYPE_SAVEPROJECT_BEFORE	1006
	#define MSG_DOCUMENTINFO_TYPE_SAVEPROJECT_AFTER		1007
	#define MSG_DOCUMENTINFO_TYPE_REMOVE							1008

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

#define MSG_TRANSLATE_POINTS								1015632
#define MSG_TRANSLATE_POLYGONS							1015633
#define MSG_TRANSLATE_NGONS									1015634
#define MSG_TRANSLATE_SEGMENTS							1015831
#define MSG_PRETRANSLATE_POINTS							1015822
#define MSG_PRETRANSLATE_POLYGONS						1015823
#define MSG_PRETRANSLATE_NGONS							1015824
#define MSG_PRETRANSLATE_SEGMENTS						1015832
#define MSG_UPDATE_NGONS										475000000
#define	MSG_DOCUMENT_MODE_CHANGED						200000091		// tool message when doc::action changed
#define MSG_TOOL_RESTART										200000096
#define MSG_DEFORMMODECHANGED								200000125
#define MSG_ANIMATE													300001037 

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)

// for new CheckNBit Routine
#define	NBIT_SET 1
#define	NBIT_DEL 2 
#define NBIT_TOG 3
#define NBIT_INTERNAL_NODITRY	0xf0

// HDIRTY bits
// hdirtybits
enum HDIRTY_ID
{
	HDIRTY_ID_ANIMATION							= 0,
	HDIRTY_ID_OBJECT								= 1,
	HDIRTY_ID_OBJECT_MATRIX					= 2,
	HDIRTY_ID_OBJECT_HIERARCHY			= 3,
	HDIRTY_ID_TAG										= 4,
	HDIRTY_ID_MATERIAL							= 5,
	HDIRTY_ID_SHADER								= 6,
	HDIRTY_ID_RENDERSETTINGS				= 7,
	HDIRTY_ID_VP										= 8,
	HDIRTY_ID_FILTER								= 9,
	HDIRTY_ID_NBITS									= 10,
	HDIRTY_ID_MAX,
};

#define HDIRTY_MASK_ANIMATION						(1<<HDIRTY_ID_ANIMATION)
#define HDIRTY_MASK_OBJECT							(1<<HDIRTY_ID_OBJECT)
#define HDIRTY_MASK_OBJECT_MATRIX				(1<<HDIRTY_ID_OBJECT_MATRIX)
#define HDIRTY_MASK_OBJECT_HIERARCHY		(1<<HDIRTY_ID_OBJECT_HIERARCHY)
#define HDIRTY_MASK_TAG									(1<<HDIRTY_ID_TAG)
#define HDIRTY_MASK_MATERIAL						(1<<HDIRTY_ID_MATERIAL)
#define HDIRTY_MASK_SHADER							(1<<HDIRTY_ID_SHADER)
#define HDIRTY_MASK_RENDERSETTINGS			(1<<HDIRTY_ID_RENDERSETTINGS)
#define HDIRTY_MASK_VP									(1<<HDIRTY_ID_VP)
#define HDIRTY_MASK_FILTER							(1<<HDIRTY_ID_FILTER)
#define HDIRTY_MASK_NBITS								(1<<HDIRTY_ID_NBITS)

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

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

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

	public:
		Bool Content(void) const				 { return AtCall(Content)(); }
		Bool IsEqual(const GeMarker &m) const	 { return AtCall(IsEqual)(m); }

		static GeMarker* Alloc()				 {	return (*C4DOS.At->GeMarkerAlloc)();	}
		static void Free(GeMarker *&obj) { (*C4DOS.At->GeMarkerFree)(obj); }
};

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

		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); }

		C4DAtom *GetClone(LONG flags, AliasTrans *trn) { return AtCall(GetClone)(flags,trn); }
		Bool CopyTo(C4DAtom *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);

		ULONG GetDirty(LONG flags) const { return C4DOS.Bo->GetDirty(this,flags); }
		void SetDirty(LONG flags) { C4DOS.Bo->SetDirty(this,flags); }

		ULONG GetHDirty(ULONG mask) const { return BoCall(GetHDirty)(mask); }
		void SetHDirty(ULONG mask)		{ BoCall(SetHDirty)(mask); }
};

class C4DAtomGoal : public C4DAtom
{
	private:
		C4DAtomGoal();
		~C4DAtomGoal();
};

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

		LONG GetCount() const													{ return AtCall(GetCount)(); }
		LONG GetCount(LONG type, LONG instance) const	{ return AtCall(AAGetCountTI)(type, instance); }
		C4DAtom *GetIndex(LONG idx) const							{ return AtCall(GetIndex)(idx); }
		Bool Append(C4DAtom *obj)											{ return AtCall(Append)(obj); }
		void Flush()																	{ AtCall(Flush)(); }
		Bool Remove(C4DAtom *obj)											{ return AtCall(AARemove)(obj); }

		Bool CopyTo(AtomArray *dest) const						{ return AtCall(AACopyTo)(dest); }
		Bool CopyToFilter(AtomArray *dest, LONG type, LONG instance, Bool generators = TRUE) const	{ return AtCall(AACopyToFilter)(dest, type, instance, generators); }

		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); }

		C4DAtom *GetPreferred() const									{ return AtCall(AAGetPreferred)(); }
		void SetPreferred(C4DAtom *t_preferred)				{ AtCall(AASetPreferred)(t_preferred); }
		void FilterObject(LONG type, LONG instance, Bool generators = FALSE)   { AtCall(AAFilterObject)(type, instance, generators); }
		void FilterObjectChildren()										{ AtCall(AAFilterObjectChildren)(); }
		Bool Append(AtomArray *src)										{ return AtCall(AAAppendArr)(src); }
		LONG Find(C4DAtom *obj)												{ return AtCall(AAFind)(obj); }
};

class GeListNode : public C4DAtomGoal
{
	private:
		GeListNode();
		~GeListNode();
	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 GetBranchInfoEx(BranchInfo *info, LONG max) { return AtCall(GetBranchInfoEx)(info,max); }
		LONG GetBranchInfo(BranchInfo *info, LONG max, ULONG flags) { return AtCall(GetBranchInfo)(info,max,flags); }
		Bool IsDocumentRelated(void) { return AtCall(IsDocumentRelated)(); }

		// new bit function for 64 bits at the moment
		Bool GetNBit(LONG bit) const;
		Bool ChangeNBit(LONG bit, LONG bitmode);
		LONG GetInfo(void);
};

class GeListHead : public GeListNode
{
	private:
		GeListHead();
		~GeListHead();
	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); }
		void				Insert(GeListNode *bn, GeListNode *parent, GeListNode *prev);

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

class BaseList2D : public GeListNode
{
	private:
		BaseList2D();
		~BaseList2D();
	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) const { 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 TransferMarker(BaseList2D *dst) const { return AtCall(TransferMarker)(dst); }

		const GeMarker& GetMarker(void) const { return AtCall(GetMarker)(); }
		void SetMarker(const GeMarker &m) { AtCall(SetMarker)(m); }

		Bool SetAnimatedParameter(const DescID &id,const GeData &t_data1,const GeData &t_data2,Real mix,LONG flags,CTrack *track);
		Bool GetAnimatedParameter(const DescID &id,GeData &t_data1,GeData &t_data2,Real &mix,LONG flags);

		PluginShader* GetFirstShader() const { return AtCall(GetFirstShader)(); }
		void InsertShader(PluginShader *shader, PluginShader *pred=NULL) { AtCall(InsertShader)(shader,pred); }
		
		Bool Edit(void);

		void GetIcon(IconData *dat);

		void ClearKeyframeSelection();
		Bool FindKeyframeSelection(const DescID &id);
		Bool SetKeyframeSelection(const DescID &id,Bool selection);
		Bool KeyframeSelectionContent();

		// layer
		LayerObject     *GetLayerObject(BaseDocument *doc);
		      Bool       SetLayerObject(LayerObject *layer);
		const LayerData *GetLayerData  (BaseDocument *doc, Bool rawdata=FALSE);
		Bool             SetLayerData  (BaseDocument *doc, const LayerData &data);


		// new animation system
		GeListHead* GetCTrackRoot(void);
		CTrack*	    GetFirstCTrack(void);  
		CTrack*	    FindCTrack(const DescID &id);

		const String &GetTypeName(void); // typisierter Kategorie-Name, z.B. Phong, Spline, Bone
		BaseList2D *GetMain(void) const;

		void InsertTrackSorted(CTrack *track);
};

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();
		~BaseLink();
	public:

		BaseList2D*		GetLink(const BaseDocument *doc, LONG instanceof=0) const { return C4DOS.Ln->GetLink(this,doc,instanceof); }
		C4DAtomGoal*	GetLinkAtom(const BaseDocument *doc, LONG instanceof=0) const { return C4DOS.Ln->GetLinkAtom(this,doc,instanceof); }

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

		void					SetLink(C4DAtomGoal *list)  { C4DOS.Ln->SetLink(this,list); }

		Bool					Read(HyperFile *hf) { return C4DOS.Ln->Read(this,hf); }
		Bool					Write(HyperFile *hf) const { return C4DOS.Ln->Write(this,hf); }
		BaseLink*			GetClone(LONG flags, AliasTrans *trn) const { return C4DOS.Ln->GetClone(this,flags,trn); }
		Bool					CopyTo(BaseLink *dst, LONG flags, AliasTrans *trn) const { return C4DOS.Ln->CopyTo(this,dst,flags,trn); }
		Bool					IsCacheLink() const { return C4DOS.Ln->IsCacheLink(this); }

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

class AliasTrans
{
	private:
		AliasTrans();
		~AliasTrans();
	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 
{
	private:
		PluginSceneLoader();
		~PluginSceneLoader();
};

class PluginSceneSaver  : public BaseList2D 
{
	private:
		PluginSceneSaver();
		~PluginSceneSaver();
};

void HandleShaderMessage(GeListNode *node, PluginShader *ps, LONG type, void *data);
void HandleInitialChannel(GeListNode *node, LONG id, LONG type, void *data);

#endif
