///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Contains the base class.
 *	\file		IceCell.h
 *	\author		Pierre Terdiman
 *	\date		February, 5, 2000
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICECELL_H__
#define __ICECELL_H__

	// Loop through all owners
	#define FOREACH_OWNER(cell, owner)										\
		{for(udword __idx=0;__idx<cell->GetNbOwners();__idx++){				\
			owner = cell->GetOwner(__idx);									\
			if(owner){														\

	// Loop through all references
	#define FOREACH_REF(cell, ref)											\
		{for(udword __idx=0;__idx<cell->GetNbRefs();__idx++){				\
			ref = cell->GetRef(__idx);										\
			if(ref){														\

	// Loop through all typed references
	#define FOREACH_TREF(cell, ref, type)									\
		{for(udword __idx=0;__idx<cell->GetNbRefs();__idx++){				\
			ref = cell->GetRef(__idx);										\
			if(ref && ref->GetType()==type){								\

	// Loop through all registered cells
	#define FOREACH_CELL(cell, type)										\
		{for(udword __idx=0;__idx<GetKernel()->GetNbEntries();__idx++){		\
			cell = GetKernel()->GetEntries()[__idx];						\
			if(cell && cell->GetType()==type){								\

	// End loop
	#define END_FOREACH	}}}

	//! Cell flags
	enum CellFlag
	{
		CF_VALID				=	(1<<0),		//!< Cell has successfully been initialized
		CF_KERNEL_MODIF			=	(1<<1),		//!< Kernel control: enable direct cell members modifications by the kernel
		CF_KERNEL_DESTRUCT		=	(1<<2),		//!< Kernel control: enable direct cell destruction by the kernel
		CF_KERNEL_MSGS			=	(1<<3),		//!< Enable kernel messages
		CF_KERNEL_INVALIDREF	=	(1<<4),		//!< Enable OnInvalidReference calls
		CF_FORCE_DWORD			=	0x7fffffff
	};

	//! Request types
	enum KernelRequest
	{
		KR_FIELDSIZE			=	1,			//!< Request the size of a dynamic field
		KR_FORCE_DWORD			=	0x7fffffff
	};

	class Kernel;
	class DataBlock;

	class ICECORE_API Cell
	{
										DECLARE_PROTECTED_CLASS(Cell)
		public:
		//! TO BE DOCUMENTED
		virtual			udword			Import(ImportContext& ic);
		//! TO BE DOCUMENTED
		virtual			udword			Export(ExportContext& ec);
		//! TO BE DOCUMENTED
		virtual			bool			GetFields(Container& edit, udword flags);
		virtual			bool			GetFields(Container& edit, eFieldType type);
		virtual			bool			GetFields(Container& edit, eFieldType type, udword user);
		virtual			bool			GetFields(Container& edit);
		virtual			FieldDescriptor* GetFieldDescriptor(eFieldType type, udword user);

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/**
		 *	This method is called by the kernel after a declared field has been modified.
		 *	\param		field			[in] descriptor for the modified field
		 *	\return		true if the method has been overriden
		 */
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual			bool			OnModifiedField(FieldDescriptor* field)					{ return false;							}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/**
		 *	This method is called by the kernel to request various dynamic information.
		 *	\param		kr				[in] kernel request code
		 *	\param		context			[in] request context - depends on kr
		 *	\param		data			[out] a place for the user to answer the request
		 *	\return		true if the method has been overriden
		 */
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual			bool			OnKernelRequest(KernelRequest kr, udword context, udword& data)		{ return false;				}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/**
		 *	This method is called by the kernel after a referenced cell has been dereferenced or deleted.
		 *	\param		invalidref		[in] the now invalid referenced cell
		 *	\return		true if the method has been overriden
		 *	\warning	Only called if CF_KERNEL_INVALIDREF is enabled
		 */
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual			bool			OnInvalidReference(const Cell* invalidref)				{ return false;							}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/**
		 *	This method is called by the kernel to send a message to a given cell.
		 *	\param		msg		[in] the message structure
		 *	\return		true if the method has been overriden
		 */
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual			bool			Message(const IceMsg& msg)								{ return false;							}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/**
		 *	This method sends a message to all cell owners whose type is given.
		 *	\param		msg		[in] the message structure
		 *	\param		type	[in] pointer to the type, or null to send the message to all owners
		 *	\return		true if success
		 */
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
						bool			SendMsgToOwners(const IceMsg& msg, uword* type=null);

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/**
		 *	This method sends a message to all cell references whose type is given.
		 *	\param		msg		[in] the message structure
		 *	\param		type	[in] pointer to the type, or null to send the message to all references
		 *	\return		true if success
		 */
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
						bool			SendMsgToRefs(const IceMsg& msg, uword* type=null);

		//! TO BE DOCUMENTED
						bool			CreateRef(Cell* ref);
						bool			DeleteRef(Cell* ref);
						bool			CreateRef(KID kid);
						bool			DeleteRef(KID kid);
						bool			CreateTypedRef(Cell* ref, RTYPE type);

		//! TO BE DOCUMENTED
						bool			ReplaceRef(Cell* oldref, Cell* newref);

		//! TO BE DOCUMENTED
						udword			GetNbRefs();
						udword			GetNbOwners();
						Cell*			GetOwner(udword i=0);
						Cell*			GetRef(udword i=0);

		//! TO BE DOCUMENTED
		__forceinline	KID				GetKernelID()								const		{ return m__KernelID;					}
		//! High-speed KernelID-to-cell translation
						Cell*			Translate(KID kid);

		__forceinline	uword			GetType()									const		{ return m__Type;						}
		__forceinline	Cell&			SetType(uword type)										{ m__Type = type;		return *this;	}
		__forceinline	uword			GetCount()									const		{ return m__Count;						}
		__forceinline	Cell&			IncCount()												{ m__Count++;			return *this;	}
		__forceinline	Cell&			ResetCount()											{ m__Count = 0;			return *this;	}

//		__forceinline	uword			GetFlags()									const		{ return m__Flags;						}
		__forceinline	bool			IsSet(CellFlag flag)						const		{ return (m__Flags&flag)!=0;			}
		__forceinline	Cell&			Enable(CellFlag flag)									{ m__Flags |= flag;		return *this;	}
		__forceinline	Cell&			Disable(CellFlag flag)									{ m__Flags &= ~flag;	return *this;	}

		//! Shared data blocks
						DataBlock*		CreateDataBlock(udword length);
						DataBlock*		ShareDataBlock(DataBlock* block);

		//! TO BE DOCUMENTED
		__forceinline	Cell&			SetName(const String& name)								{ m__Name = name; return *this;			}
		__forceinline	Cell&			GetName(String& name)									{ name = m__Name; return *this;			}
		__forceinline	const char*		GetName()									const		{ return m__Name.Get();					}

		//! TO BE DOCUMENTED
		virtual			bool			CanDestruct()											{ return GetNbOwners()==0;				}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/**
		 *	The self-destruction method. The kernel always deletes cells indirectly, using this method. That way the app has a way to
		 *	definitely prevent the kernel from deleting cells, by overriding this method. This should not be needed nonetheless.
		 *	\param		context		[in] destruction context
		 *	\param		userdata	[in] possible user-defined data
		 *	\return		true if the cell has been deleted
		 */
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual			bool			SelfDestruct(udword context=0, udword userdata=0)		{ delete this;	return true;			}

		//! TO BE DOCUMENTED
						Cell*			Clone(bool copymembers=true);

		//! TO BE DOCUMENTED
		virtual			bool			IsKindOf(const char* name)	{ if(strcmp(GetClassName(), name)==0) return true; else return false;	}
		virtual			udword			GetLevel()									const		{ return 0;								}														\

		//! TO BE DOCUMENTED
						DECLARE_CLASS(Cell);
						DECLARE_FIELDS;
						PREVENT_COPY(Cell)
		public:

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/**
		 *	This method executes a given command. No commands defined for Cell.
		 *	\param		command		[in] the command to execute
		 *	\param		userdata	[in] user-defined data
		 *	\return		true if success
		 */
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual			bool			ExecCommand(const char* command, udword userdata=0)		{ return false;							}
		virtual			Cell&			EnumCommand(const char* command, udword userdata=0)		{ return *this;							}
						bool			DispatchCommand(const char* command, udword userdata=0, bool refs=true);
		private:
						KID				m__KernelID;	//!< Global unique kernel identifier
						uword			m__Flags;		//!< Cell flags
						uword			m__Type;		//!< Cell type
						uword			m__Count;		//!< Runtime stats
						String			m__Name;		//!< Cell name

		static			Kernel*			m__Kernel;		//!< Shared kernel shortcut

		virtual			Cell*			CreateInstance()										{ return new Cell;						}

				friend	class			Kernel;
	};

	class ICECORE_API CellsContainer : public Container
	{
		public:
		// Constructor / Destructor
		__forceinline						CellsContainer()			{}
		__forceinline						~CellsContainer()			{}

		__forceinline	udword				GetNbCells()		const	{ return GetNbEntries();				}
		__forceinline	Cell**				GetCells()			const	{ return (Cell**)GetEntries();			}
		__forceinline	Cell*				GetCell(udword i)	const	{ return (Cell*)GetEntry(i);			}

						CellsContainer&		AddCell(const Cell* cell)	{ Add(udword(cell));	return *this;	}
	};

	class ICECORE_API DataBlock : public Cell
	{
						DECLARE_PROTECTED_CLASS(DataBlock)
						DECLARE_ICE_CLASS(DataBlock, Cell);
						DECLARE_FIELDS;

			// Initialize
						bool			Init(udword length)										{ return mBlock.Init(length);			}

						DynamicBlock	mBlock;
	};

#endif // __ICECELL_H__
