/*	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_PathAccessor_h__
#define __data_PathAccessor_h__

#include <boost/tokenizer.hpp>

namespace fe
{

class FE_DL_EXPORT VoidAccessor
{
	public:
		VoidAccessor(void);
		VoidAccessor(const String &a_path);
		~VoidAccessor(void);
		VoidAccessor &operator=(const String &a_path);

		void	setup(	const String &a_path);

		void	*access(const Record r_in, sp<Attribute> &a_rspAttr);

		String	path(void);

	protected:
		std::list<String>	m_path;
		String				m_last;
		String				m_sep;
};

template <class T>
class FE_DL_EXPORT PathAccessor : public VoidAccessor
{
	public:
		PathAccessor(void);
		PathAccessor(const String &a_path);
		~PathAccessor(void);
		T		*operator()(const Record record);

};

template <class T>
class FE_DL_EXPORT ScopedPathAccessor
{
	public:
		ScopedPathAccessor(void);
		ScopedPathAccessor(sp<Scope> a_scope, const String &a_path);
		~ScopedPathAccessor(void);
		void	setup(sp<Scope> a_scope, const String &a_path);
		T		*operator()(const Record record);
		T		*operator()(sp<RecordArray>& rspRA, UWORD a_i);
	private:
		std::vector<Accessor<Record> >	m_path;
		Accessor<T>						m_last;
};

template <class T>
ScopedPathAccessor<T>::ScopedPathAccessor(void)
{
}

template <class T>
ScopedPathAccessor<T>::ScopedPathAccessor(sp<Scope> a_scope,
		const String &a_path)
{
	setup(a_scope, a_path);
}

template <class T>
ScopedPathAccessor<T>::~ScopedPathAccessor(void)
{
}

template <class T>
void ScopedPathAccessor<T>::setup(sp<Scope> a_scope, const String &a_path)
{
	m_path.clear();
	boost::char_separator<char> sep(".");
	typedef boost::tokenizer<boost::char_separator<char> > t_tokenizer;
	std::string std_str = a_path.c_str();
	std::vector<std::string> tokens;
	t_tokenizer tokenizer(std_str, sep);
	for(t_tokenizer::iterator i_t = tokenizer.begin();
		i_t != tokenizer.end(); ++i_t)
	{
		tokens.push_back(*i_t);
	}

	if(tokens.size() == 0)
	{
		return;
	}

	m_path.resize(tokens.size()-1);

	for(unsigned int i = 0; i < m_path.size(); i++)
	{
		m_path[i].setup(a_scope, tokens[i].c_str());
	}
	m_last.setup(a_scope, tokens[tokens.size()-1].c_str());
}

template <class T>
T *ScopedPathAccessor<T>::operator()(const Record r_in)
{
	if(m_last.index() == 0) { return NULL; }
	Record r_a = r_in;
	for(unsigned int i = 0; i < m_path.size(); i++)
	{
		Record *pRecord = m_path[i].queryAttribute(r_a);
		if(pRecord && pRecord->isValid())
		{
			r_a = *pRecord;
		}
		else
		{
			return NULL;
		}
	}

	return m_last.queryAttribute(r_a);
}


template <class T>
T *ScopedPathAccessor<T>::operator()(sp<RecordArray>& rspRA, UWORD a_i)
{
	Record r_a = rspRA->getRecord(a_i);
	return (*this)(r_a);
}

template <class T>
PathAccessor<T>::PathAccessor(void)
{
}

template <class T>
PathAccessor<T>::PathAccessor(const String &a_path)
	: VoidAccessor(a_path)
{
}

template <class T>
PathAccessor<T>::~PathAccessor(void)
{
}

template <class T>
T *PathAccessor<T>::operator()(const Record r_in)
{
	if(m_last == "") { return NULL; }
	UWORD i;
	Record r_a = r_in;
	for(std::list<String>::iterator i_r = m_path.begin();
		i_r != m_path.end(); i_r++)
	{
		sp<Attribute> &attr = r_a.layout()->scope()->findAttribute(*i_r, i);
		if(!attr.isValid())
		{
			return NULL;
		}
		if(!r_a.layout()->checkAttribute(i))
		{
			return NULL;
		}
		r_a = r_a.accessAttribute<Record>(i);
		if(!r_a.isValid())
		{
			return NULL;
		}
	}
	sp<Attribute> &attr = r_a.layout()->scope()->findAttribute(m_last, i);
	if(!attr.isValid())
	{
		return NULL;
	}
	if(!r_a.layout()->checkAttribute(i))
	{
		return NULL;
	}
	return &(r_a.accessAttribute<T>(i));
}



} /* namespace */

#endif /* __data_PathAccessor_h__ */

