// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010  Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#ifndef NL_TEMPLATIZER_H
#define NL_TEMPLATIZER_H

#include <nel/misc/types_nl.h>
#include <nel/misc/common.h>
#include <nel/misc/debug.h>
#include <nel/misc/eval_num_expr.h>

#include <vector>
#include <string>
#include <map>

class ITemplatizerBloc;

const char	EnvSeparator = '/';








/**
 * A Templatizer Env
 */
class CTemplatizerEnv : public NLMISC::CEvalNumExpr
{
public:

	/// Constructor
	CTemplatizerEnv(CTemplatizerEnv* parent) : Parent(parent), CurrentArrayNode(0)	{ }

	/// Destructor
	virtual ~CTemplatizerEnv();

	/// Clear Env
	virtual void		clear();

	/// Get value
	virtual std::string	get(const std::string& name);

	/// Set value
	template<typename T>
	void		set(const std::string& name, const T& value)
	{
		std::string::size_type dotpos = name.find(EnvSeparator);
		std::string		child = name.substr(0, dotpos);

		if (dotpos == std::string::npos)
		{
			setAsRawText(name, NLMISC::toString(value));
		}
		else
		{
			getEnv(child)->set(name.substr(dotpos+1), value);
		}
	}

	/// Set a Define
	void				define(const std::string& name)
	{
		set(name, 1);
	}

	/// Set a Conditional Define
	void				define(bool isdef, const std::string& name)
	{
		if (isdef)
			set(name, 1);
	}

	/// Does Variable exist?
	virtual bool		exists(const std::string& name) const
	{
		TValueMap::const_iterator	it = Values.find(name);
		if (it == Values.end())
			return (Parent == NULL ? false : Parent->exists(name));
		return true;
	}

	/// Does Sub Environment exist?
	virtual bool		envExists(const std::string& name) const
	{
		std::string::size_type dotpos = name.find(EnvSeparator);
		std::string		child = name.substr(0, dotpos);

		if (child.empty())
			return true;

		TEnvMap::const_iterator	it = Envs.find(child);
		if (it == Envs.end())
			return false;

		return (dotpos == std::string::npos) ? true : (*it).second->envExists(name.substr(dotpos+1));
	}

	/// Enter Sub Env, like getEnv() but it doesn't look in parent, and always goes in current env
	virtual CTemplatizerEnv*	getSubEnv(const std::string& name)
	{
		std::string::size_type dotpos = name.find(EnvSeparator);
		std::string		child = name.substr(0, dotpos);

		if (child.empty())
			return this;

		CTemplatizerEnv*	env = NULL;

		if (child == ".")
		{
			env = this;
		}
		else if (child == "..")
		{
			env = (Parent != NULL ? Parent : this);
		}
		else if (child == "...")
		{
			env = getRootEnv();
		}
		else
		{
			TEnvMap::iterator	it = Envs.find(child);
			if (it != Envs.end())
			{
				env = (*it).second;
			}
			else
			{
				env = new CTemplatizerEnv(this);
				Envs[child] = env;
			}

		}

		return (dotpos == std::string::npos) ? env : env->getSubEnv(name.substr(dotpos+1));
	}

	/// Get Sub Env
	virtual CTemplatizerEnv*	getEnv(const std::string& name)
	{
		std::string::size_type dotpos = name.find(EnvSeparator);
		std::string		child = name.substr(0, dotpos);

		if (child.empty())
			return this;

		if (child == ".")
		{
			return (dotpos == std::string::npos) ? this : this->getSubEnv(name.substr(dotpos+1));
		}
		else if (child == "..")
		{
			CTemplatizerEnv*	env = (Parent != NULL ? Parent : this);
			return (dotpos == std::string::npos) ? env : env->getSubEnv(name.substr(dotpos+1));
		}
		else if (child == "...")
		{
			CTemplatizerEnv*	env = getRootEnv();
			return (dotpos == std::string::npos) ? env : env->getSubEnv(name.substr(dotpos+1));
		}
		else
		{
			TEnvMap::iterator	it = Envs.find(child);
			if (it != Envs.end())
			{
				return (dotpos == std::string::npos) ? (*it).second : (*it).second->getSubEnv(name.substr(dotpos+1));
			}
			else
			{
				return Parent != NULL ? Parent->getEnv(name) : getSubEnv(name);
			}
		}
	}

	/// Get Sub Env
	CTemplatizerEnv*	getEnv(uint node)
	{
		return getEnv(NLMISC::toString("%08X", node));
	}

	/// Evaluate string (string replacement)
	virtual std::string		eval(const std::string& text);

	/// Get Next Array Node
	CTemplatizerEnv*	nextArrayNode(const std::string& array)
	{
		CTemplatizerEnv*	aenv = getSubEnv(array);
		uint				node = (aenv->CurrentArrayNode)++;
		return aenv->getSubEnv(NLMISC::toString("%08X", node));
	}

	/// Set Sub Env
	virtual void		setSubEnv(const std::string& name, CTemplatizerEnv* subenv)
	{
		Envs[name] = subenv;
	}

	/// Get Parent Env
	virtual CTemplatizerEnv*	getParent()
	{
		return Parent;
	}

public:

	/// Parent Env
	CTemplatizerEnv*	Parent;

	typedef std::map<std::string, ITemplatizerBloc*>	TValueMap;
	typedef std::map<std::string, CTemplatizerEnv*>		TEnvMap;

	/// Contained Values
	TValueMap			Values;

	/// Sub Env
	TEnvMap				Envs;

	/// Get Root Env
	virtual CTemplatizerEnv*	getRootEnv()
	{
		CTemplatizerEnv*	root = this;
		while (root->getParent() != NULL)
			root = root->getParent();

		return root;
	}

	/// Current Array Node
	uint				CurrentArrayNode;

	/// Set As Raw Text
	virtual void		setAsRawText(const std::string& name, const std::string& text);

	/// Set Value Node
	virtual void		setValueNode(const std::string& name, ITemplatizerBloc* bloc)
	{
		Values[name] = bloc;
	}

	/// Get Value Node
	virtual ITemplatizerBloc*	getValueNode(const std::string& name)
	{
		ITemplatizerBloc*	node = NULL;
		CTemplatizerEnv*	env = NULL;
		return getValueNodeAndEnv(name, node, env) ? node : NULL;
	}

	/// Get Value Node
	virtual bool		getValueNodeAndEnv(const std::string& name, ITemplatizerBloc*& node, CTemplatizerEnv*& env)
	{
		std::string::size_type pos = name.find_last_of(EnvSeparator);
		if (pos == std::string::npos)
		{
			node = getNode(name);
			env = this;
			while (node == NULL && env != NULL)
			{
				env = env->getParent();
				if (env != NULL)
					node = env->getNode(name);
			}
		}
		else
		{
			env = getEnv(name.substr(0, pos));
			if (env != NULL)
				node = env->getNode(name.substr(pos+1));
		}

		return node != NULL && env != NULL;
	}

	virtual ITemplatizerBloc*	getNode(const std::string& name)
	{
		TValueMap::iterator	it = Values.find(name);
		return it == Values.end() ? NULL : (*it).second;
	}

	virtual NLMISC::CEvalNumExpr::TReturnState	evalValue (const char *value, double &result, uint32 userData);
};


/**
 * A Templatizer Env
 */
class CTemplatizerRefEnv : public CTemplatizerEnv
{
public:

	/// Constructor
	CTemplatizerRefEnv(CTemplatizerEnv* ref) : CTemplatizerEnv(NULL), Reference(ref)	{ }

	/// Clear Env
	virtual void		clear()
	{
		Reference = NULL;
	}

	/// Get value
	virtual std::string	get(const std::string& name)
	{
		return Reference->get(name);
	}

	/// Does Variable exist?
	virtual bool		exists(const std::string& name) const
	{
		return Reference->exists(name);
	}

	/// Does Sub Environment exist?
	virtual bool		envExists(const std::string& name) const
	{
		return Reference->envExists(name);
	}

	/// Get Sub Env
	virtual CTemplatizerEnv*	getEnv(const std::string& name)
	{
		return Reference->getEnv(name);
	}

	/// Evaluate string (string replacement)
	virtual std::string			eval(const std::string& text)
	{
		return Reference->eval(text);
	}

	/// Enter Sub Env, like getEnv() but it doesn't look in parent, and always goes in current env
	virtual CTemplatizerEnv*	getSubEnv(const std::string& name)
	{
		return Reference->getSubEnv(name);
	}

	/// Get Parent Env
	virtual CTemplatizerEnv*	getParent()
	{
		return Reference->getParent();
	}
public:

	CTemplatizerEnv*	Reference;

	/// Get Root Env
	virtual CTemplatizerEnv*	getRootEnv()
	{
		return Reference->getRootEnv();
	}

	/// Set As Raw Text
	virtual void		setAsRawText(const std::string& name, const std::string& text)
	{
		Reference->setAsRawText(name, text);
	}

	/// Set Value Node
	virtual void		setValueNode(const std::string& name, ITemplatizerBloc* bloc)
	{
		Reference->setValueNode(name, bloc);
	}

	/// Get Value Node
	virtual ITemplatizerBloc*	getValueNode(const std::string& name)
	{
		return Reference->getValueNode(name);
	}

	/// Get Value Node
	virtual bool	getValueNodeAndEnv(const std::string& name, ITemplatizerBloc*& node, CTemplatizerEnv*& env)
	{
		return Reference->getValueNodeAndEnv(name, node, env);
	}

	virtual ITemplatizerBloc*	getNode(const std::string& name)
	{
		return Reference->getNode(name);
	}
};


/**
 * <Class description>
 * \author Benjamin Legros
 * \author Nevrax France
 * \date 2003
 */
class CTemplatizer
{
public:

	/// Constructor
	CTemplatizer();

	/// Destructor
	~CTemplatizer();



	/**
	 * Build templatizer from text
	 */
	bool		build(const char* text);


	/**
	 * Evaluate template and render to string
	 */
	std::string	eval();


	/**
	 * Set Value in env
	 */
	template<typename T>
	void		set(const std::string& var, const T& value)
	{
		if (RootEnv == NULL)
			return;

		std::string::size_type pos = var.find_last_of(EnvSeparator);

		if (pos == std::string::npos)
		{
			RootEnv->set(var, value);
		}
		else
		{
			RootEnv->getEnv(var.substr(0, pos))->set(var.substr(pos+1), value);
		}
	}

public:

	ITemplatizerBloc*		RootBloc;

	CTemplatizerEnv*		RootEnv;

};



class CTemplatizerParser
{
public:

	CTemplatizerParser() : _Buffer(NULL), _Line(0), _Valid(false)	{ }
	CTemplatizerParser(const CTemplatizerParser& ptr) : _Buffer(ptr._Buffer), _Line(ptr._Line), _Valid(ptr._Valid)	{ }
	CTemplatizerParser(const char*	buffer, uint linestart = 1) : _Buffer(buffer), _Line(linestart), _Valid(_Buffer != NULL)	{ }

	char	operator * () const			{ return *_Buffer; }
	char	operator [] (int i) const	{ return _Buffer[i]; }

	CTemplatizerParser&	operator = (const CTemplatizerParser& ptr)
	{
		_Buffer = ptr._Buffer;
		_Line = ptr._Line;
		_Valid = ptr._Valid;
		return *this;
	}

	CTemplatizerParser&	operator ++ ()
	{
		if (*_Buffer == '\0')
			return *this;

		if (*_Buffer == '\n')
			++_Line;

		++_Buffer;
		return *this;
	}

	CTemplatizerParser	operator ++ (int)
	{
		CTemplatizerParser	ret(*this);
		++(*this);
		return ret;
	}

	void	invalidate()	{ _Valid = false; }
	bool	isValid() const	{ return _Valid; }

	uint	getLine() const	{ return _Line; }

private:

	const char*	_Buffer;

	uint	_Line;

	bool	_Valid;

};




/**
 * A Templatizer node
 */
class ITemplatizerBloc
{
public:

	/// Constructor
	ITemplatizerBloc();

	/// Destructor
	virtual ~ITemplatizerBloc();



	/// Evaluate node
	virtual std::string	eval(CTemplatizerEnv* env)
	{
		std::string	res;
		uint	i;
		for (i=0; i<Blocs.size(); ++i)
			res += Blocs[i]->eval(env);
		return res;
	}

	/// Get Text (assuming this is a raw text bloc)
	virtual std::string	getText(CTemplatizerEnv* env)
	{
		return "";
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		return NULL;
	}

	/// Get Actual Bloc (not a reference)
	virtual ITemplatizerBloc*	getActualBloc()
	{
		return this;
	}

public:

	std::string	evalParam(const std::string& param, CTemplatizerEnv* env)
	{
		TParamMap::iterator	it = Params.find(param);
		if (it == Params.end())
			return "";
		return (*it).second->eval(env);
	}

public:

	/// Bloc types
	enum TType
	{
		Text,
	};

	/// Bloc type
	TType				Type;

	typedef std::vector<ITemplatizerBloc*>				TBlocList;
	typedef std::map<std::string, ITemplatizerBloc*>	TParamMap;

	/// Params
	TParamMap			Params;

	/// Sub blocs
	TBlocList			Blocs;


	/// Parse bloc
	static ITemplatizerBloc*	parseBloc(CTemplatizerParser& ptr);

	/// Parse bloc header
	virtual CTemplatizerParser	parseHeader(CTemplatizerParser ptr);

	/// Parse bloc internal data
	virtual CTemplatizerParser	parseInternal(CTemplatizerParser ptr);

	/// Has A Internal Bloc of data
	virtual bool		hasInternal() const	{ return true; }
};





/// Root Templatizer
class CTemplatizerRootBloc : public ITemplatizerBloc
{
public:

};

/// Reference Node
class CTemplatizerReferenceBloc : public ITemplatizerBloc
{
public:

	ITemplatizerBloc*	Reference;

	/// Constructor
	CTemplatizerReferenceBloc(ITemplatizerBloc* ref = NULL) : Reference(ref)	{}

	/// Destructor
	virtual ~CTemplatizerReferenceBloc()
	{
		Reference = NULL;
	}

	/// Evaluate node
	virtual std::string	eval(CTemplatizerEnv* env)
	{
		std::string			name = evalParam("name", env);
		std::string			ref = evalParam("ref", env);
		ITemplatizerBloc*	refnode = env->getValueNode(ref);
		if (refnode != NULL)
			env->setValueNode(name, new CTemplatizerReferenceBloc(refnode));
		else
			nlwarning("Failed to create reference on '%s', not found", name.c_str());
		return "";
	}

	/// Get Text (assuming this is a raw text bloc)
	virtual std::string	getText(CTemplatizerEnv* env)
	{
		return Reference->getText(env);
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		static const char*	args[] = { "name", "ref" };
		return (const char**)args;
	}

	/// Get Actual Bloc (not a reference)
	virtual ITemplatizerBloc*	getActualBloc()
	{
		return Reference->getActualBloc();
	}

	/// Has A Internal Bloc of data
	virtual bool		hasInternal() const	{ return false; }
};


/// RefEnv Bloc
class CTemplatizerRefEnvBloc : public ITemplatizerBloc
{
public:

	/// Evaluate node
	virtual std::string	eval(CTemplatizerEnv* env)
	{
		std::string			name = evalParam("name", env);
		std::string			ref = evalParam("ref", env);

		CTemplatizerEnv*	refenv = env->getEnv(ref);
		if (refenv != NULL)
			env->setSubEnv(name, new CTemplatizerRefEnv(refenv));
		else
			nlwarning("Failed to create reference on env '%s', not found", name.c_str());
		return "";
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		static const char*	args[] = { "name", "ref" };
		return (const char**)args;
	}

	/// Has A Internal Bloc of data
	virtual bool		hasInternal() const	{ return false; }
};





/**
 * Comment Bloc
 */
class CTemplatizerCommentBloc : public ITemplatizerBloc
{
public:

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		return "";
	}

	/// Parse bloc internal data
	virtual CTemplatizerParser	parseInternal(CTemplatizerParser ptr);

};


/**
 * Raw Text Bloc
 */
class CTemplatizerRawTextBloc : public ITemplatizerBloc
{
public:

	std::string		Text;

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		return Text;
	}

	virtual std::string	getText(CTemplatizerEnv* env)
	{
		return Text;
	}
};

// Set As Raw Text
inline void	CTemplatizerEnv::setAsRawText(const std::string& name, const std::string& text)
{
	CTemplatizerRawTextBloc*	bloc = new CTemplatizerRawTextBloc();
	bloc->Text = text;
	setValueNode(name, bloc);
}

// Get value
inline std::string	CTemplatizerEnv::get(const std::string& name)
{
	ITemplatizerBloc*	bloc = getValueNode(name);

	return (bloc == NULL) ? std::string("") : bloc->getText(this);
}

// eval num expr override
inline NLMISC::CEvalNumExpr::TReturnState	CTemplatizerEnv::evalValue (const char *value, double &result, uint32 userData)
{
	if (*value != '$')
	{
		return NLMISC::CEvalNumExpr::ValueError;
	}

	std::string	strvalue = get(value+1);

	if (sscanf(strvalue.c_str(), "%lf", &result) != 1)
	{
		result = (strvalue.empty() ? 0.0 : 1.0);
	}

	return NLMISC::CEvalNumExpr::NoError;
}



/**
 * Text Bloc
 */
class CTemplatizerTextBloc : public ITemplatizerBloc
{
public:

	std::string		Text;

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		return env->eval(Text);
	}

	virtual std::string	getText(CTemplatizerEnv* env)
	{
		return env->eval(Text);
	}

	/// Parse bloc internal data
	virtual CTemplatizerParser	parseInternal(CTemplatizerParser ptr);
};




/**
 * Sub bloc
 */
class CTemplatizerSubBloc : public ITemplatizerBloc
{
public:

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		std::string			subname = evalParam("name", env);
		CTemplatizerEnv*	subenv = env->getSubEnv(subname);

		return ITemplatizerBloc::eval(subenv);
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		static const char*	args[] = { "name" };
		return (const char**)args;
	}
};


/**
 * Loop bloc
 */
class CTemplatizerLoopBloc : public ITemplatizerBloc
{
public:

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		std::string			subname = evalParam("name", env);
		CTemplatizerEnv*	subenv = env->getSubEnv(subname);

		std::string			res;

		CTemplatizerEnv::TEnvMap::iterator	it;
		for (it=subenv->Envs.begin(); it!=subenv->Envs.end(); ++it)
			res += ITemplatizerBloc::eval((*it).second);

		return res;
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		static const char*	args[] = { "name" };
		return (const char**)args;
	}
};


/**
 * IfDefEnv bloc
 */
class CTemplatizerIfDefEnvBloc : public ITemplatizerBloc
{
public:

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		std::string			subname = evalParam("name", env);
		std::string			evalinsub = evalParam("evalinsub", env);

		if (env->envExists(subname))
		{
			sint eval;
			NLMISC::fromString(evalinsub, eval);
			CTemplatizerEnv*	subenv = (eval ? env->getEnv(subname) : env);
			return ITemplatizerBloc::eval(subenv);
		}

		return "";
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		static const char*	args[] = { "name", "evalinsub" };
		return (const char**)args;
	}
};


/**
 * IfDef bloc
 */
class CTemplatizerIfDefBloc : public ITemplatizerBloc
{
public:

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		std::string			varname = evalParam("name", env);

		if (env->exists(varname))
		{
			return ITemplatizerBloc::eval(env);
		}

		return "";
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		static const char*	args[] = { "name" };
		return (const char**)args;
	}
};


/**
 * IfDefEnv bloc
 */
class CTemplatizerIfNotDefEnvBloc : public ITemplatizerBloc
{
public:

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		std::string			subname = evalParam("name", env);

		if (!env->envExists(subname))
		{
			return ITemplatizerBloc::eval(env);
		}

		return "";
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		static const char*	args[] = { "name" };
		return (const char**)args;
	}
};


/**
 * IfDef bloc
 */
class CTemplatizerIfNotDefBloc : public ITemplatizerBloc
{
public:

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		std::string			varname = evalParam("name", env);

		if (!env->exists(varname))
		{
			return ITemplatizerBloc::eval(env);
		}

		return "";
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		static const char*	args[] = { "name" };
		return (const char**)args;
	}
};


/**
 * Switch bloc
 */
class CTemplatizerSwitchBloc : public ITemplatizerBloc
{
public:

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		std::string			switchvalue = evalParam("value", env);

		uint	i;
		for (i=0; i<Blocs.size(); ++i)
			if (Blocs[i]->evalParam("case", env) == switchvalue)
				return Blocs[i]->eval(env);

		return "";
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		static const char*	args[] = { "value" };
		return (const char**)args;
	}
};

/**
 * File bloc
 */
class CTemplatizerFileBloc : public ITemplatizerBloc
{
public:

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		std::string	clearfile = evalParam("clear", env);
		std::string	filename = evalParam("name", env);

		std::string	result = ITemplatizerBloc::eval(env);

		FILE*	f;
		f = fopen(filename.c_str(), (clearfile == "true" ? "w" : "a"));
		if (f != NULL)
		{
			fwrite(result.c_str(), 1, result.size(), f);
			fclose(f);
		}

		return result;
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		static const char*	args[] = { "name" };
		return (const char**)args;
	}
};

/**
 * Set bloc
 */
class CTemplatizerSetBloc : public ITemplatizerBloc
{
public:

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		std::string	var = evalParam("name", env);
		std::string	result = ITemplatizerBloc::eval(env);

		env->set(var, result);

		return "";
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		static const char*	args[] = { "name" };
		return (const char**)args;
	}
};

/**
 * Append bloc
 */
class CTemplatizerAppendBloc : public ITemplatizerBloc
{
public:

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		std::string	var = evalParam("name", env);
		std::string	result = ITemplatizerBloc::eval(env);

		ITemplatizerBloc*	bloc = env->getValueNode(var);
		if (bloc == NULL)
			return "";

		CTemplatizerRawTextBloc*	text = dynamic_cast<CTemplatizerRawTextBloc*>(bloc->getActualBloc());
		if (text == NULL)
			return "";

		text->Text += result;

		return "";
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		static const char*	args[] = { "name" };
		return (const char**)args;
	}
};

/**
 * Define Bloc
 */
class CTemplatizerDefineBloc : public ITemplatizerBloc
{
public:

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		std::string	name = evalParam("name", env);
		env->setValueNode(name, new CTemplatizerReferenceBloc(this));
		return "";
	}

	virtual std::string	getText(CTemplatizerEnv* env)
	{
		return ITemplatizerBloc::eval(env);
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		static const char*	args[] = { "name" };
		return (const char**)args;
	}
};

/**
 * If Bloc
 */
class CTemplatizerIfBloc : public ITemplatizerBloc
{
public:

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		std::string	value = evalParam("cond", env);
		double		result;
		NLMISC::CEvalNumExpr::TReturnState	res = env->evalExpression(value.c_str(), result, NULL);

		if (res == NLMISC::CEvalNumExpr::NoError && result != 0.0)
		{
			return ITemplatizerBloc::eval(env);
		}
		else
		{
			return "";
		}
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		static const char*	args[] = { "cond" };
		return (const char**)args;
	}
};

/**
 * If Not Bloc
 */
class CTemplatizerIfNotBloc : public ITemplatizerBloc
{
public:

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		std::string	value = evalParam("cond", env);

		if (value.empty())
		{
			return ITemplatizerBloc::eval(env);
		}
		else
		{
			return "";
		}
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		static const char*	args[] = { "cond" };
		return (const char**)args;
	}
};

/**
 * Join bloc
 */
class CTemplatizerJoinBloc : public ITemplatizerBloc
{
public:

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		std::string	sep = evalParam("separator", env);

		std::string	res;
		uint	i;
		for (i=0; i<Blocs.size(); ++i)
		{
			std::string	token = Blocs[i]->eval(env);

			if (token.empty())
				continue;

			if (!res.empty())
				res += sep;

			res += token;
		}
		return res;
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		static const char*	args[] = { "separator" };
		return (const char**)args;
	}
};

/**
 * User Defined function call
 */
class CTemplatizerUserFunctionBloc : public ITemplatizerBloc
{
public:

	CTemplatizerUserFunctionBloc(const std::string& name) : Name(name)	{}

	std::string		Name;

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		ITemplatizerBloc*	func = NULL;
		CTemplatizerEnv*	fenv = NULL;
		if (!env->getValueNodeAndEnv(Name, func, fenv))
		{
			nlwarning("Unknown user function '%s'", Name.c_str());
			return "";
		}

		// subenv is child of object env, not of current env
		CTemplatizerEnv*	subenv = new CTemplatizerEnv(fenv);

		// deport params in subenv
		// \todo : eval param in current env
		TParamMap::iterator	it;
		for (it=Params.begin(); it!=Params.end(); ++it)
			subenv->setAsRawText((*it).first, (*it).second->getText(env));
			//subenv->setValueNode((*it).first, new CTemplatizerReferenceBloc((*it).second));

		std::string	res = func->getText(subenv);

		delete subenv;

		return res;
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		return NULL;
	}

	/// Has A Internal Bloc of data
	virtual bool		hasInternal() const
	{
		return false;
	}
};

/**
 * Class
 */
class CTemplatizerClassBloc : public ITemplatizerBloc
{
public:

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		std::string	name = evalParam("name", env);
		env->setValueNode(name, new CTemplatizerReferenceBloc(this));
		return "";
	}

	virtual std::string	instantiate(CTemplatizerEnv* env)
	{
		return ITemplatizerBloc::eval(env);
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		static const char*	args[] = { "name" };
		return (const char**)args;
	}
};

/**
 * Class
 */
class CTemplatizerObjectBloc : public ITemplatizerBloc
{
public:

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		std::string	classname = evalParam("class", env);
		std::string	name = evalParam("name", env);

		ITemplatizerBloc*	bloc = env->getValueNode(classname);
		if (bloc == NULL)
		{
			nlwarning("Unknown class '%s'", classname.c_str());
			return "";
		}

		CTemplatizerClassBloc*	classbloc = dynamic_cast<CTemplatizerClassBloc*>(bloc->getActualBloc());
		if (classbloc == NULL)
		{
			nlwarning("object '%s' is not a class", classname.c_str());
			return "";
		}

		CTemplatizerEnv* objectenv = env->getSubEnv(name);
		objectenv->clear();

		return classbloc->instantiate(objectenv);
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		static const char*	args[] = { "class", "name" };
		return (const char**)args;
	}

	/// Has A Internal Bloc of data
	virtual bool		hasInternal() const	{ return false;	}
};


/**
 * Breakpoint
 */
class CTemplatizerBreakpointBloc : public ITemplatizerBloc
{
public:

	virtual std::string	eval(CTemplatizerEnv* env)
	{
		std::string	value = evalParam("name", env);
		return "";
	}

	/// Get Param list
	virtual const char**	getDefParamList()
	{
		static const char*	args[] = { "name" };
		return (const char**)args;
	}
};


#endif // NL_TEMPLATIZER_H

/* End of templatizer.h */