#ifndef _PROPERTYGRAMMAR_H_
#define _PROPERTYGRAMMAR_H_

#include "IPropertyActions.h"
#include "Parsers/GrammarErrorHandler.hpp"

// #include <boost/config/warning_disable.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>

#include <iostream>

namespace spirit = boost::spirit;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;

namespace GST
{
namespace Parsers
{

//
// the grammar
//
template<typename Iterator /*, typename Skipper*/>
class PropertyGrammar : public qi::grammar<Iterator /*, Skipper*/>
{
public:
	PropertyGrammar(boost::shared_ptr<IPropertyActions> actions)
		: PropertyGrammar::base_type(
			  propertyString_) // define here the base rule
		, _actions(actions)
	{
		using ascii::string;
		using qi::char_;
		using qi::lexeme;
		using qi::lit;
		using qi::space;

		// define here function pointers to Semantic actions (more beautiful
		// grammar definiton)
		typedef boost::function<void(
			qi::unused_type, qi::unused_type, qi::unused_type)>
			void_action;
		typedef boost::function<void(
			const std::string &, qi::unused_type, qi::unused_type)>
			value_action;
		typedef boost::function<void(
			const std::vector<std::string> &, qi::unused_type, qi::unused_type)>
			vector_action;

		void_action nextObject(
			boost::bind(&IPropertyActions::PropNextObject, _actions));
		value_action addValue(
			boost::bind(&IPropertyActions::PropAddValue, _actions, ::_1));
		vector_action addVector(
			boost::bind(&IPropertyActions::PropAddVector, _actions, ::_1));

		//
		// ###  the grammar definiton   ###
		value_ %= lexeme[*(char_ - (lit(';') ^ lit('}') ^ lit(')')))];

		array_ = lit('{') > value_ % ';' > lit('}');

		entry_ = array_[addVector] | value_[addValue];

		oneObject_ = lit('(') > -(entry_ > *(lit(';') > entry_)) > lit(')');

		propertyString_
			= oneObject_[nextObject] > *(lit(';') > oneObject_[nextObject]);
		// ### end of grammar definiton ###
		//

		//
		// ### error handling
		entry_.name("entry_");
		array_.name("array_");
		value_.name("value_");
		oneObject_.name("oneObject_");
		propertyString_.name("propertyString_");

		namespace qil = qi::labels;

		qi::on_error<qi::fail>(propertyString_,
							   error_handler_func(error_handler())(
								   qil::_1, qil::_2, qil::_3, qil::_4));
		// ### end of error handling
		//

	} // end of c'tor

	qi::rule<Iterator /*, Skipper*/> propertyString_;
	qi::rule<Iterator /*, Skipper*/> oneObject_;
	qi::rule<Iterator /*, Skipper*/> entry_;
	qi::rule<Iterator, std::string() /*, Skipper*/> value_;
	qi::rule<Iterator, std::vector<std::string>() /*, Skipper*/> array_;

private:
	boost::shared_ptr<IPropertyActions> _actions;
};

} // namespace Parsers
} // namespace GST

#endif //_PROPERTYGRAMMAR_H_
