/*	Copyright (C) 2003-2008 Free Electron Organization
	Any use of this software requires a license.  If a valid license
	was not distributed with this file, visit freeelectron.org. */

#ifndef __data_RecordSB_h__
#define __data_RecordSB_h__

namespace fe
{

#define FE_RECORD_COUNT_DEBUG	FALSE

class LayoutSB;

template <class T>
class Accessor;

/* TODO:
	private RecordArray data
	remove RecordArray friend from Record
	remove WeakRecord friend from Record
	remove offset table exposure from layout
*/

/**	@brief Reference to an instance of a Layout

	@ingroup data

	A record is simply a pointer to a Layout and a pointer to a
	state block.  A state block is a block of memory with Attributes laid
	out as specified by a Layout object.
	*/
class FE_DL_EXPORT RecordSB
{
	friend class WeakRecordSB;
	friend class LayoutSB;
	friend class RecordArraySB;
	friend class SegmentStore;
	public:
		RecordSB(I32 ignored=0);
		RecordSB(const RecordSB &other);
virtual	~RecordSB(void);

		RecordSB	&operator=(const RecordSB &r_other);

		bool	operator==(const RecordSB &r_other) const;
		bool	operator!=(const RecordSB &r_other) const;

		/** Return a unique runtime id (id-runtime, idr, since 'rid' has
			other meaning. */
		UWORD		idr(void) const;

		/** Return true if the Record points to a valid state block. */
		bool		isValid(void) const;
		/** Return the Layout. */
		sp<Layout>	layout(void) const;

		bool		extractInstance(Instance &instance, const String &attrName);

		RecordSB		clone(void);
		//RecordSB		deepclone(void);


		template <class T>
		T			&accessAttribute(UWORD aLocator) const;

		void		*rawAttribute(UWORD aLocator) const;

	private:
		/** Return the state block. */
		void		*data(void) const;
		/** Return a raw pointer to the Layout.  Mainly intended for Accessor
			for speed. */
		LayoutSB	*rawLayout(void) const;

	private:
		void		acquire(void);
		void		release(void);
		/** Set the state block. */
		void		set(void *datablock);

	private:
		sp<LayoutSB>		m_spLayout;
		void				*m_pStateBlock;
};

struct hash_record_sb
{ UWORD operator()(const RecordSB r_rec) const
	{ return r_rec.idr() % 17191; } };

inline bool operator<(const RecordSB &lhs, const RecordSB &rhs)
{
	return (lhs.idr() < rhs.idr());
}

class RecordSBInfo : public BaseType::Info
{
	public:
virtual	String	print(void *instance);
virtual	IWORD	output(std::ostream &ostrm, void *instance, t_serialMode mode);
virtual	void	input(std::istream &istrm, void *instance, t_serialMode mode);
virtual	IWORD	iosize(void);
virtual	bool	getConstruct(void);
virtual	void	construct(void *instance);
virtual	void	destruct(void *instance);
};

inline RecordSB::RecordSB(I32)
{
	m_pStateBlock = NULL;
}

inline RecordSB::RecordSB(const RecordSB &other)
{
	m_spLayout = other.m_spLayout;
	m_pStateBlock = other.m_pStateBlock;
	acquire();
}

/*
inline Record::Record(void *datablock)
{
	m_pStateBlock = datablock;
	acquire();
	m_spLayout = FE_SB_TO_HDR(m_pStateBlock)->m_pStore->getLayout();
}
*/

inline RecordSB::~RecordSB(void)
{
	release();
}

inline LayoutSB *RecordSB::rawLayout(void) const
{
	return m_spLayout.raw();
}

inline RecordSB &RecordSB::operator=(const RecordSB &other)
{
	if(this != &other)
	{
		release();
		m_spLayout = other.m_spLayout;
		m_pStateBlock = other.m_pStateBlock;
		acquire();
	}
	return *this;
}

inline bool RecordSB::operator==(const RecordSB &other) const
{
	return (m_pStateBlock == other.m_pStateBlock);
}

inline bool RecordSB::operator!=(const RecordSB &other) const
{
	return (m_pStateBlock != other.m_pStateBlock);
}

inline void *RecordSB::data(void) const
{
	return m_pStateBlock;
}

inline UWORD RecordSB::idr(void) const
{
	return reinterpret_cast<UWORD>(m_pStateBlock);
}

template <class T>
inline T &RecordSB::accessAttribute(UWORD aLocator) const
{
	return *((T *)((char *)(data()) + m_spLayout->offsetTable()[aLocator]));
}

inline void *RecordSB::rawAttribute(UWORD aLocator) const
{
	return (void *)((char *)(data()) + m_spLayout->offsetTable()[aLocator]);
}

inline bool RecordSB::isValid(void) const
{
	return (m_pStateBlock != NULL);
}

inline sp<Layout> RecordSB::layout(void) const
{
	return m_spLayout;
}

inline void RecordSB::set(void *datablock)
{
	release();
	m_pStateBlock = datablock;
	acquire();
	m_spLayout = FE_SB_TO_HDR(m_pStateBlock)->m_pStore->getLayout();
}

inline void RecordSB::release(void)
{
#if FE_RECORD_COUNT_DEBUG
	register UWORD index;
	if(m_spLayout.isValid())
	{
		m_spLayout->scope()->findAttribute(FE_C,index);
		if(m_spLayout->offsetTable()[index] != offsetNone)
		{
			IWORD &count= *((IWORD *)((char *)(data()) +
											layout()->offsetTable()[index]));

			fprintf(stderr,"Release %p %d->%d %s\n",(U32)this,count,count-1,
					m_spLayout->name().c_str());
		}
	}
#endif

	if(m_pStateBlock)
	{
#if FE_COUNTED_TRACK
		Counted::untrackReference(FE_SB_TO_HDR(m_pStateBlock),&m_pStateBlock);
//		Counted::untrackReference(this,this);
//		Counted::deregisterRegion(this);
#endif
		FE_SB_TO_HDR(m_pStateBlock)->m_pStore->releaseSB(*this);
	}
}

inline void RecordSB::acquire(void)
{
#if FE_RECORD_COUNT_DEBUG
	register UWORD index;
	if(m_spLayout.isValid())
	{
		m_spLayout->scope()->findAttribute(FE_C,index);
		if(m_spLayout->offsetTable()[index] != offsetNone)
		{
			IWORD &count= *((IWORD *)((char *)(data()) +
										m_spLayout->offsetTable()[index]));

			fprintf(stderr,"Acquire %p %d->%d %s\n",(U32)this,count,count+1,
					m_spLayout->name().c_str());
		}
	}
#endif

	if(m_pStateBlock)
	{
		FE_SB_TO_HDR(m_pStateBlock)->m_pStore->acquireSB(m_pStateBlock);
#if FE_COUNTED_TRACK
//		Counted::registerRegion(this,sizeof(Record),"Record "+
//				(m_spLayout.isValid()? m_spLayout->name(): "<invalid>"));
//		Counted::trackReference(this,this);
		Counted::trackReference(FE_SB_TO_HDR(m_pStateBlock),&m_pStateBlock,
				"RecordSB");
#endif
	}
}

} /* namespace */

#endif /* __data_RecordSB_h__ */
