/*	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_LayoutAV_h__
#define __data_LayoutAV_h__

namespace fe
{

class Scope;
class RecordAV;
class BaseAccessor;


/** @brief Record "type" definition

	@ingroup data

	A Layout is a definition of Attribute layout in Record instances.

	Layout objects can only be created via a Scope.  For typical use
	all operations on Layout objects are also done through Scope methods.

	@todo full data system guide
	*/
class FE_DL_EXPORT LayoutAV: public Layout, public Initialize<LayoutAV>,
		public ClassSafe<GlobalHolder>
{
	friend class RecordAV;
	friend class WeakRecordAV;
	friend class RecordArrayAV;
	public:
		LayoutAV(sp<Scope> &scope);
		LayoutAV(sp<Scope> &scope, const String &name);
		LayoutAV(Scope *pScope, const String &name);
	private:
		LayoutAV(const LayoutAV &other);
		LayoutAV &operator=(const LayoutAV &other);
	public:
virtual	~LayoutAV(void);

		LayoutAV		&copy(const LayoutAV &other);
virtual	void			initialize(void);

		/** Convienience function to Scope::populate */
virtual	void			populate(const String &attribute_name);
		/** Convienience function to Scope::populate */
virtual	void			populate(const String &attribute_name,
								const String &attribute_type);
		/** Convienience function to Scope::populate.  This particular one
			does a check if the layout is locked and if so verifys the
			exsitence of the attribute. */
virtual	void			populate(const BaseAccessor &accessor);
		/** Convienience function to Scope::populate */
virtual	void			populate(sp<Attribute> spAttribute);
		/** Convienience function to Scope::populate */
		void			populate(sp<LayoutAV> spLayout);

virtual	void			setName(const String &name);
virtual	const String&	name(void) const;
virtual	const String	verboseName(void) const;

virtual	void			setConstruct(bool construct);
virtual	const bool		&construct(void) const;

virtual	hp<Scope>&		scope(void);


virtual	void			peek(Peeker &peeker);

		RecordAV		createRecord(void);

virtual	bool			checkAttribute(UWORD a_locator) const;
virtual	bool			checkAttributeStr(const String &a_name);
virtual	void			resizeLocatorTable(UWORD a_size);

		void			createRecord(RecordAV &r_new);
		void			freeRecord(RecordAV &r_old);
		void			freeArrayIndex(const UWORD &aArrayIndex);

virtual	void			notifyOfAttributeChange(sp<Depend> &depend);

	private:
						LayoutAV(void);
		void			constructor(sp<Scope> &scope);

		void			addMissingAttributes(void);
		void			assignDefaultAttributes(RecordAV &r_new);
		void			destructAttributes(const UWORD &a_arrayIndex);

		std::vector< sp<BaseTypeVector> >	&attributeVector(void);
		std::vector< UWORD >				&locatorTable(void);
		const UWORD							&idr(const UWORD &a_index) const;
		void					acquireArrayIndex(const UWORD &aArrayIndex);
		void					releaseArrayIndex(const UWORD &aArrayIndex);

		unsigned int		serialIndex(void) const { return m_serialIndex; }

	private:
static	FE_DL_PUBLIC UWORD					ms_unique;
static	FE_DL_PUBLIC UWORD					ms_record_idr;
		String								m_name;
		hp<Scope>							m_hpScope;
		std::vector< sp<BaseTypeVector> >	m_attributeVector;
		std::vector< UWORD >				m_locatorTable;
		std::vector< UWORD >				m_idr;
		std::set< UWORD >					m_freeList;
		UWORD								m_avSize;
		sp< TypeVector<int> >				m_rc;
		sp< TypeVector<int> >				m_sn;
		bool								m_construct;
		unsigned int						m_serialIndex;

	public:
static
const	FE_DL_PUBLIC UWORD					locatorNone = (UWORD)(-1);
static
const	FE_DL_PUBLIC UWORD					arrayindexNone = (UWORD)(-1);
};

#if FE_DATA_STORE==FE_AV
typedef LayoutAV LayoutDefault;
#endif

inline bool LayoutAV::checkAttribute(UWORD aLocator) const
{
	return (m_locatorTable[aLocator] != locatorNone);
}

inline const UWORD &LayoutAV::idr(const UWORD &aIndex) const
{
	return m_idr[aIndex];
}

inline std::vector< sp<BaseTypeVector> > &LayoutAV::attributeVector(void)
{
	return m_attributeVector;
}

inline std::vector< UWORD > &LayoutAV::locatorTable(void)
{
	return m_locatorTable;
}

inline void LayoutAV::setName(const String &name)
{
	SAFEGUARD;
	m_name = name;
}
inline const String& LayoutAV::name(void) const
{
	SAFEGUARD;
	return m_name;
}
inline const String LayoutAV::verboseName(void) const
{
	return "Layout " + name();
}

inline void LayoutAV::setConstruct(bool construct)
{
	SAFEGUARD;
	m_construct = construct;
}
inline const bool &LayoutAV::construct(void) const
{
	SAFEGUARD;
	return m_construct;
}

inline hp<Scope>& LayoutAV::scope(void)
{
	SAFEGUARD;
	return m_hpScope;
}

inline void LayoutAV::acquireArrayIndex(const UWORD &aArrayIndex)
{
	if(m_rc.isValid())
	{
		m_rc->at(aArrayIndex)++;
	}
	else
	{
		feX("RC is on by default, should not get here");
	}
}

inline void LayoutAV::releaseArrayIndex(const UWORD &aArrayIndex)
{
	if(m_rc.isValid())
	{
		int &rc = m_rc->at(aArrayIndex);
		rc--;
		if(rc == 0)
		{
			destructAttributes(aArrayIndex);
			freeArrayIndex(aArrayIndex);
		}
	}
}

} /* namespace */

#endif /* __data_LayoutAV_h__ */

