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

#include "c4d_baseeffectorplugin.h"

EffectorDataLib	*efflib_cache;

EffectorDataLib *CheckEffectorLib(LONG offset)
{
	return (EffectorDataLib*)CheckLib(BASEEFFECTORLIB_ID,offset,(C4DLibrary**)&efflib_cache);
}

Bool EffectorData::InitEffector(GeListNode *node) { return TRUE; }
void EffectorData::FreeEffector(GeListNode *node) { }
Bool EffectorData::AddToExecution(BaseObject *op, PriorityList *list)	{ list->Add(op, EXECUTION_EXPRESSION, 0); return TRUE; }
Bool EffectorData::IsInstanceOf(const GeListNode *node,LONG type) const { return type==Obaseeffector; }

Bool EffectorData::Init(GeListNode *node)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_Init));
	if (!elib || !elib->Effector_Init) return FALSE;

	if (!elib->Effector_Init(node)) return FALSE;

	return InitEffector(node);
}

void EffectorData::Free(GeListNode *node)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_Free));
	if (!elib || !elib->Effector_Free) return;

	elib->Effector_Free(node);

	FreeEffector(node);
}

LONG EffectorData::GetHandleCount(BaseObject *op)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_GetHandleCount));
	if (!elib || !elib->Effector_GetHandleCount) return 0;

	return elib->Effector_GetHandleCount(op);
}

Vector EffectorData::GetHandle(BaseObject *op, LONG i)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_GetHandle));
	if (!elib || !elib->Effector_GetHandle) return 0;

	return elib->Effector_GetHandle(op,i);
}

void EffectorData::SetHandle(BaseObject *op, LONG i, Vector p)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_SetHandle));
	if (!elib || !elib->Effector_SetHandle) return;

	elib->Effector_SetHandle(op,i,p);
}

Bool EffectorData::GetDDescription(GeListNode *node, Description *description, LONG &flags)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_GetDDescription));
	if (!elib || !elib->Effector_GetDDescription) return FALSE;

	Bool res=elib->Effector_GetDDescription(node,description,flags);

	if (!res) return FALSE;

	return ObjectData::GetDDescription(node,description,flags);
}

LONG EffectorData::Execute(BaseObject *op, BaseDocument *doc, BaseThread *bt, LONG priority, LONG flags)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_Execute));
	if (!elib || !elib->Effector_Execute) return EXECUTION_RESULT_MEMORYERROR;

	return elib->Effector_Execute(op,doc,bt,priority,flags);
}

Bool EffectorData::ExecuteEffector(BaseObject *op, BaseDocument *doc, BaseObject *gen, MoData *md, Real strength, BaseThread *thread)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_ExecuteEffector));
	if (!elib || !elib->Effector_ExecuteEffector) return FALSE;

	return elib->Effector_ExecuteEffector(op,doc,gen,md,strength,thread);
}

void EffectorData::ModifyPoints(BaseObject *op, BaseObject *gen, BaseDocument *doc, EffectorDataStruct *data, MoData *md, BaseThread *thread)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_ModifyPoints));
	if (!elib || !elib->Effector_ModifyPoints) return;

	elib->Effector_ModifyPoints(op,gen,doc,data,md,thread);
}

Bool EffectorData::ModifyObject(BaseObject *mod, BaseDocument *doc, BaseObject *op, const Matrix &op_mg, const Matrix &mod_mg, Real lod, LONG flags, BaseThread *thread)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_ModifyObject));
	if (!elib || !elib->Effector_ModifyObject) return FALSE;

	return elib->Effector_ModifyObject(mod,doc,op,op_mg,mod_mg,lod,flags,thread);
}

Bool EffectorData::Message(GeListNode *node, LONG type, void *t_data)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_Message));
	if (!elib || !elib->Effector_Message) return FALSE;

	Bool res=elib->Effector_Message(node,type,t_data);

	if (!res) return FALSE;

	return ObjectData::Message(node,type,t_data);
}

void EffectorData::GetDimension(BaseObject *op, Vector *mp, Vector *rad)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_GetDimension));
	if (!elib || !elib->Effector_GetDimension) return;

	elib->Effector_GetDimension(op,mp,rad);
}

Bool EffectorData::Draw(BaseObject *op, LONG type, BaseDraw *bd, BaseDrawHelp *bh)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_Draw));
	if (!elib || !elib->Effector_Draw) return FALSE;

	Bool res=elib->Effector_Draw(op,type,bd,bh);

	if (!res) return FALSE;

	return ObjectData::Draw(op,type,bd,bh);
}

Bool EffectorData::CopyTo(NodeData *dest,GeListNode *snode,GeListNode *dnode,LONG flags,AliasTrans *trn)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_CopyTo));
	if (!elib || !elib->Effector_CopyTo) return FALSE;

	if (!elib->Effector_CopyTo(dest,snode,dnode,flags,trn)) return FALSE;

	return ObjectData::CopyTo(dest,snode,dnode,flags,trn);
}

void EffectorData::AddEffectorDependence(BaseObject *op)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_AddEffectorDependence));
	if (!elib || !elib->Effector_AddEffectorDependence) return;

	elib->Effector_AddEffectorDependence(this->Get(),op);
}

EffectorDataStruct* EffectorData::GetEffectorData(void)
{ 
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_GetEffectorData));
	if (!elib || !elib->Effector_GetEffectorData) return NULL;

	return elib->Effector_GetEffectorData(this->Get());
}

C4D_Falloff* EffectorData::GetFalloff(void) 
{ 
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_GetFalloff));
	if (!elib || !elib->Effector_GetFalloff) return NULL;

	return elib->Effector_GetFalloff(this->Get());
}

void EffectorData::CalcPlacebo(BaseObject	*op, BaseObject	*gen, BaseDocument *doc, EffectorDataStruct *data, LONG index, MoData *md, const Vector	&globalpos, Real fall_weight)
{ 
}

//modify data->strengths values accordingly in CalcPointValue
void EffectorData::CalcPointValue(BaseObject	*op, BaseObject	*gen, BaseDocument *doc, EffectorDataStruct *data, LONG index, MoData *md, const Vector &globalpos, Real fall_weight) 
{ 
}

//called seperately as it may not be needed (and therefore sometimes might reduce number of calculations
Vector EffectorData::CalcPointColor(BaseObject *op, BaseObject *gen, BaseDocument	*doc, EffectorDataStruct *data, LONG index, MoData	*md, const Vector	&globalpos, Real fall_weight)
{
	return 1.0f;
}

LONG EffectorData::GetEffectorFlags(void) 
{	
	return EFFECTORFLAGS_HASFALLOFF; 
}

Bool EffectorData::ModifyDDescription(GeListNode *node, Description *description, AtomArray *ar) 
{ 
	return TRUE; 
}

void EffectorData::InitPoints(BaseObject *op, BaseObject *gen, BaseDocument *doc, EffectorDataStruct *data, MoData *md, BaseThread *thread) 
{ 
}

void EffectorData::FreePoints(void)	
{ 
}

//---------------------------------------
//Registration

static void FillEffectorPlugin(EFFECTORPLUGIN *np, DataAllocator *npalloc, LONG info, LONG disklevel, BaseBitmap *icon)
{
	FillNodePlugin(np,info,npalloc,icon,disklevel,NULL);

	np->command_icon					= icon;
	np->GetDimension					= &ObjectData::GetDimension;
	np->Draw									= &ObjectData::Draw;
	np->DetectHandle					= &ObjectData::DetectHandle;
	np->MoveHandle						= &ObjectData::MoveHandle; 
	np->Execute								= &ObjectData::Execute;
	np->AddToExecution				= &ObjectData::AddToExecution;
	np->GetModelingAxis				= &ObjectData::GetModelingAxis;

	np->GetEffectorData				= &EffectorData::GetEffectorData;
	np->GetFalloff						= &EffectorData::GetFalloff;
	np->AddEffectorDependence = &EffectorData::AddEffectorDependence;
	np->GetEffectorFlags			= &EffectorData::GetEffectorFlags;
	np->ModifyDDescription		= &EffectorData::ModifyDDescription;
	np->ExecuteEffector				= &EffectorData::ExecuteEffector;
	np->InitPoints						= &EffectorData::InitPoints;
	np->ModifyPoints					= &EffectorData::ModifyPoints;
	np->FreePoints						= &EffectorData::FreePoints;
	np->CalcPlacebo						= &EffectorData::CalcPlacebo;
	np->CalcPointValue				= &EffectorData::CalcPointValue;
	np->CalcPointColor				= &EffectorData::CalcPointColor;

	np->InitEffector					= &EffectorData::InitEffector;
	np->FreeEffector					= &EffectorData::FreeEffector;
}

Bool RegisterEffectorPlugin(LONG id, const String &str, LONG info, DataAllocator *g, const String &description, LONG disklevel)
{
	return RegisterEffectorPlugin(id,str,info,g,description,NULL,disklevel);
}

Bool RegisterEffectorPlugin(LONG id, const String &str, LONG info, DataAllocator *npalloc, const String &description, String icon, LONG disklevel)
{
	Bool ok=FALSE;

	if (icon.Content())
	{
		AutoAlloc<BaseBitmap> icon1;
		if (icon1 && icon1->Init(GeGetPluginPath()+String("res")+icon)==IMAGE_OK)
			ok=RegisterEffectorPlugin(id,str,info,npalloc,description,icon1,disklevel);
	}
	else
		ok=RegisterEffectorPlugin(id,str,info,npalloc,description,NULL,disklevel);

	return ok;
}



Bool RegisterEffectorPlugin(LONG id, const String &str, LONG objectinfo, DataAllocator *npalloc, const String &description, BaseBitmap *icon, LONG disklevel)
{
	// only allow registration if MoGfx is present
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_Init));
	if (!elib) return FALSE;	

	if (description.Content() && !RegisterDescription(id,description)) return FALSE;

	objectinfo |= OBJECT_MODIFIER;
	objectinfo |= OBJECT_CAMERADEPENDENT;

	EFFECTORPLUGIN np;
	ClearMem(&np,sizeof(np));
	FillEffectorPlugin(&np,npalloc,objectinfo,disklevel,icon);

	np.CheckDirty		= &ObjectData::CheckDirty;
	np.ModifyObject	= &ObjectData::ModifyObject;

	if (objectinfo&OBJECT_PARTICLEMODIFIER)
		np.ModifyParticles = &ObjectData::ModifyParticles;
	
	if (objectinfo&OBJECT_ISSPLINE) 
		np.GetContour = &ObjectData::GetContour;
	
	if (objectinfo&OBJECT_GENERATOR) 
		np.GetVirtualObjects = &ObjectData::GetVirtualObjects;

	return GeRegisterPlugin(C4DPL_OBJECT,id,str,&np,sizeof(np));
}
