///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Contains code for ICE kernel.
 *	\file		IceKernel.h
 *	\author		Pierre Terdiman
 *	\date		April, 4, 2000
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEKERNEL_H__
#define __ICEKERNEL_H__

	// Returns the V-Table [handle with care]
	ICECORE_API VTABLE			GetVTable(Cell* cell);

	// Create a dynamic identifier
	ICECORE_API	DynID			CreateID(const String& desc);
	// Get the dynamic identifier descriptor
	ICECORE_API	const String*	GetDescriptor(DynID id);

	// Returns the global kernel
	ICECORE_API	Kernel*			GetKernel();

	// Translation shortcut
	ICECORE_API	Cell*			Translate(KID kid);

	// Greasy KID stuff ....
	#define	PTR(kid)			Translate(kid)

	//! Kernel flags
	enum KernelFlag
	{
		KF_CELL_CONTROL		=	(1<<0),		//!< Enable high-level cell control (self-destructions, etc)
		KF_MESSAGES			=	(1<<1),		//!< Enable global messages
		KF_SECURITY			=	(1<<2),		//!< Enable high-level security. Kernel is allowed to automatically disable "explosive" features.
		KF_CELL_NOTIF		=	(1<<3),		//!< Enable Kernel-to-cells notifications
		KF_CELL_MODIF		=	(1<<4),		//!< Allow the kernel to automatically fix bad pointers within cells (handle that one with care)
		KF_FORCE_DWORD		=	0x7fffffff
	};

	//! Kernel remapping modes
	enum RemappingMode
	{
		KRM_TYPE			=	0,			//!< Remap by type
		KRM_ADDRESS			=	1,			//!< Remap by address
		KRM_USER			=	2,			//!< Remap by user-defined param
		KRM_FORCE_DWORD		=	0x7fffffff
	};

	#define FLAG_CONTROL(flagtype, member)	public:																								\
	__forceinline	bool	IsSet	(flagtype flag)	const	{ return (member&flag)!=0;	}														\
	virtual			bool	Enable	(flagtype flag)			{ if(IsSet(flag)) return true;	member |= flag;		return OnModifiedFlag(flag);}	\
	virtual			bool	Disable	(flagtype flag)			{ if(!IsSet(flag)) return true;	member &= ~flag;	return OnModifiedFlag(flag);}	\
	virtual			bool	OnModifiedFlag(flagtype flag);																						\
	private:		udword	member;	public:

	//! ICE dynamic cast
	__forceinline Cell* DynamicCast(KID kid, const char* classname)
	{
		// Catch cell pointer
		Cell* tmp = PTR(kid);
		// Check type
		if(!tmp || !tmp->IsKindOf(classname))	return null;
		//
		return tmp;
	}

	//! ICE dynamic cast
	__forceinline Cell* DynamicCast(Cell* cell, const char* classname)
	{
		// Check type
		if(!cell || !cell->IsKindOf(classname))	return null;
		//
		return cell;
	}

	class ICECORE_API Kernel
	{
		public:
		// Constructor/Destructor
										Kernel();
		virtual							~Kernel();

						FLAG_CONTROL(KernelFlag, mFlags)

		// API registration & cell factory
						bool			RegisterAPI		(const char* api, CLASSCREATOR callback);
						void*			CreateClass		(const char* classname);

		// Cells registration
						bool			Register		(Cell* object);
						bool			Unregister		(Cell* object);

		// References machinery
		__forceinline	bool			CreateRef		(Cell* owner, Cell* ref)	{ return mTracker.AddRef((udword)owner->m__KernelID, (udword)ref->m__KernelID);}
		__forceinline	bool			CreateRef		(KID ownerkid, KID refkid)	{ return mTracker.AddRef((udword)ownerkid, (udword)refkid);	}
						bool			DeleteRef		(Cell* owner, Cell* ref);
						bool			DeleteRef		(KID ownerkid, KID refkid);
		// Experimental
						bool			ReplaceRef		(Cell* owner, Cell* oldref, Cell* newref);
		// Data access
		__forceinline	udword			GetNbRefs		(Cell* cell)				{ return mTracker.GetNbRefs((udword)cell->m__KernelID);		}
		__forceinline	udword			GetNbOwners		(Cell* cell)				{ return mTracker.GetNbOwners((udword)cell->m__KernelID);	}
						Cell*			GetOwner		(Cell* cell, udword i);
						Cell*			GetRef			(Cell* cell, udword i);

		__forceinline	bool			CreateTypedRef	(Cell* owner, Cell* ref, RTYPE type)	{ return mTracker.AddRef((udword)owner->m__KernelID, (udword)ref->m__KernelID, type);}

		// Cell searching
						udword			GetCells		(CellsContainer& list, udword type);
						Cell*			GetCell			(const String& name);

		// Check kernel integrity
						bool			Checkup			(bool deletelostcells=false);

		// Kernel remapping
						bool			Remap(RemappingMode mode, udword* userdefined=null);

		//! Cell access. The first entry is always the kernel itself, which is not even a cell-based component.
		//! Hence the -1 and +1 to return the relevant parts only.
		__forceinline	udword			GetNbEntries	()		const		{ return mTranslator.GetNbEntries()-1;		}
		__forceinline	udword			GetMaxNbEntries	()		const		{ return mTranslator.GetMaxNbEntries()-1;	}
		__forceinline	Cell**			GetEntries		()		const		{ return ((Cell**)mTranslator.GetList())+1;	}

		__forceinline	udword			GetTrackerRam	()					{ return mTracker.GetUsedRam();				}

		//! High-speed KernelID-to-cell translation
		__forceinline	Cell*			Translate		(KID kid)			{ return (Cell*)mTranslator.GetPointer(kid);}

		//! Cell self-destruction user-param
		__forceinline	Kernel&			SetSDUP			(udword param)		{ mSDUP = param;	return *this;			}

		// Debug
						RefTracker*		GetTracker()						{ return &mTracker; }

						PREVENT_COPY(Kernel)
		private:
						udword			mSDUP;				//!< Self-Destruction user-parameter
						RefTracker		mTracker;			//!< Reference tracker
						XList			mTranslator;		//!< Main translation module
						Container		mCallbacks;			//!< Class creators

		// Secure cell self-destruction
						Kernel&			TerminateCell	(Cell* cell);
		// Automatic reference fixing - handle with care...
						bool			FixInvalidReference(Cell* owner, Cell* badref, Cell* newref=null, bool allowmodif=true);
	};

	class ICECORE_API SmartKID
	{
		public:
										SmartKID(KID kid=INVALID_KID)	: mKid(kid)		{}
										~SmartKID()										{}

										operator void*()		{ return (void*)(udword(Translate(mKid))-INVALID_ID);	}
						Cell*			operator->()	const	{ return PTR(mKid);										}

//						SmartKID& operator= (const SmartKID& k)	{ return *this; }
//						Cell&		operator*()		const	{ return *PTR(mKid); }

		private:
						KID				mKid;

				friend	class			Kernel;
	};

#endif // __ICEKERNEL_H__
