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

#ifndef __C4DBASEDOCUMENT_H
#define __C4DBASEDOCUMENT_H

#ifdef __API_INTERN__
abc def xyz
#endif

#include "c4d_baselist.h"
#include "c4d_file.h"
#include "c4d_tools.h"
#include "operatingsystem.h"

class BaseTag;
class TextureTag;
class BaseObject;
class BaseMaterial;
class C4DThread;
class BaseSound;

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

class MultipassObject : public BaseList2D
{
	private:
		MultipassObject();
		~MultipassObject();
	public:
		MultipassObject *GetNext(void) { return (MultipassObject*)AtCall(GetNext ); }
		MultipassObject *GetPred(void) { return (MultipassObject*)AtCall(GetPred ); }
};

class RenderData : public BaseList2D
{
	private:
		RenderData();
		~RenderData();
	public:
		RenderData *GetNext(void) { return (RenderData*)AtCall(GetNext ); }
		RenderData *GetPred(void) { return (RenderData*)AtCall(GetPred ); }
		RenderData *GetDown    (void) { return (RenderData*)AtCall(GetDown ); }
		RenderData *GetUp      (void) { return (RenderData*)AtCall(GetUp ); }
		RenderData *GetDownLast(void) { return (RenderData*)AtCall(GetDownLast ); }

		BaseVideoPost *GetFirstVideoPost();
		void InsertVideoPost(BaseVideoPost *pvp, BaseVideoPost *pred=NULL);
		void InsertVideoPostLast(BaseVideoPost *pvp);

		MultipassObject *GetFirstMultipass();
		void InsertMultipass(MultipassObject *obj, MultipassObject *pred=NULL);

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

//---------------------- LAYERS --------------------------------------------------------
class LayerObject : public BaseList2D
{
	private:
		LayerObject();
		~LayerObject();

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

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

struct LayerData
{
	Bool   solo;       // solo mode
	Bool   view;       // visible in editor view
	Bool   render;     // visible in render view
	Bool   manager;    // visible in scene browser, timeline
	Bool   locked;     // not selectable, nece no modification possible - greyed out in Scene Browser
	Bool   generators; // generators on /off
	Bool   deformers;  // deformers on /off
	Bool   expressions;// expressions on /off
	Bool   animation;  // animation on/off

	Vector color;

	Bool	xref; // import with xref

	LayerData() 
	{
		view				= TRUE;
		render			= TRUE;
		manager			= TRUE;
		locked			= FALSE;
		deformers		= TRUE;
		generators	= TRUE;
		expressions = TRUE;
		animation		= TRUE;
		xref				= TRUE;
		color				= 1.0;
	}
};


//--------------------------------------------------------------------------------------

#define SELECTION_NEW	0
#define SELECTION_ADD	1
#define SELECTION_SUB	2

struct PickSessionDataStruct;

typedef void (*PickSessionCallBack)(LONG flags, const PickSessionDataStruct *psd);
#define PICKSESSION_FLAG_CANCELED	1

struct PickSessionDataStruct
{
	AtomArray							*active;
	PickSessionCallBack		callback;
	void									*userdata;
	Bool									multi;

	PickSessionDataStruct()
	{
		active = AtomArray::Alloc();
	}
	~PickSessionDataStruct()
	{
		AtomArray::Free(active);
	}
};

class BaseDocument : public BaseList2D
{
	private:
		BaseDocument();
		~BaseDocument();
	public:
		BaseDocument *GetNext(void) { return (BaseDocument*)AtCall(GetNext ); }
		BaseDocument *GetPred(void) { return (BaseDocument*)AtCall(GetPred ); }

		BaseContainer GetData(DOCUMENTSETTINGS type);
		void SetData(DOCUMENTSETTINGS type, const BaseContainer &bc);
		BaseContainer *GetSettingsInstance(LONG type);

		BaseObject		*GetFirstObject(void);
		BaseMaterial	*GetFirstMaterial(void);
		RenderData		*GetFirstRenderData(void);

		void InsertRenderData(RenderData *rd, RenderData *parent, RenderData *pred);
		void InsertRenderDataLast(RenderData *rd);
		void InsertMaterial(BaseMaterial *mat, BaseMaterial *pred=NULL, Bool checknames=FALSE);
		void InsertObject(BaseObject *op, BaseObject *parent, BaseObject *pred, Bool checknames=FALSE);

		RenderData		*GetActiveRenderData(void);
		BaseObject		*GetActiveObject  (void);
		BaseMaterial	*GetActiveMaterial(void);
		BaseTag				*GetActiveTag     (void);
		BaseObject		*GetRealActiveObject(AtomArray *help, Bool *multi);

		void				  GetActiveObjects  (AtomArray &selection,GETACTIVEOBJECTFLAGS flags) const;
		void				  GetActivePolygonObjects(AtomArray &selection,Bool children) const;
		void				  GetActiveObjectsFilter(AtomArray &selection, Bool children, LONG type, LONG instanceof) const;
		void				  GetActiveTags     (AtomArray &selection) const;
		void				  GetActiveMaterials(AtomArray &selection) const;
		void				  GetSelection      (AtomArray &selection) const;

		void SetActiveObject    (BaseObject *op,LONG mode=SELECTION_NEW);
		void SetActiveTag       (BaseTag *tag,LONG mode=SELECTION_NEW);
		void SetActiveMaterial  (BaseMaterial	*mp,LONG mode=SELECTION_NEW);
		void SetActiveRenderData(RenderData *rd);
		void SetSelection       (BaseList2D *bl, LONG mode=SELECTION_NEW);

		void Flush(void);

		BaseObject *GetHighest(LONG type, Bool editor);

		BaseMaterial	*SearchMaterial   (const String &str);
		BaseMaterial	*SearchMaterialInc(const String &str);
		BaseObject		*SearchObject     (const String &str);
		BaseObject		*SearchObjectInc  (const String &str);

		BaseObject		*GetHelperAxis(void);

		BaseContainer	GetAllTextures(const AtomArray *ar);

		Bool			GetChanged(void);
		void			SetChanged(void);

		Filename	GetDocumentName(void);
		Filename	GetDocumentPath(void);
		void			SetDocumentName(const Filename &fn);
		void			SetDocumentPath(const Filename &path);

		Real			GetLOD(void);
		void			SetLOD(Real lod);

		LONG			GetFps(void) const;
		void			SetFps(LONG fps);

		BaseTime	GetMinTime(void);
		void			SetMinTime(const BaseTime &t);

		BaseTime	GetMaxTime(void);
		void			SetMaxTime(const BaseTime &t);

		BaseTime	GetUsedMinTime(BaseList2D *check);
		BaseTime	GetUsedMaxTime(BaseList2D *check);

		BaseTime	GetLoopMinTime(void);
		void			SetLoopMinTime(const BaseTime &t);

		BaseTime	GetLoopMaxTime(void);
		void			SetLoopMaxTime(const BaseTime &t);

		Bool			GetRenderLod(void);
		void			SetRenderLod(Bool lod);

		BaseTime	GetTime(void);
		void			SetTime(const BaseTime &t);

		LONG			GetMode(void);
		void			SetMode(LONG m);

		LONG			GetAction(void);
		void			SetAction(LONG a);

		Bool			IsEditMode(void);

		Bool			StartUndo(void);
		Bool			EndUndo(void);
		Bool			AddUndo(UNDOTYPE type, void *data, Bool allowFromThread=FALSE);
		Bool			AddUndo(BaseDraw* bd);
		Bool			DoUndo(Bool multiple = FALSE);
		Bool			DoRedo(void);
		void      FlushUndoBuffer(void) { C4DOS.Bd->FlushUndoBuffer(this); }
		BaseList2D* GetUndoPtr() { return C4DOS.Bd->GetUndoPtr(this); }
		BaseList2D* FindUndoPtr(BaseList2D *bl, UNDOTYPE type) { return C4DOS.Bd->FindUndoPtr(this,bl,type); }
		void      AutoKey(BaseList2D *undo, BaseList2D *op, Bool recursive, Bool pos, Bool scale, Bool rot, Bool param, Bool pla) { C4DOS.Bd->AutoKey(this, undo, op, recursive, pos, scale, rot, param, pla); }
		Bool			RecordKey(BaseList2D *op, const BaseTime &time, const DescID &id, BaseList2D *undo, Bool eval_attribmanager, Bool autokeying, Bool allow_linking){ return C4DOS.Bd->RecordKey(this,op,time,id,undo,eval_attribmanager,autokeying,allow_linking); }
		void      Record(void) { C4DOS.Bd->Record(this); }

		void			AnimateObject(BaseList2D *op, const BaseTime &time, ANIMATEFLAGS flags);

		BaseDocument *Polygonize(Bool keepanimation=FALSE);

		BaseDraw  *GetActiveBaseDraw(void);
		BaseDraw  *GetRenderBaseDraw(void);
		BaseDraw  *GetBaseDraw(LONG num);
		LONG			GetBaseDrawCount();
		LONG		  GetSplinePlane(void);

		void			SetRewind(LONG flags=0);

		BaseSceneHook *FindSceneHook(LONG id) const { return C4DOS.Bd->FindSceneHook(this,id); }

		static BaseDocument *Alloc(void);
		static void Free(BaseDocument *&v);

		Bool IsCacheBuilt(Bool force=FALSE) { return C4DOS.Bd->IsCacheBuilt(this,force); }

		void ForceCreateBaseDraw(void);

		// layers
		GeListHead *GetLayerObjectRoot(void);
		Bool HandleSelectedTextureFilename(BaseChannel *bc, const Filename &fn, Filename *resfilename, Bool undo, GEMB_R *already_answered);
		Bool ReceiveMaterials  (BaseObject *op, AtomArray *mat, Bool clearfirst);
		Bool ReceiveNewTexture (BaseObject *op, const Filename &filename, Bool sdown, GEMB_R *already_answered);

		Bool CollectSounds(BaseSound *snd, const BaseTime &from, const BaseTime &to);
		// only internal!!!
		void RecordZero(void) { C4DOS.Bd->RecordZero(this); }
		void RecordNoEvent(void) { C4DOS.Bd->RecordNoEvent(this); }

		LONG GetDrawTime() { return C4DOS.Bd->GetDrawTime(this); }

		// compute expressions, caches etc
		Bool ExecutePasses(BaseThread *bt, Bool animation, Bool expressions, Bool caches, BUILDFLAGS flags);

		const PickSessionDataStruct *GetPickSession() const;
		void StartPickSession(PickSessionDataStruct *psd);
		void StopPickSession(Bool cancel);

		Bool GetDefaultKey(CKey* pKey,Bool &bOverdub) const;
		void SetDefaultKey(CKey* pKey,Bool bOverdub);

		void SendInfo(LONG type, LONG format, const Filename &fn, BaseList2D *bl, Bool hooks_only) { return C4DOS.Bd->SendInfo(this,type,format,fn,bl,hooks_only); }

		void SetHighlightedObject(BaseObject *op, LONG mode = SELECTION_NEW);
		void SetHighlightedObjects(AtomArray &selection, LONG mode = SELECTION_NEW);
		void GetHighlightedObjects(AtomArray &selection) const;

		Bool IsAxisEnabled(void);
};

class Hierarchy
{
	private:
		BaseDocument	*doc;
		BaseThread		*bt;
	public:
		virtual void *Alloc(void)=0;
		virtual void Free(void *data)=0;
		virtual void CopyTo(void *src, void *dst)=0;
		virtual Bool Do(void *data, BaseObject *op, const Matrix &mg, Bool controlobject)=0;

		Bool Run(BaseDocument *doc, Bool spheres, Real lod, Bool uselod, BUILDFLAGS flags, void *startdata, BaseThread *bt);
};

class PriorityList
{
	private:
		PriorityList();
		~PriorityList();
	public:
		void Add(GeListNode *node, LONG priority, EXECUTIONFLAGS flags) { C4DOS.Bd->PrAdd(this,node,priority,flags); }
};

BaseDocument	*GetActiveDocument(void);
BaseDocument	*GetFirstDocument(void);
Bool					LoadFile(const Filename &name);

void InsertBaseDocument	(BaseDocument *doc);
void SetActiveDocument	(BaseDocument *doc);
void KillDocument				(BaseDocument *&doc);

BaseDocument *LoadDocument(const Filename &name, SCENEFILTER loadflags, BaseThread *thread);
Bool MergeDocument(BaseDocument *doc, const Filename &name, SCENEFILTER loadflags, BaseThread *thread);

Bool SaveDocument(BaseDocument *doc, const Filename &name, SAVEDOCUMENTFLAGS saveflags, LONG format);

BaseDocument*	IsolateObjects(BaseDocument *doc,const AtomArray &t_objects);

RENDERRESULT RenderDocument(BaseDocument *doc, const BaseContainer &rdata, ProgressHook *pr, void *private_data, BaseBitmap *bmp, RENDERFLAGS renderflags, BaseThread *th);

// editor modes
enum
{
	Mcamera	      	= 0,
	Mobject		    	= 1,
	Mtexture		  	= 3,
	Mtextureaxis  	= 4,
	Mpoints		    	= 5,
	Medges					= 6,
	Mpolygons     	= 7,
	Manimation	  	= 9,
	Mkinematic	  	= 10,
	Mmodel        	= 11,
	Mpaint        	= 12,
	Muvpoints     	= 13,
	Muvpolygons   	= 14,
	Mpolyedgepoint	= 15,		// private 
	Medgepoint			= 16,		// private
	Mworkplane			=	17,
	Mdrag						= 1000	// for dragging of handles
};

Bool InteractiveModeling_Rewind(BaseDocument *doc);
Bool InteractiveModeling_Restart(BaseDocument *doc);

void RunAnimation(BaseDocument *doc, Bool forward, Bool stop);
void SetDocumentTime(BaseDocument *doc, const BaseTime &time);
Bool CloseAllDocuments();
Bool StopExternalRenderer();

#endif
