#pragma once

// [config-parser.h]: configuration file parser
//
// -------------------------------------------------------------------------------------------- //

#include "mpi-com.h"
#include "str-com.h"
#include "cfg-var.h"

namespace nse
{
	class ConfigParser {
	public:
		ConfigParser();
		~ConfigParser();

		bool run(const char* filename);
		bool mpi_run(const char* filename, const MPI_Comm comm);
		bool mpi_run(const char* filename);


		bool is_varname(const char* name) const;
		const cfgVariable get_variable(const int idx) const;
		const cfgVariable get_variable(const char* name) const;

		bool get_value(const char* name, int* value) const;
		bool get_value(const char* name, float* value) const;
		bool get_value(const char* name, double* value) const;

		bool get_value(const char* name, char** value) const;
		bool get_value(const char* name, std::string& value) const;

		bool get_value(const char* name, bool* value) const;


		bool mpi_is_varname(const char* name, const MPI_Comm comm) const;

		template< typename T >
		bool mpi_get_value(const char* name, T* value, const MPI_Comm comm) const;

		bool mpi_get_value(const char* name, char** value, const MPI_Comm comm) const;
		bool mpi_get_value(const char* name, std::string& value, const MPI_Comm comm) const;


		void print() const;

	private:	// datatypes //

		enum LEXEME_TYPE {	// lexeme types //
			IS_INVALID,
			IS_NAME,
			IS_ASSIGNMENT,
			IS_BRACE_OPEN, IS_BRACE_CLOSE,			// {}
			IS_BRACKET_OPEN, IS_BRACKET_CLOSE,		// ()
			IS_SEMICOLON,
			IS_VALUE,
			IS_OP_ADD, IS_OP_SUB,				// +,-		[priority=1, assoc.=left]
			IS_OP_MUL, IS_OP_DIV, IS_OP_MOD,	// *,/,%	[priority=2, assoc.=left]
			IS_OP_PLUS, IS_OP_MINUS,			// +,-		[priority=3, assoc.=left]
			IS_OP_EXP							// ^		[priority=4, assoc.=right]
		};

		enum OP_ASSOCIATIVITY { IS_OP_LEFT, IS_OP_RIGHT };	// operation specifiers //

		struct parserState {	// helper struct to control parsing state //

			parserState();
			parserState(const parserState& state);
			~parserState();

			void truncate_name_space();
			void append_name_space(const char* name);

			int idx, level;		// lexeme index and namespace level 
			char *name_space;	// current namespace

		private:	// allocation data
			int nalloc;
			static const int c_alloc_init = 64;
		};

		struct rpnList {		// helper struct for RPN expressions evaluation //

			rpnList();
			~rpnList();

			bool convert(
				parserState& state,		// advancing state after delimiter [';']
				const LEXEME_TYPE *lexeme_type, const FileParser& parser);

		private:	// interface //
			void init();
			void add(const int idx);
			bool empty();

		public:
			int *expr;		// lexeme index corresponding to element
			int nexpr;		// number of elements in expression

		private:	// allocation data
			int nalloc;
			static const int c_alloc_init = 64;
		};

	private:	// static //

		static bool is_valid_name(const char* lexeme);	// valid variable name check //

														// op - priority interface //
		static bool is_op(const LEXEME_TYPE op);
		static bool is_op_binary(const LEXEME_TYPE op);
		static bool is_op_unary(const LEXEME_TYPE op);

		static int op_priority(const LEXEME_TYPE op);
		static OP_ASSOCIATIVITY op_associativity(const LEXEME_TYPE op);

		static bool op_lt(const LEXEME_TYPE opA, const LEXEME_TYPE opB);

	private:	// processing //

		bool add(const cfgVariable& rvalue);	// adding variable to list //

		const cfgVariable evaluate_rpn(
			const rpnList& rpn,
			parserState state,	// using copy due to namespace operations
			const LEXEME_TYPE *lexeme_type, const FileParser& parser) const;

		bool run_lexical_analysis(LEXEME_TYPE *lexeme_type,
			const FileParser& parser);
		bool run_syntax_analysis(const LEXEME_TYPE *lexeme_type,
			const FileParser& parser);

	private:	// data //	

		int nalloc_vars;
		static const int c_alloc_init = 64;

		int nvars;
		cfgVariable *var;
	};
}