
#include "operatingsystem.h"
#include "c4d_graphview.h"
#include "c4d_customdatatypeplugin.h"
#include "c4d_baseplugin.h"
#include "lib_description.h"
#ifndef __API_INTERN__
	#include "c4d_general.h"
#else
	#include "ge_registry.h"
#endif

CUSTOMDATATYPEPLUGIN *FindCustomDataTypePlugin(LONG type)
{
	return C4DOS.Ge->FindCustomDataTypePlugin(type);
}

RESOURCEDATATYPEPLUGIN *FindResourceDataTypePlugin(LONG type)
{
	return C4DOS.Ge->FindResourceDataTypePlugin(type);
}

BaseContainer GetCustomDataTypeDefault(LONG type)
{
	BaseContainer bc(type);
	RESOURCEDATATYPEPLUGIN *plug = FindResourceDataTypePlugin(type);
	if (plug) CallResourceDataType(plug,GetDefaultProperties)(bc);
	return bc;
}

LONG GetDataType(LONG resourcetype)
{
	if (!resourcetype) return 0;

	RESOURCEDATATYPEPLUGIN *r = FindResourceDataTypePlugin(resourcetype);
	if (!r) 
	{
		return 0;
	}
	CUSTOMDATATYPEPLUGIN *c = CallResourceDataType(r,GetCustomDataTypePlugin)();
	if (!c) 
	{
		GeBoom();
		return 0;
	}
	return CallCustomDataType(c,GetDataID)();
}

CustomProperty *CustomDataTypeClass::GetProperties()
{
	return NULL;
}

LONG CustomDataTypeClass::GetDataID()
{
	return GetId();
}

LONG CustomDataTypeClass::GetValueID()
{
	return GetId();
}

void CustomDataTypeClass::GetDefaultProperties(BaseContainer &data)
{
}

LONG CustomDataTypeClass::GetConversionsFrom(LONG *&table)
{
	defaultconversiontype = GetValueID();
	table = &defaultconversiontype;
	return 1;
}

LONG CustomDataTypeClass::GetConversionsTo(LONG *&table)
{
	defaultconversiontype = GetValueID();
	table = &defaultconversiontype;
	return 1;
}

GvError CustomDataTypeClass::ConvertFromGv(LONG type,const void *const src,LONG cpu_id,CustomDataType *dst)
{
	return GV_CALC_ERR_UNDEFINED;
}

GvError CustomDataTypeClass::ConvertToGv(LONG type,const CustomDataType *src,void *dst,LONG cpu_id)
{
	return GV_CALC_ERR_UNDEFINED;
}

GvValueFlags CustomDataTypeClass::GetCalculationFlags()
{
	return GV_CALC_NOP;
}

GvError CustomDataTypeClass::Calculate(LONG calculation,const CustomDataType *src1, const CustomDataType *src2, CustomDataType *dst, Real parm1)
{
	return GV_CALC_ERR_UNDEFINED;
}

struct Helper
{
	CustomDataType **data;
};

Bool CustomDataTypeClass::ConvertGeDataToGv(const GeData &src,void *t_dst,LONG cpu_id)
{
	Helper *dst = (Helper*)t_dst;
	if (!dst || !dst->data[cpu_id]) return FALSE;
	const CustomDataType *s = src.GetCustomDataType(GetValueID());
	if (!CopyData(s,dst->data[cpu_id],NULL)) return FALSE;
	return TRUE;
}

Bool CustomDataTypeClass::ConvertGvToGeData(const void *const t_src,LONG cpu_id,GeData &dst)
{
	Helper *src = (Helper*)t_src;
	if (!src || !src->data[cpu_id]) return FALSE;
	dst = GeData(GetValueID(),*src->data[cpu_id]);

	return TRUE;
}

GV_VALUE_HANDLER *CustomDataTypeClass::GetGvValueHandler()
{
	if (valuehandler==(GV_VALUE_HANDLER*)-1) return NULL;
	if (valuehandler) return valuehandler;

	GV_VALUE_HANDLER *val;

	Registry *reg = NULL;	
	for (reg = GeRegistryGetFirst(REGISTRYTYPE_GV_VALUE); reg; reg = reg->GetNext())
	{
		val = (GV_VALUE_HANDLER*)reg->GetData(); 
		if (val->value_id==GetValueID())
		{
			valuehandler = val;
			return val;
		}
	}
	GeBoom();
	
	valuehandler = (GV_VALUE_HANDLER*)-1;
	return NULL;
}

GvError CustomDataTypeClass::ConvertToGeData(LONG dst_type,const CustomDataType *src,GeData &dst)
{
	if (dst_type!=GetId() || !src) return GV_CALC_ERR_UNDEFINED;

	dst = GeData(dst_type,*src);
	if (dst.GetType()!=DA_NIL) return (GvError)0;
	return GV_CALC_ERR_UNDEFINED;
}

Bool CustomDataTypeClass::_GetDescription(const CustomDataType *data,Description &res,DESCFLAGS_DESC &flags,const BaseContainer &parentdescription,DescID *singledescid)
{
	return (flags&DESCFLAGS_DESC_LOADED)!=DESCFLAGS_DESC_0;
}

Bool CustomDataTypeClass::GetParameter(const CustomDataType *data,const DescID &id,GeData &t_data,DESCFLAGS_GET &flags)
{
	return (flags&DESCFLAGS_GET_PARAM_GET)!=DESCFLAGS_GET_0;
}

Bool CustomDataTypeClass::SetDParameter(CustomDataType *data,const DescID &id,const GeData &t_data,DESCFLAGS_SET &flags)
{
	return (flags&DESCFLAGS_SET_PARAM_SET)!=DESCFLAGS_SET_0;
}

Bool CustomDataTypeClass::GetEnabling(const CustomDataType *data,const DescID &id,const GeData &t_data,DESCFLAGS_ENABLE &flags,const BaseContainer *itemdesc)
{
	return TRUE;
}

Bool CustomDataTypeClass::InterpolateKeys(GeData &res, const GeData &t_data1,const GeData &t_data2,Real mix,LONG flags)
{
	return FALSE;
}

void CustomDataTypeClass::CheckData(const BaseContainer &bc,GeData &data)
{
}

Bool RegisterCustomDataTypePlugin(const String &str, LONG info, CustomDataTypeClass *dat,LONG disclevel)
{
	if (!dat) return FALSE;

	LONG id = dat->GetId(); 

	CUSTOMDATATYPEPLUGIN np;
	ClearMem(&np,sizeof(np));

	np.adr									= dat;
	np.info									= info;
	np.Destructor						= &BaseData::Destructor;
													
	np.disclevel						= disclevel;
	np.AllocData						=	&CustomDataTypeClass::AllocData						;
	np.FreeData							=	&CustomDataTypeClass::FreeData						;
	np.CopyData							=	&CustomDataTypeClass::CopyData						;
	np.Compare							=	&CustomDataTypeClass::Compare							;
	np.WriteData						= &CustomDataTypeClass::WriteData						;
	np.ReadData							= &CustomDataTypeClass::ReadData						;	
	np.GetResourceSym				= &CustomDataTypeClass::GetResourceSym			;	
	np.GetProperties				= &CustomDataTypeClass::GetProperties				;
	np.GetDefaultProperties = &CustomDataTypeClass::GetDefaultProperties;

	np.GetConversionsFrom		= &CustomDataTypeClass::GetConversionsFrom	;
	np.ConvertFromGv				= &CustomDataTypeClass::ConvertFromGv				;

	np.GetConversionsTo			= &CustomDataTypeClass::GetConversionsTo		;
	np.ConvertToGv					= &CustomDataTypeClass::ConvertToGv					;
	np.ConvertToGeData			= &CustomDataTypeClass::ConvertToGeData			;

	np.GetCalculationFlags	= &CustomDataTypeClass::GetCalculationFlags	;
	np.Calculate						= &CustomDataTypeClass::Calculate						;
	
	np.GetGvValueHandler		= &CustomDataTypeClass::GetGvValueHandler		;

	np.ConvertGeDataToGv		= &CustomDataTypeClass::ConvertGeDataToGv		;
	np.ConvertGvToGeData		= &CustomDataTypeClass::ConvertGvToGeData		;

	np.GetValueID						= &CustomDataTypeClass::GetValueID					;
	np.GetDataID						= &CustomDataTypeClass::GetDataID						;

	np._GetDescription			= &CustomDataTypeClass::_GetDescription			;
	np.GetParameter					= &CustomDataTypeClass::GetParameter				;
	np.SetDParameter				= &CustomDataTypeClass::SetDParameter				;
	np.GetEnabling					= &CustomDataTypeClass::GetEnabling					;
	np.CheckData						= &CustomDataTypeClass::CheckData						;
	np.InterpolateKeys      = &CustomDataTypeClass::InterpolateKeys;

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



ResourceDataTypeClass::ResourceDataTypeClass(LONG t_datatypeid,CUSTOMDATATYPEPLUGIN *t_datatype)
{
	datatypeid = t_datatypeid;
	datatype   = t_datatype;
}

CustomProperty *ResourceDataTypeClass::GetProperties()
{
	return CallCustomDataType(datatype,GetProperties)();
}

const CHAR *ResourceDataTypeClass::GetResourceSym()
{
	return CallCustomDataType(datatype,GetResourceSym)();
}

void ResourceDataTypeClass::GetDefaultProperties(BaseContainer &data)
{
	CallCustomDataType(datatype,GetDefaultProperties)(data);
}

LONG ResourceDataTypeClass::GetCustomDataType()
{
	return datatypeid;
}

CUSTOMDATATYPEPLUGIN *ResourceDataTypeClass::GetCustomDataTypePlugin()
{
	return datatype;
}

Bool ResourceDataTypeClass::GetDescription(const CustomDataType *data,Description &res,DESCFLAGS_DESC &flags,const BaseContainer &parentdescription,DescID *singledescid)
{
	return CallCustomDataType(datatype,_GetDescription)(data,res,flags,parentdescription,singledescid);
}

void ResourceDataTypeClass::CheckData(const BaseContainer &bc,GeData &data)
{
	CallCustomDataType(datatype,CheckData)(bc,data);
}


Bool RegisterResourceDataTypePlugin(const String &str, LONG info, ResourceDataTypeClass *dat,LONG disclevel)
{
	if (!dat) return FALSE;

	LONG id = dat->GetId(); 

	RESOURCEDATATYPEPLUGIN np;
	ClearMem(&np,sizeof(np));

	np.adr											= dat;
	np.info											= info;
	np.Destructor								= &BaseData::Destructor;
															
	np.disclevel								= disclevel;

	np.GetResourceSym						= &ResourceDataTypeClass::GetResourceSym					;	
	np.GetProperties						= &ResourceDataTypeClass::GetProperties						;
	np.GetDefaultProperties			= &ResourceDataTypeClass::GetDefaultProperties		;
	np.GetCustomDataTypePlugin	= &ResourceDataTypeClass::GetCustomDataTypePlugin	;
	np.GetDescription						= &ResourceDataTypeClass::GetDescription					;
	np.CheckData								= &ResourceDataTypeClass::CheckData								;

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