///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Contains import-export related code.
 *	\file		IceImportExport.h
 *	\author		Pierre Terdiman
 *	\date		April, 4, 2000
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEIMPORTEXPORT_H__
#define __ICEIMPORTEXPORT_H__

#include <math.h>

	class	Cell;

	struct ICECORE_API DynamicBlock
	{
						DynamicBlock()	{ Length = 0; Data = null;			}
						~DynamicBlock()	{ Release();						}

				bool	Release()		{ DELETEARRAY(Data); return true;	}

				bool	Init(udword length)
				{
						Release();
						Data = new ubyte[length];
						CHECKALLOC(Data);
						Length = length;
						return true;
				}

				bool	Compare(DynamicBlock* blc)
				{
					if(!blc)				return false;
					if(blc->Length!=Length)	return false;
					ubyte* Data2 = blc->Data;
					for(udword i=0;i<Length;i++)
						if(Data[i]!=Data2[i])	return false;
					return true;
				}

		udword			Length;
		ubyte*			Data;
	};

	//! TO BE DOCUMENTED
	#define OFFSET_OF(Class, Member)	(size_t)&(((Class*)0)->Member)
	//! TO BE DOCUMENTED
	#define ARRAYSIZE(p)				(sizeof(p)/sizeof(p[0]))

	//! Native supported types, understood by the kernel.
	enum eFieldType
	{
		FIELD_BOOL				= 0,			//!< A bool (not a BOOL!)
		FIELD_BYTE				= 1,			//!< An sbyte or ubyte
		FIELD_WORD				= 2,			//!< An sword or uword
		FIELD_DWORD				= 3,			//!< An sdword or udword
		FIELD_FLOAT				= 4,			//!< A float
		FIELD_DOUBLE			= 5,			//!< A double
		FIELD_CELLPTR			= 6,			//!< A Cell pointer (or any pointer to a derived class)
		FIELD_STRING			= 7,			//!< A String
		FIELD_POINT				= 8,			//!< A vector = 3 floats
		FIELD_QUAT				= 9,			//!< A quaternion = 4 floats
		FIELD_PR				= 10,			//!< A PR structure (vector + quaternion)
		FIELD_PRS				= 11,			//!< A PRS structure (vector + quaternion + vector)
		FIELD_DYNABLOC			= 12,			//!< A dynamic data block (struct DynamicBlock)
		FIELD_KID				= 13,			//!< A kernel ID
		FIELD_PTR				= 14,			//!< A generic pointer (not a Cell*)
		FIELD_FORCE_DWORD		= 0x7fffffff
	};

	// Flags
	enum eFieldFlag
	{
		F_HIDDEN			= 0,				//!< Default: hidden field
		F_VISIBLE			= (1<<0),			//!< Visible field
		F_EDITABLE			= (1<<1),			//!< Editable field
		F_DUPLICABLE		= (1<<2),			//!< Duplicable field
		F_GLOBALMSGONMODIF	= (1<<3),			//!< Send a global message on field modification
		F_OWNERMSGSONMODIF	= (1<<4),			//!< Send a message to owners on field modification
		F_REFMSGSONMODIF	= (1<<5),			//!< Send a message to references on field modification
		F_SELFMSGSONMODIF	= (1<<6),			//!< Send a message to the modified cell on field modification
		F_ALL				= 0xffffffff		//!< All fields
	};

	//! TO BE DOCUMENTED
	#define _FIELD(type, name, fieldtype, count, flags, callback, user)				{ fieldtype, #name, OFFSET_OF(type, name), count, flags, callback, user }

	//! Define a single base field
	#define DEFINE_FIELD(type, name, fieldtype, flags, callback)					_FIELD(type, name, fieldtype,     1, flags, callback, 0)
	//! Define a static array of base fields
	#define DEFINE_FIELDS(type, name, fieldtype, count, flags, callback)			_FIELD(type, name, fieldtype, count, flags, callback, 0)
	//! Define a single custom field
	#define DEFINE_USER_FIELD(type, name, fieldtype, flags, callback, user)			_FIELD(type, name, fieldtype,     1, flags, callback, user)
	//! Define a static array of custom fields
	#define DEFINE_USER_FIELDS(type, name, fieldtype, count, flags, callback, user)	_FIELD(type, name, fieldtype, count, flags, callback, user)
	//! Define a dynamic array of base fields
	#define DEFINE_ARRAY(type, name, fieldtype, flags, callback)					_FIELD(type, name, fieldtype,     0, flags, callback, 0)
	//! Define a dynamic array of custom fields
	#define DEFINE_USER_ARRAY(type, name, fieldtype, flags, callback, user)			_FIELD(type, name, fieldtype,     0, flags, callback, user)

	//! TO BE DOCUMENTED
	#define BEGIN_FIELDS(currentclass)		FieldDescriptor currentclass::mClassDescriptor[] = {
	//! TO BE DOCUMENTED
	#define END_FIELDS(currentclass)		};	udword currentclass::GetDescriptorSize()	{ return ARRAYSIZE(mClassDescriptor);	}

	struct FieldDescriptor;
	//! ICE Standard modification callback
	typedef void				(*MODIFICATION)(Cell* owner, FieldDescriptor* field);

	//! A field descriptor
	struct ICECORE_API FieldDescriptor
	{
		// Compulsory values
						eFieldType		Type;			//!< Field type (bool, byte, quaternion, etc)
						char*			Name;			//!< Field name (appears exactly as in the source file)
						udword			Offset;			//!< Offset from the start of the class (ie from "this", field is located at "this"+Offset)
						uword			Count;			//!< Number of items of type Type (0 for dynamic sizes)
						uword			Flags;			//!< Field parameters
						MODIFICATION	Callback;		//!< Modification callback
		// User-defined values
						udword			UserParam;		//!< A user-defined parameter / ID to customize some fields.

						udword			FieldSize();
		__forceinline	void*			Address(Cell* cell)					{ return (void*)(udword(cell) + Offset);	}
						void			Replace(Cell* cell, void* data);
		__forceinline	void			Copy(Cell* dest, Cell* src)			{ Replace(dest, Address(src));				}
	};

	//! A field controller
	class ICECORE_API FieldController
	{
		public:
									FieldController()	{ mControlledType = FIELD_FORCE_DWORD; }
		virtual						~FieldController()	{}

				FieldController&	SetControlledType(eFieldType type)		{ mControlledType = type; return *this; }
				eFieldType			GetControlledType()						{ return mControlledType;				}

				bool				IsCompatible(FieldDescriptor& field)	{ return mControlledType==field.Type;	}

		virtual	bool				Update(Cell* cell, FieldDescriptor* field)	= 0;

		private:
				eFieldType			mControlledType;
	};

	class ICECORE_API SinusFloatController : public FieldController
	{
		public:
									SinusFloatController()	{ SetControlledType(FIELD_FLOAT); mTime = 0.0f; mAmplitude = 10.0f; }
		virtual						~SinusFloatController()	{}

		virtual	bool				Update(Cell* cell, FieldDescriptor* field)
				{
					mTime += 0.01f;
					float Value = mAmplitude * sinf(mTime);

					field->Replace(cell, &Value);

					return true;
				}

		private:
				float				mTime;
				float				mAmplitude;
	};

//  friend  HObject*     Create##currentClass()     { return new currentClass();  }

	//! TO BE DOCUMENTED
	#define DECLARE_CLASS(currentclass)		public:	char* GetClassName()	{	return #currentclass;	}

	//! TO BE DOCUMENTED
	#define DECLARE_FIELDS																				\
																										\
	static	FieldDescriptor		mClassDescriptor[];														\
																										\
	/*virtual*/ udword GetDescriptorSize();																\
	FieldDescriptor* GetDescriptor()	{	return mClassDescriptor;	}								\

	//! TO BE DOCUMENTED
	#define DECLARE_ICE_CLASS(currentclass, baseclass)													\
																										\
	private:																							\
																										\
	virtual Cell* CreateInstance()		{	return new currentclass;	}								\
																										\
	public:																								\
																										\
	DECLARE_CLASS(currentclass);																		\
																										\
	virtual	bool	IsKindOf(const char* name)	{														\
		if(strcmp(currentclass::GetClassName(), name)==0) return true;									\
		else return baseclass::IsKindOf(name);	}														\
																										\
	virtual	udword	GetLevel()					const	{ return baseclass::GetLevel() + 1;	}			\
																										\
	virtual bool GetFields(Container& edit, udword flags)												\
	{																									\
		baseclass::GetFields(edit, flags);																\
		FieldDescriptor* Fields = currentclass::GetDescriptor();										\
		for(udword i=0;i<currentclass::GetDescriptorSize();i++)											\
		{																								\
			if(Fields[i].Flags&flags)	edit.Add((udword)&Fields[i]);									\
		}																								\
		return true;																					\
	}																									\
																										\
	virtual bool GetFields(Container& edit, eFieldType type)											\
	{																									\
		baseclass::GetFields(edit, type);																\
		FieldDescriptor* Fields = currentclass::GetDescriptor();										\
		for(udword i=0;i<currentclass::GetDescriptorSize();i++)											\
		{																								\
			if(Fields[i].Type==type)	edit.Add((udword)&Fields[i]);									\
		}																								\
		return true;																					\
	}																									\
																										\
	virtual bool GetFields(Container& edit, eFieldType type, udword user)								\
	{																									\
		baseclass::GetFields(edit, type, user);															\
		FieldDescriptor* Fields = currentclass::GetDescriptor();										\
		for(udword i=0;i<currentclass::GetDescriptorSize();i++)											\
		{																								\
			if(Fields[i].Type==type && Fields[i].UserParam==user)	edit.Add((udword)&Fields[i]);		\
		}																								\
		return true;																					\
	}																									\
																										\
	virtual bool GetFields(Container& edit)																\
	{																									\
		baseclass::GetFields(edit);																		\
		FieldDescriptor* Fields = currentclass::GetDescriptor();										\
		for(udword i=0;i<currentclass::GetDescriptorSize();i++)	edit.Add((udword)&Fields[i]);			\
		return true;																					\
	}																									\
																										\
	virtual FieldDescriptor* GetFieldDescriptor(eFieldType type, udword user)							\
	{																									\
		baseclass::GetFieldDescriptor(type, user);														\
		FieldDescriptor* Fields = currentclass::GetDescriptor();										\
		for(udword i=0;i<currentclass::GetDescriptorSize();i++)											\
		{																								\
			if(Fields[i].Type==type && Fields[i].UserParam==user)	return &Fields[i];					\
		}																								\
		return null;																					\
	}																									\
																										\
	virtual udword Export(ExportContext& ec)															\
	{																									\
		if(!baseclass::Export(ec))	return 0;															\
		else return ec.Save(#currentclass, this, mClassDescriptor, currentclass::GetDescriptorSize());	\
	}																									\
																										\
	virtual udword Import(ImportContext& ic)															\
	{																									\
		if(!baseclass::Import(ic))	return 0;															\
		else return ic.Load(#currentclass, this, mClassDescriptor, currentclass::GetDescriptorSize());	\
	}


	class ICECORE_API ImportContext
	{
		public:
					ImportContext();
					~ImportContext();
		udword		Load(const char* classname, Cell* currentclass, FieldDescriptor* fields, udword nbfields);
	};

	class ICECORE_API ExportContext
	{
		public:
					ExportContext();
					~ExportContext();
		udword		Save(const char* classname, Cell* currentclass, FieldDescriptor* fields, udword nbfields);
	};


	//! TO BE DOCUMENTED
	#define DECLARE_METHODS	public:	virtual bool ExecCommand(const char* command, udword userdata=0);

	#define BEGIN_METHODS(currentclass, baseclass)									\
		bool currentclass::ExecCommand(const char* command, udword userdata)	{	\
		if(baseclass::ExecCommand(command, userdata)) return true;					\

	#define DECLARE_METHOD_0(method)				if(!command) EnumCommand(#method, userdata); else if(strcmp(command, #method)==0)		{ method();			return true; }
	#define DECLARE_METHOD_1(method, p0)			if(!command) EnumCommand(#method, userdata); else if(strcmp(command, #method)==0)		{ method(p0);		return true; }
	#define DECLARE_METHOD_2(method, p0, p1)		if(!command) EnumCommand(#method, userdata); else if(strcmp(command, #method)==0)		{ method(p0, p1);	return true; }
	#define END_METHODS		return false;	}

	//! TO BE DOCUMENTED
	typedef void* (*CLASSCREATOR)(const char* classname);

	#define DECLARE_CLASSLIST(currentapi)	GetKernel()->RegisterAPI(#currentapi, currentapi::CreateClass);
	#define BEGIN_CLASSLIST(currentapi)		void* currentapi::CreateClass(const char* name){
	#define REGISTER_CLASS(currentclass)	if(name && ::strcmp(name, #currentclass)==0)	return new currentclass;
	#define END_CLASSLIST					return null; }

	#define DECLARE_PROTECTED_CLASS(currentclass)	\
		friend void* CreateClass(const char* name);	\
		protected:	currentclass();					\
		virtual		~currentclass();				\
		public:

	// Various ways to create classes
	#define CreateICEObject(classname)	GetKernel()->CreateClass(classname)

#endif // __ICEIMPORTEXPORT_H__
