///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Contains the reference tracking system.
 *	\file		IceRefTracker.h
 *	\author		Pierre Terdiman
 *	\date		April, 4, 2000
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEREFTRACKER_H__
#define __ICEREFTRACKER_H__

	// Tracker flags
	enum ICECORE_API RefTrackFlag
	{
		REFTRACK_INVALIDOFFSETS		=	(1<<0),		//!< Offsets need recomputing (lazy evaluation)
		REFTRACK_FORCE_DWORD		=	0x7fffffff
	};

	// RTYPE-related macros
	#define RTYPE_NBBITS				16
	#define RTYPE_OWNER(x)				(x&0xffff)
	#define RTYPE_REF(x)				((x>>16)&0xffff)
	#define RTYPE_SETMASK				0x0000ffff
	#define RTYPE_CLEARMASK				0xffff0000
	#define RTYPE_MAKE(owner, ref)		(((ref&0xffff)<<16)|(owner&0xffff))

	enum RTYPEOP
	{
		RTYPEOP_REPLACE		= 0,
		RTYPEOP_AND			= 1,
		RTYPEOP_OR			= 2,
		RTYPEOP_FORCE_DWORD	= 0x7fffffff
	};

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

						bool			AddRef(udword owner, udword ref, RTYPE type=0);
						bool			RemoveRef(udword owner, udword ref);
						bool			RemoveIndex(udword id);

		__forceinline	udword*			GetOwnersList()			const		{	return mOwners;							}
		__forceinline	udword*			GetRefsList()			const		{	return mRefs;							}
		__forceinline	udword			GetNbPairs()			const		{	return mCurNbPairs;						}

		__forceinline	udword			GetNbMarkedIndices()	const		{	return mMarkedIndices.GetNbEntries();	}
		__forceinline	udword*			GetMarkedIndices()		const		{	return mMarkedIndices.GetEntries();		}

//		__forceinline	udword			GetNbMarkedLinks()		const		{	return mMarkedLinks.GetNbEntries();		}
//		__forceinline	udword*			GetMarkedLinks()		const		{	return mMarkedLinks.GetEntries();		}

						udword			GetNbRefs(udword owner);
						udword			GetNbOwners(udword ref);

		__forceinline	udword			GetOwner(udword ref, udword i)
						{
							// Lazy evaluation: create valid offsets
							if(mFlags&REFTRACK_INVALIDOFFSETS)	CreateOffsets();

							return (mOwners[mSortedRefs[mRefsOffsets[ref-mMinRef]+i]]>>RTYPE_NBBITS);
						}

		__forceinline	udword			GetRef(udword owner, udword i)
						{
							// Lazy evaluation: create valid offsets
							if(mFlags&REFTRACK_INVALIDOFFSETS)	CreateOffsets();

							return (mRefs[mSortedOwners[mOwnersOffsets[owner-mMinOwner]+i]]>>RTYPE_NBBITS);
						}

						bool			PairExists(udword owner, udword ref)	{ return GetPairIndex(owner, ref)!=INVALID_ID;	}
						bool			SetType(udword owner, udword ref, RTYPE type, RTYPEOP op);

						udword			GetUsedRam();

		// Dump
						RefTracker&		Dump();

						PREVENT_COPY(RefTracker)
		private:
						udword			mFlags;					//!< Tracker flags

						udword			mMaxNbPairs;			//!< Number of dwords allocated in mOwners & mRefs
						udword			mCurNbPairs;			//!< Number of used entries
						udword*			mOwners;				//!< List of owners
						udword*			mRefs;					//!< List of references

						udword*			mSortedOwners;			//!< List of sorted owners
						udword*			mSortedRefs;			//!< List of sorted references

						udword*			mOwnersOffsets;			//!< Radix-like offsets for owners
						udword*			mRefsOffsets;			//!< Radix-like offsets for references

						udword			mMinOwner;				//!< Smallest owner index
						udword			mMinRef;				//!< Smallest reference index
						udword			mMaxOwner;				//!< Largest owner index
						udword			mMaxRef;				//!< Largest reference index

						Container		mMarkedLinks;			//!< Tags
						Container		mMarkedIndices;			//!< Tags

		// Internal methods
						bool			CreateOffsets();
						bool			PurgeList();
						udword			GetPairIndex(udword owner, udword ref);
						udword			GetPairIndex2(udword owner, udword ref);
						bool			MarkLink(udword owner, udword ref);
						bool			MarkIndex(udword id);
	};

#endif // __ICEREFTRACKER_H__
