#include "c4d_basedocument.h"
#include "c4d_memory.h"
#include "c4d_basetag.h"
#include "c4d_baseobject.h"
#include "c4d_basecontainer.h"
#include "c4d_basebitmap.h"
#include "c4d_raytrace.h"
#include "c4d_thread.h"
#include "c4d_general.h"

#define BdCall(fnc) (this->*C4DOS.Bd->fnc)

RenderData *RenderData::Alloc(void)
{						
	return C4DOS.Bd->RdAlloc();
}

void RenderData::Free(RenderData *&bl)
{
	C4DOS.Bl->Free(bl);
	bl=NULL;
}

PluginVideoPost *RenderData::GetFirstVideoPost()
{
	return C4DOS.Bd->RdGetFirstVideoPost(this);
}

void RenderData::InsertVideoPost(PluginVideoPost *pvp, PluginVideoPost *pred)
{
	C4DOS.Bd->RdInsertVideoPost(this,pvp,pred);
}

BaseDocument *BaseDocument::Alloc(void)
{						
	return C4DOS.Bd->Alloc();
}

void BaseDocument::Free(BaseDocument *&bl)
{
	C4DOS.Bl->Free(bl);
	bl=NULL;
}

BaseContainer BaseDocument::GetData(LONG type)
{
	BaseContainer bc;
	C4DOS.Bd->GetData(this,type,&bc);
	return bc;
}

void BaseDocument::SetData(LONG type, const BaseContainer &bc)
{
	C4DOS.Bd->SetData(this,type,&bc);
}

BaseObject *BaseDocument::GetFirstObject(void)
{
	return C4DOS.Bd->GetFirstObject(this);
}

BaseMaterial *BaseDocument::GetFirstMaterial(void)
{
	return C4DOS.Bd->GetFirstMaterial(this);
}

RenderData *BaseDocument::GetFirstRenderData(void)
{
	return C4DOS.Bd->GetFirstRenderData(this);
}

void BaseDocument::InsertRenderData(RenderData *rd, RenderData *pred)
{
	C4DOS.Bd->InsertRenderData(this,rd,pred);
}

void BaseDocument::InsertMaterial(BaseMaterial *mat, BaseMaterial *pred, Bool checknames)
{
	C4DOS.Bd->InsertMaterial(this,mat,pred,checknames);
}

void BaseDocument::InsertObject(BaseObject *op, BaseObject *parent, BaseObject *pred, Bool checknames)
{
	C4DOS.Bd->InsertObject(this,op,parent,pred,checknames);
}

RenderData *BaseDocument::GetActiveRenderData(void)
{
	return C4DOS.Bd->GetActiveRenderData(this);
}

BaseObject *BaseDocument::GetActiveObject(void)
{
	return C4DOS.Bd->GetActiveObject(this);
}

BaseObject *BaseDocument::GetHelperAxis(void)
{
	return C4DOS.Bd->GetHelperAxis(this);
}

BaseMaterial *BaseDocument::GetActiveMaterial(void)
{
	return C4DOS.Bd->GetActiveMaterial(this);
}

BaseTag *BaseDocument::GetActiveTag(void)  
{
	return C4DOS.Bd->GetActiveTag(this,NULL);
}

void BaseDocument::SetActiveObject(BaseObject *op,LONG mode)
{
	BdCall(SetActiveObject)(op,mode);
}

void BaseDocument::SetActiveMaterial(BaseMaterial *mat,LONG mode)
{
	BdCall(SetActiveMaterial)(mat,mode);
}

void BaseDocument::SetActiveTag(BaseTag *tag,LONG mode)
{
	BdCall(SetActiveTag)(tag,mode);
}

void BaseDocument::GetActiveObjects(AtomArray &selection,Bool childs) const
{
	BdCall(GetActiveObjects)(selection,childs);
}

void BaseDocument::GetActiveTags(AtomArray &selection) const
{
	BdCall(GetActiveTags)(selection);
}

void BaseDocument::GetActiveMaterials(AtomArray &selection) const 
{
	BdCall(GetActiveMaterials)(selection);
}

void BaseDocument::SetActiveRenderData(RenderData *rd)
{
	C4DOS.Bd->SetActiveRenderData(this,rd);
}

void BaseDocument::Flush(void) 
{
	C4DOS.Bd->FlushAll(this);
}

BaseObject *BaseDocument::GetHighest(LONG type, Bool editor) 
{
	return C4DOS.Bd->GetHighest(this,type,editor);
}

BaseMaterial *BaseDocument::SearchMaterial(const String &str)
{
	return C4DOS.Bd->SearchMaterial(this,&str,FALSE);
}

BaseObject *BaseDocument::SearchObject(const String &str)	
{
	return C4DOS.Bd->SearchObject(this,&str,FALSE);
}

BaseMaterial *BaseDocument::SearchMaterialInc(const String &str)
{
	return C4DOS.Bd->SearchMaterial(this,&str,TRUE);
}

BaseObject *BaseDocument::SearchObjectInc(const String &str)	
{
	return C4DOS.Bd->SearchObject(this,&str,TRUE);
}

Bool BaseDocument::GetChanged(void)
{
	BaseContainer bc;
	C4DOS.Bd->GetData(this,SETTINGS_GENERAL,&bc);
	return bc.GetBool(DOCUMENT_CHANGED);
}

void BaseDocument::SetChanged(void)
{
	BaseContainer bc;
	bc.SetBool(DOCUMENT_CHANGED,TRUE);
	C4DOS.Bd->SetData(this,SETTINGS_GENERAL,&bc);
}

void BaseDocument::SetDocumentName(const Filename &fn)
{
	BaseContainer bc;
	bc.SetFilename(DOCUMENT_NAME,fn);
	C4DOS.Bd->SetData(this,SETTINGS_GENERAL,&bc);
}

void BaseDocument::SetDocumentPath(const Filename &fn)
{
	BaseContainer bc;
	bc.SetFilename(DOCUMENT_PATH,fn);
	C4DOS.Bd->SetData(this,SETTINGS_GENERAL,&bc);
}

Filename BaseDocument::GetDocumentName(void)
{
	BaseContainer bc;
	C4DOS.Bd->GetData(this,SETTINGS_GENERAL,&bc);
	return bc.GetFilename(DOCUMENT_NAME);
}

Filename BaseDocument::GetDocumentPath(void)
{
	BaseContainer bc;
	C4DOS.Bd->GetData(this,SETTINGS_GENERAL,&bc);
	return bc.GetFilename(DOCUMENT_PATH);
}

Real BaseDocument::GetLOD(void)
{
	BaseContainer bc;
	C4DOS.Bd->GetData(this,SETTINGS_GENERAL,&bc);
	return bc.GetReal(DOCUMENT_LOD);
}

LONG BaseDocument::GetFps(void)
{
	BaseContainer bc;
	C4DOS.Bd->GetData(this,SETTINGS_GENERAL,&bc);
	return bc.GetLong(DOCUMENT_FPS);
}

BaseTime BaseDocument::GetMinTime(void)
{
	BaseContainer bc;
	C4DOS.Bd->GetData(this,SETTINGS_GENERAL,&bc);
	return bc.GetTime(DOCUMENT_MINTIME);
}

BaseTime BaseDocument::GetMaxTime(void)
{
	BaseContainer bc;
	C4DOS.Bd->GetData(this,SETTINGS_GENERAL,&bc);
	return bc.GetTime(DOCUMENT_MAXTIME);
}

BaseTime BaseDocument::GetLoopMinTime(void)
{
	BaseContainer bc;
	C4DOS.Bd->GetData(this,SETTINGS_GENERAL,&bc);
	return bc.GetTime(DOCUMENT_LOOPMINTIME);
}

BaseTime BaseDocument::GetLoopMaxTime(void)
{
	BaseContainer bc;
	C4DOS.Bd->GetData(this,SETTINGS_GENERAL,&bc);
	return bc.GetTime(DOCUMENT_LOOPMAXTIME);
}

Bool BaseDocument::GetRenderLod(void)
{
	BaseContainer bc;
	C4DOS.Bd->GetData(this,SETTINGS_GENERAL,&bc);
	return bc.GetBool(DOCUMENT_RENDERLOD);
}

void BaseDocument::SetLOD(Real lod)
{
	BaseContainer bc;
	bc.SetReal(DOCUMENT_LOD,lod);
	C4DOS.Bd->SetData(this,SETTINGS_GENERAL,&bc);
}

void BaseDocument::SetFps(LONG fps)
{
	BaseContainer bc;
	bc.SetLong(DOCUMENT_FPS,fps);
	C4DOS.Bd->SetData(this,SETTINGS_GENERAL,&bc);
}

void BaseDocument::SetMinTime(const BaseTime &t)
{
	BaseContainer bc;
	bc.SetTime(DOCUMENT_MINTIME,t);
	C4DOS.Bd->SetData(this,SETTINGS_GENERAL,&bc);
}

void BaseDocument::SetMaxTime(const BaseTime &t)
{
	BaseContainer bc;
	bc.SetTime(DOCUMENT_MAXTIME,t);
	C4DOS.Bd->SetData(this,SETTINGS_GENERAL,&bc);
}

void BaseDocument::SetLoopMinTime(const BaseTime &t)
{
	BaseContainer bc;
	bc.SetTime(DOCUMENT_LOOPMINTIME,t);
	C4DOS.Bd->SetData(this,SETTINGS_GENERAL,&bc);
}

void BaseDocument::SetLoopMaxTime(const BaseTime &t)
{
	BaseContainer bc;
	bc.SetTime(DOCUMENT_LOOPMAXTIME,t);
	C4DOS.Bd->SetData(this,SETTINGS_GENERAL,&bc);
}

void BaseDocument::SetRenderLod(Bool lod)
{
	BaseContainer bc;
	bc.SetBool(DOCUMENT_RENDERLOD,lod);
	C4DOS.Bd->SetData(this,SETTINGS_GENERAL,&bc);
}

BaseTime BaseDocument::GetTime(void)
{
	BaseContainer bc;
	C4DOS.Bd->GetData(this,SETTINGS_GENERAL,&bc);
	return bc.GetTime(DOCUMENT_TIME);
}

LONG BaseDocument::GetMode(void)
{
	BaseContainer bc;
	C4DOS.Bd->GetData(this,SETTINGS_GENERAL,&bc);
	return bc.GetLong(DOCUMENT_MODE);
}

LONG BaseDocument::GetAction(void)
{
	BaseContainer bc;
	C4DOS.Bd->GetData(this,SETTINGS_GENERAL,&bc);
	return bc.GetLong(DOCUMENT_ACTION);
}

Bool BaseDocument::IsEditMode(void)
{
	LONG mode=GetMode();
	return mode==Mpoints || mode==Mpolygons || mode==Medges; 
}

void BaseDocument::SetTime(const BaseTime &t)
{
	BaseContainer bc;
	bc.SetTime(DOCUMENT_TIME,t);
	C4DOS.Bd->SetData(this,SETTINGS_GENERAL,&bc);
}

void BaseDocument::SetMode(LONG m)
{
	BaseContainer bc;
	bc.SetLong(DOCUMENT_MODE,m);
	C4DOS.Bd->SetData(this,SETTINGS_GENERAL,&bc);
}

void BaseDocument::SetAction(LONG a)
{
	BaseContainer bc;
	bc.SetLong(DOCUMENT_ACTION,a);
	C4DOS.Bd->SetData(this,SETTINGS_GENERAL,&bc);
}

void InsertBaseDocument(BaseDocument *doc)
{
	C4DOS.Ge->InsertBaseDocument(doc);
}

void SetActiveDocument(BaseDocument *doc)
{
	C4DOS.Ge->SetActiveDocument(doc);
}

BaseDocument *GetActiveDocument(void)
{
	return C4DOS.Ge->GetActiveDocument();
}

BaseDocument *GetFirstDocument(void)
{
	return C4DOS.Ge->GetFirstDocument();
}

void KillDocument(BaseDocument *&doc)
{
	C4DOS.Ge->KillDocument(doc);
	doc=NULL;
}

Bool LoadFile(const Filename &name)
{
	return C4DOS.Ge->LoadFile(&name);
}

BaseDocument *LoadDocument(const Filename &name, Bool show_error)
{
	BaseDocument *doc=BaseDocument::Alloc();
	if (!doc) return NULL;
	if (!C4DOS.Ge->LoadDocument(doc,&name,show_error))
		blDelete(doc);
	return doc;
}

Bool SaveDocument(BaseDocument *doc, const Filename &name, Bool show_error, LONG format)
{
	return C4DOS.Ge->SaveDocument(doc,&name,show_error,format);
}

LONG RenderDocument(BaseDocument *doc, ProgressHook *pr, void *private_data, BaseBitmap *bmp, 
									  const BaseContainer &rdata, LONG renderflags, Bool dummy, Thread *th, LONG v_left, LONG v_top, LONG v_right, LONG v_bottom)
{
	return C4DOS.Ge->RenderDocument(doc,pr,private_data,bmp,&rdata,renderflags,0,th?th->Get():NULL,v_left,v_top,v_right,v_bottom);
}

Bool BaseDocument::StartUndo(void)
{
	return C4DOS.Bd->StartUndo(this);
}

Bool BaseDocument::EndUndo(void)
{
	return C4DOS.Bd->EndUndo(this);
}

Bool BaseDocument::AddUndo(LONG type, void *data)
{
	return C4DOS.Bd->AddUndo(this,type,data);
}

Bool BaseDocument::DoUndo(void)
{
	return C4DOS.Bd->DoUndo(this);
}

Bool BaseDocument::DoRedo(void)
{
	return C4DOS.Bd->DoRedo(this);
}

void BaseDocument::AnimateDocument(BaseThread *bt,Bool doexpressions,Bool doanim)
{
	C4DOS.Bd->AnimateDocument(this,bt,doexpressions,doanim);
}

void BaseDocument::AnimateObject(BaseList2D *op, const BaseTime &time, LONG flags)
{
	C4DOS.Bd->AnimateObject(this,op,time,flags);
}

BaseDocument *BaseDocument::Polygonize(void)
{
	BaseDocument	*dst=BaseDocument::Alloc(); if (!dst) return NULL;
	BaseObject		*nx=NULL,*res=NULL,*op=NULL;
	ModelingCommandData cd;
	cd.doc = dst;

	if (!CopyTo(dst,0,NULL)) goto Error;

	for (op=dst->GetFirstObject(); op; op=nx)
	{
		nx=op->GetNext();

		cd.op = op;
		if (!SendModelingCommand(MCOMMAND_CURRENTSTATETOOBJECT,cd)) goto Error;

		res = (BaseObject*)cd.result1;
		if (!res) goto Error;

		res->InsertBefore(op);
		blDelete(op);
	}

	return dst;

Error:
	blDelete(dst);
	return NULL;
}

BaseDraw *BaseDocument::GetActiveBaseDraw(void)
{
	return C4DOS.Bd->GetActiveBaseDraw(this);
}

BaseDraw *BaseDocument::GetRenderBaseDraw(void)
{
	return C4DOS.Bd->GetRenderBaseDraw(this);
}

BaseDraw *BaseDocument::GetBaseDraw(LONG num)
{
	return C4DOS.Bd->GetBaseDraw(this,num);
}

LONG BaseDocument::GetSplinePlane(void)
{
	return C4DOS.Bd->GetSplinePlane(this);
}

Bool BaseDocument::SoundCommand(LONG command)
{
	return C4DOS.Bd->SoundCommand(this,command);
}

void BaseDocument::SetRewind(LONG flags)
{
	C4DOS.Bd->SetRewind(this,flags);
}

void *HAlloc(void *main) { return ((Hierarchy*)main)->Alloc(); }
void HFree(void *main, void *data) { ((Hierarchy*)main)->Free(data); }
void HCopyTo(void *main, void *src, void *dst) { ((Hierarchy*)main)->CopyTo(src,dst); }
Bool HDo(void *main, void *data, BaseObject *op, const Matrix &mg, Bool controlobject) { return ((Hierarchy*)main)->Do(data,op,mg,controlobject); }

Bool Hierarchy::Run(BaseDocument *t_doc, Bool spheres, Real lod, LONG flags, void *startdata, BaseThread *t_bt)
{
	doc=t_doc;
	bt =t_bt;
	return C4DOS.Bd->RunHierarchy(this,doc,spheres,lod,flags,startdata,bt,HAlloc,HFree,HCopyTo,HDo);
}

LONG BaseDocument::MaterialGroup_GetCount()
{
	return C4DOS.Bd->MgGetCount(this);
}

BaseContainer* BaseDocument::MaterialGroup_Add(const BaseContainer &g)
{
	return C4DOS.Bd->MgAdd(this,g);
}

Bool BaseDocument::MaterialGroup_Remove(LONG id)
{
	return C4DOS.Bd->MgRemove(this,id);
}

BaseContainer* BaseDocument::MaterialGroup_GetID(LONG id)
{
	return C4DOS.Bd->MgGetID(this,id);
}

BaseContainer* BaseDocument::MaterialGroup_GetIndex(LONG i)
{
	return C4DOS.Bd->MgGetIndex(this,i);
}

Bool BaseDocument::MaterialGroup_IsVisible(BaseMaterial *mat)
{
	return C4DOS.Bd->MgIsVisible(this,mat);
}

