#define _CRT_SECURE_NO_DEPRECATE
#include "config-parser.h"
#include "str-com.h"

#include <stdio.h>
#include <string.h>
#include <ctype.h>

#include <stack>

//
// Implementation: helper classes
//
// ConfigParser::parserState
nse::ConfigParser::parserState::parserState()
{
	idx = 0;
	level = 0;

	nalloc = c_alloc_init;
	name_space = new char[c_alloc_init];
	*name_space = '\0';
}
nse::ConfigParser::parserState::parserState(
	const parserState& state)
{
	idx = state.idx;
	level = state.level;
	nalloc = state.nalloc;

	name_space = new char[nalloc];
	strcpy(name_space, state.name_space);
}
nse::ConfigParser::parserState::~parserState()
{
	delete[] name_space;
}

void nse::ConfigParser::parserState::truncate_name_space()
{
	truncate_name(name_space, '.');
}
void nse::ConfigParser::parserState::append_name_space(
	const char* name)
{
	append_name(&name_space, &nalloc, name, '.');
}

//
// ConfigParser::rpnList
nse::ConfigParser::rpnList::rpnList()
{
	nexpr = 0;

	nalloc = c_alloc_init;
	expr = new int[nalloc];
}
nse::ConfigParser::rpnList::~rpnList()
{
	delete[] expr;
}

void nse::ConfigParser::rpnList::init()
{
	nexpr = 0;
}

void nse::ConfigParser::rpnList::add(const int idx)
{
	if (nexpr >= nalloc) {
		int *buf = new int[nalloc + c_alloc_init];
		memcpy(buf, expr, nalloc * sizeof(int));

		delete[] expr;
		expr = buf;
	}

	expr[nexpr] = idx;
	nexpr++;
}

bool nse::ConfigParser::rpnList::empty()
{
	return nexpr == 0;
}

bool nse::ConfigParser::rpnList::convert(
	parserState& state,
	const LEXEME_TYPE *lexeme_type, const FileParser& parser)
{
	const int nlexeme = parser.get_ntokens();
	std::stack<int> hstack;

	init();

	LEXEME_TYPE p_lex = IS_INVALID, lex;
	bool status = true;
	while ((state.idx < nlexeme) && (p_lex != IS_SEMICOLON))
	{

		lex = lexeme_type[state.idx];

		if ((lex == IS_VALUE) || (lex == IS_NAME)) {
			// adding value | variable reference
			//	- postpone existence check to evaluation step
			add(state.idx);
		}
		else
			if (lex == IS_BRACKET_OPEN) {
				hstack.push(state.idx);	// pushing '(' to stack
			}
			else
				if (lex == IS_BRACKET_CLOSE) {
					// pop till '(' found & remove '(' from stack

					int idx;
					bool flag = false;
					while (!hstack.empty()) {
						idx = hstack.top();
						hstack.pop();
						if (lexeme_type[idx] == IS_BRACKET_OPEN) {
							flag = true;
							break;
						}
						else
						{
							add(idx);
						}
					}

					if (!flag) {
						printf(" CONFIG:> missing bracket '(' (line, %i)\n",
							parser.get_line_num(state.idx));
					}
					else
						if (p_lex == IS_BRACKET_OPEN) {
							printf(" CONFIG:> null sub-expression found '()' (line, %i)\n",
								parser.get_line_num(state.idx));
							flag = false;
						}

					status = status && flag;
				}
				else
					if (is_op(lex))	// handling operators
					{
						int idx;
						while (!hstack.empty()) {
							idx = hstack.top();
							if (!is_op(lexeme_type[idx])) break;

							if (
								((op_associativity(lex) == IS_OP_LEFT) &&
								(!op_lt(lexeme_type[idx], lex))) ||

								((op_associativity(lex) == IS_OP_RIGHT) &&
								(op_lt(lex, lexeme_type[idx])))
								)
							{
								hstack.pop();
								add(idx);
							}
							else
								break;
						}
						hstack.push(state.idx);
					}
					else
						if (lex == IS_SEMICOLON) {
							// removing elements until stack is empty or getting '('

							int idx;
							bool flag = true;
							while (!hstack.empty()) {
								idx = hstack.top();
								hstack.pop();
								if (lexeme_type[idx] == IS_BRACKET_OPEN) {
									flag = false;
									break;
								}
								else
								{
									add(idx);
								}
							}

							if (!flag) {
								printf(" CONFIG:> missing bracket ')' (line, %i)\n",
									parser.get_line_num(state.idx));
							}

							status = status && flag;
						}
						else
						{
							printf(" CONFIG:> unexpected lexeme in expression: '%s' (line, %i)\n",
								parser.get_token(state.idx), parser.get_line_num(state.idx));
							status = false;
						}

		p_lex = lex;
		state.idx++;
	}

	status = status && (!empty());
	return status;
}


//
// Implementation: ConfigureParser
//
nse::ConfigParser::ConfigParser()
{
	nvars = 0;
	nalloc_vars = c_alloc_init;

	var = new cfgVariable[nalloc_vars];
}

nse::ConfigParser::~ConfigParser()
{
	nvars = 0;
	nalloc_vars = 0;

	delete[] var;
}

bool nse::ConfigParser::is_op(const LEXEME_TYPE op)
{
	return (
		(op == IS_OP_ADD) || (op == IS_OP_SUB) ||
		(op == IS_OP_MUL) || (op == IS_OP_DIV) ||
		(op == IS_OP_MOD) ||
		(op == IS_OP_PLUS) || (op == IS_OP_MINUS) ||
		(op == IS_OP_EXP));
}

bool nse::ConfigParser::is_op_binary(const LEXEME_TYPE op)
{
	return (
		(op == IS_OP_ADD) || (op == IS_OP_SUB) ||
		(op == IS_OP_MUL) || (op == IS_OP_DIV) ||
		(op == IS_OP_MOD) ||
		(op == IS_OP_EXP));
}

bool nse::ConfigParser::is_op_unary(const LEXEME_TYPE op)
{
	return ((op == IS_OP_PLUS) || (op == IS_OP_MINUS));
}

int nse::ConfigParser::op_priority(
	const LEXEME_TYPE op)
{
	if ((op == IS_OP_ADD) || (op == IS_OP_SUB)) return 1;
	if ((op == IS_OP_MUL) || (op == IS_OP_DIV) ||
		(op == IS_OP_MOD)) return 2;
	if ((op == IS_OP_PLUS) || (op == IS_OP_MINUS)) return 3;
	if ((op == IS_OP_EXP)) return 4;

	return 0;
}

nse::ConfigParser::OP_ASSOCIATIVITY
nse::ConfigParser::op_associativity(
	const LEXEME_TYPE op)
{
	if (op == IS_OP_EXP) return IS_OP_RIGHT;
	else
		return IS_OP_LEFT;
}

bool nse::ConfigParser::op_lt(
	const LEXEME_TYPE opA, const LEXEME_TYPE opB)
{
	return (op_priority(opA) < op_priority(opB));
}

bool nse::ConfigParser::is_valid_name(const char* token)
{
	int token_length = strlen(token);

	if (token_length == 0) return false;
	if ((!isalpha(token[0])) && (token[0] != '_')) return false;

	for (int i = 1; i < token_length - 1; i++) {
		if ((!isalnum(token[i])) &&
			(token[i] != '_') && (token[i] != '.')) return false;
	}
	if ((!isalnum(token[token_length - 1])) &&
		(token[token_length - 1] != '_')) return false;

	return true;
}


bool nse::ConfigParser::add(const cfgVariable& ex)
{
	if (!ex.is_valid_name()) return false;

	// just overwriting variable if already exists
	for (int k = 0; k < nvars; k++) {
		if (var[k].is_eq_name(ex)) {
			var[k] = ex;
			return true;
		}
	}

	if (nvars >= nalloc_vars)
	{
		cfgVariable *hvar = new cfgVariable[nalloc_vars + c_alloc_init];
		for (int i = 0; i < nalloc_vars; i++) {
			hvar[i] = var[i];
		}

		delete[] var;
		var = hvar;

		nalloc_vars += c_alloc_init;
	}

	var[nvars] = ex;
	nvars++;
	return true;
}

bool nse::ConfigParser::run_lexical_analysis(
	LEXEME_TYPE *lexeme_type, const FileParser& parser)
{
	const int nlexeme = parser.get_ntokens();
	if (nlexeme == 0) return true;

	bool status = true;
	for (int i = 0; i < nlexeme; i++) {

		const char* lexeme = parser.get_token(i);

		if (!strcmp(lexeme, "=")) lexeme_type[i] = IS_ASSIGNMENT;
		else
			if (!strcmp(lexeme, "{")) lexeme_type[i] = IS_BRACE_OPEN;
			else
				if (!strcmp(lexeme, "}")) lexeme_type[i] = IS_BRACE_CLOSE;
				else
					if (!strcmp(lexeme, "(")) lexeme_type[i] = IS_BRACKET_OPEN;
					else
						if (!strcmp(lexeme, ")")) lexeme_type[i] = IS_BRACKET_CLOSE;
						else
							if (!strcmp(lexeme, ";")) lexeme_type[i] = IS_SEMICOLON;
							else
								if (!strcmp(lexeme, "+"))
								{
									// checking for unary "+"
									if (i == 0) lexeme_type[i] = IS_OP_PLUS;
									else
									{
										if ((lexeme_type[i - 1] == IS_NAME) ||
											(lexeme_type[i - 1] == IS_VALUE) ||
											(lexeme_type[i - 1] == IS_BRACKET_CLOSE))
										{
											lexeme_type[i] = IS_OP_ADD;
										}
										else
											lexeme_type[i] = IS_OP_PLUS;
									}
								}
								else
									if (!strcmp(lexeme, "-"))
									{
										// checking for unary "-"
										if (i == 0) lexeme_type[i] = IS_OP_MINUS;
										else
										{
											if ((lexeme_type[i - 1] == IS_NAME) ||
												(lexeme_type[i - 1] == IS_VALUE) ||
												(lexeme_type[i - 1] == IS_BRACKET_CLOSE))
											{
												lexeme_type[i] = IS_OP_SUB;
											}
											else
												lexeme_type[i] = IS_OP_MINUS;
										}
									}
									else
										if (!strcmp(lexeme, "*")) lexeme_type[i] = IS_OP_MUL;
										else
											if (!strcmp(lexeme, "/")) lexeme_type[i] = IS_OP_DIV;
											else
												if (!strcmp(lexeme, "%")) lexeme_type[i] = IS_OP_MOD;
												else
													if (!strcmp(lexeme, "^")) lexeme_type[i] = IS_OP_EXP;
													else
														if (is_integer(lexeme) || is_double(lexeme) ||
															is_valid_string(lexeme) || is_boolean(lexeme))
														{
															lexeme_type[i] = IS_VALUE;
														}
														else
															if (is_valid_name(lexeme)) lexeme_type[i] = IS_NAME;
															else
															{
																lexeme_type[i] = IS_INVALID;
																printf(" CONFIG:> invalid lexeme: '%s' (line, %i)\n",
																	lexeme, parser.get_line_num(i));
																status = false;
															}
	}

	return status;
}

const nse::cfgVariable
nse::ConfigParser::evaluate_rpn(
	const rpnList& rpn,
	parserState state,
	const LEXEME_TYPE *lexeme_type, const FileParser& parser) const
{
	LEXEME_TYPE lex;
	std::stack<cfgVariable> dyn_expr;
	int eidx;

	for (int i = 0; i < rpn.nexpr; i++)
	{
		eidx = rpn.expr[i];
		lex = lexeme_type[eidx];

		if (is_op_binary(lex)) {
			if (dyn_expr.size() >= 2) {
				cfgVariable a = dyn_expr.top(); dyn_expr.pop();
				cfgVariable b = dyn_expr.top(); dyn_expr.pop();

				if (lex == IS_OP_ADD) b += a;
				else
					if (lex == IS_OP_SUB) b -= a;
					else
						if (lex == IS_OP_MUL) b *= a;
						else
							if (lex == IS_OP_DIV) b /= a;
							else
								if (lex == IS_OP_MOD) b %= a;
								else
									if (lex == IS_OP_EXP) b ^= a;
									else
									{
										printf(" CONFIG:> unknown binary operation: '%s' (line, %i)\n",
											parser.get_token(eidx), parser.get_line_num(eidx));
										return cfgVariable();
									}

				if (!b.is_valid_type()) {
					printf(" CONFIG:> incorrect types of operands: '%s' (line, %i)\n",
						parser.get_token(eidx), parser.get_line_num(eidx));
					return b;
				}
				dyn_expr.push(b);
			}
			else
			{
				printf(" CONFIG:> insufficient number of arguments: '%s' (line, %i)\n",
					parser.get_token(eidx),
					parser.get_line_num(eidx));
				return cfgVariable();
			}
		}
		else
			if (is_op_unary(lex)) {
				if (dyn_expr.size() >= 1) {
					cfgVariable op = dyn_expr.top(); dyn_expr.pop();
					cfgVariable res;

					if (lex == IS_OP_PLUS) res = +op;
					else
						if (lex == IS_OP_MINUS) res = -op;
						else
						{
							printf(" CONFIG:> unknown unary operation: '%s' (line, %i)\n",
								parser.get_token(eidx), parser.get_line_num(eidx));
							return cfgVariable();
						}

					if (!res.is_valid_type()) {
						printf(" CONFIG:> incorrect type of operand: '%s' (line, %i)\n",
							parser.get_token(eidx), parser.get_line_num(eidx));
						return res;
					}
					dyn_expr.push(res);
				}
				else
				{
					printf(" CONFIG:> insufficient number of arguments: '%s' (line, %i)\n",
						parser.get_token(eidx), parser.get_line_num(eidx));
					return cfgVariable();
				}
			}
			else
				if (lex == IS_NAME) {

					cfgVariable arg;
					int pend = strlen(state.name_space);

					state.append_name_space(parser.get_token(eidx));
					if (is_varname(state.name_space))
						arg = get_variable(state.name_space);
					else
					{
						if (is_varname(parser.get_token(eidx))) {
							arg = get_variable(parser.get_token(eidx));
						}
						else
						{
							printf(" CONFIG:> reference to undefined variable: '%s' (line, %i)\n",
								parser.get_token(eidx), parser.get_line_num(eidx));
							return cfgVariable();
						}
					}
					state.name_space[pend] = '\0';	// removing added name resolution

					dyn_expr.push(arg);
				}
				else
				{
					dyn_expr.push(
						cfgVariable(parser.get_token(eidx)));
				}
	}

	if (dyn_expr.size() != 1) return cfgVariable();

	return cfgVariable(dyn_expr.top());	// delay res type checking [in add]
}

bool nse::ConfigParser::run_syntax_analysis(
	const LEXEME_TYPE *lexeme_type, const FileParser& parser)
{
	const int nlexeme = parser.get_ntokens();
	if (nlexeme == 0) return true;

	parserState state;
	rpnList rpn;

	bool status = true;
	while (state.idx < nlexeme) {

		// - closing namespace [}]
		if ((lexeme_type[state.idx] == IS_BRACE_CLOSE) && (state.level > 0)) {
			state.truncate_name_space();
			state.level--; state.idx++;
			continue;
		}

		if (lexeme_type[state.idx] == IS_NAME) {
			if (state.idx + 1 < nlexeme) {
				// - open namespace [name {]
				if (lexeme_type[state.idx + 1] == IS_BRACE_OPEN) {

					// no dots allowed in namespace name at least for now
					if (strchr(parser.get_token(state.idx), '.') == NULL) {
						state.append_name_space(parser.get_token(state.idx));
					}
					else
					{
						status = false;
						printf(" CONFIG:> '.' not allowed in namespaces: '%s' (line, %i)\n",
							parser.get_token(state.idx), parser.get_line_num(state.idx));
					}

					state.level++; state.idx += 2;
					continue;
				}

				// - assignment [name = value|string ;]
				if (lexeme_type[state.idx + 1] == IS_ASSIGNMENT) {

					int varidx = state.idx;
					state.idx += 2;		// setting state at expression //

					int pend = strlen(state.name_space);

					// converting to postfix notation
					if (!rpn.convert(state, lexeme_type, parser)) {

						state.append_name_space(parser.get_token(varidx));

						status = false;
						printf(" CONFIG:> failed to process expression for variable: '%s' (line, %i)\n",
							state.name_space, parser.get_line_num(varidx));

						state.name_space[pend] = '\0';	// removing added name resolution
						continue;
					}

					// evaluating postix expression (need namespace - not full variable name)
					cfgVariable value = evaluate_rpn(rpn,
						state, lexeme_type, parser);
					if (!value.is_valid_type()) {

						state.append_name_space(parser.get_token(varidx));

						status = false;
						printf(" CONFIG:> failed to evaluate expression for variable: '%s' (line, %i)\n",
							state.name_space, parser.get_line_num(varidx));

						state.name_space[pend] = '\0';	// removing added name resolution
						continue;
					}

					state.append_name_space(parser.get_token(varidx));
					value.change_name(state.name_space);

					if (!add(value)) {
						status = false;
						printf(" CONFIG:> failed to add variable: '%s' (line, %i)\n",
							state.name_space, parser.get_line_num(varidx));
					}

					state.name_space[pend] = '\0';	// removing added name resolution
					continue;
				}
			}

			status = false;
			printf(" CONFIG:> expecting '=' or '{' for name: '%s' (line, %i)\n",
				parser.get_token(state.idx), parser.get_line_num(state.idx));
			state.idx += 2;
			continue;
		}

		status = false;
		printf(" CONFIG:> unexpected lexeme: '%s' (line, %i)\n",
			parser.get_token(state.idx), parser.get_line_num(state.idx));
		state.idx++;
	}

	if (state.level > 0) {
		status = false;
		printf(" CONFIG:> unclosed namespaces, missing '}'\n");
	}

	return status;
}

bool nse::ConfigParser::run(const char* filename)
{
	// removing elements in config -- but keeping memory
	nvars = 0;

	FileParser parser;
	if (!parser.run(filename, '#', "={};()+-*/%^", true)) {
		printf(" CONFIG:> parsing failed for file: '%s'\n", filename);
		return false;
	}

	const int nlexeme = parser.get_ntokens();
	if (nlexeme == 0) return true;

	LEXEME_TYPE *lexeme_type = new LEXEME_TYPE[nlexeme];

	bool status_lexical = run_lexical_analysis(lexeme_type, parser);
	bool status_syntax = run_syntax_analysis(lexeme_type, parser);

	delete[] lexeme_type;
	return status_lexical & status_syntax;
}

bool nse::ConfigParser::mpi_run(const char* filename, const MPI_Comm comm)
{
	const int host_rank = 0;

	int rank, status = 0;
	MPI_Comm_rank(comm, &rank);

	if (rank == host_rank) {
		if (run(filename)) status = 1;
	}
	mpi_broadcast(&status, 1, host_rank);
	return (status == 1);
}

bool nse::ConfigParser::mpi_run(const char* filename)
{
	return mpi_run(filename, MPI_COMM_WORLD);
}


bool nse::ConfigParser::is_varname(const char* name) const
{
	for (int i = 0; i < nvars; i++) {
		if (var[i].is_varname(name)) return true;
	}
	return false;
}

const nse::cfgVariable
nse::ConfigParser::get_variable(const int idx) const
{
	if ((idx < 0) || (idx >= nvars)) return cfgVariable();
	return var[idx];
}
const nse::cfgVariable
nse::ConfigParser::get_variable(const char* name) const
{
	for (int k = 0; k < nvars; k++) {
		if (var[k].is_varname(name)) return var[k];
	}
	return cfgVariable();
}

void nse::ConfigParser::print() const
{
	for (int i = 0; i < nvars; i++) {
		var[i].print();
		getc(stdin);
	}
}

bool nse::ConfigParser::get_value(const char* name, int* value) const
{
	cfgVariable var = get_variable(name);
	cfgVariable::VAR_TYPE type = var.get_type();

	if (type == cfgVariable::IS_INT) return (var.get_value(value) > 0);
	else
		if (type == cfgVariable::IS_DOUBLE)
		{
			printf(" CONFIG:> failed to set (int) variable: '%s' - declared as double\n",
				name);
			return false;
		}
		else
			if (type == cfgVariable::IS_STRING) {
				printf(" CONFIG:> failed to set (int) variable: '%s' - declared as string\n",
					name);
				return false;
			}
			else
				if (type == cfgVariable::IS_BOOLEAN) {
					printf(" CONFIG:> failed to set (int) variable: '%s' - declared as boolean\n",
						name);
					return false;
				}

	printf(" CONFIG:> failed to set (int) variable: '%s'\n", name);
	return false;
}

bool nse::ConfigParser::get_value(const char* name, float* value) const
{
	cfgVariable var = get_variable(name);
	cfgVariable::VAR_TYPE type = var.get_type();

	if (type == cfgVariable::IS_INT)
	{
		int ival;
		int status = var.get_value(&ival);
		(*value) = (float)ival;
		return (status > 0);
	}
	else
		if (type == cfgVariable::IS_DOUBLE)
		{
			double dval;
			int status = var.get_value(&dval);
			(*value) = (float)dval;
			return (status > 0);
		}
		else
			if (type == cfgVariable::IS_STRING) {
				printf(" CONFIG:> failed to set (float) variable: '%s' - declared as string\n",
					name);
				return false;
			}
			else
				if (type == cfgVariable::IS_BOOLEAN) {
					printf(" CONFIG:> failed to set (float) variable: '%s' - declared as boolean\n",
						name);
					return false;
				}

	printf(" CONFIG:> failed to set (float) variable: '%s' - undefined\n",
		name);
	return false;
}

bool nse::ConfigParser::get_value(const char* name, double* value) const
{
	cfgVariable var = get_variable(name);
	cfgVariable::VAR_TYPE type = var.get_type();

	if (type == cfgVariable::IS_INT)
	{
		int ival;
		int status = var.get_value(&ival);
		(*value) = (double)ival;
		return (status > 0);
	}
	else
		if (type == cfgVariable::IS_DOUBLE) return (var.get_value(value) > 0);
		else
			if (type == cfgVariable::IS_STRING) {
				printf(" CONFIG:> failed to set (double) variable: '%s' - declared as string\n",
					name);
				return false;
			}
			else
				if (type == cfgVariable::IS_BOOLEAN) {
					printf(" CONFIG:> failed to set (double) variable: '%s' - declared as boolean\n",
						name);
					return false;
				}

	printf(" CONFIG:> failed to set (double) variable: '%s' - undefined\n",
		name);
	return false;
}

bool nse::ConfigParser::get_value(const char* name, char** value) const
{
	cfgVariable var = get_variable(name);
	cfgVariable::VAR_TYPE type = var.get_type();

	if (type == cfgVariable::IS_INT) {
		printf(" CONFIG:> failed to set (string) variable: '%s' - declared as int\n",
			name);
		return false;
	}
	else
		if (type == cfgVariable::IS_DOUBLE)
		{
			printf(" CONFIG:> failed to set (string) variable: '%s' - declared as double\n",
				name);
			return false;
		}
		else
			if (type == cfgVariable::IS_STRING) return (var.get_value(value) > 0);
			else
				if (type == cfgVariable::IS_BOOLEAN)
				{
					printf(" CONFIG:> failed to set (string) variable: '%s' - declared as boolean\n",
						name);
					return false;
				}

	printf(" CONFIG:> failed to set (string) variable: '%s' - undefined\n",
		name);
	return false;
}

bool nse::ConfigParser::get_value(const char* name, std::string& value) const
{
	cfgVariable var = get_variable(name);
	cfgVariable::VAR_TYPE type = var.get_type();

	if (type == cfgVariable::IS_INT) {
		printf(" CONFIG:> failed to set (string) variable: '%s' - declared as int\n",
			name);
		return false;
	}
	else
		if (type == cfgVariable::IS_DOUBLE)
		{
			printf(" CONFIG:> failed to set (string) variable: '%s' - declared as double\n",
				name);
			return false;
		}
		else
			if (type == cfgVariable::IS_STRING) return (var.get_value(value) > 0);
			else
				if (type == cfgVariable::IS_BOOLEAN)
				{
					printf(" CONFIG:> failed to set (string) variable: '%s' - declared as boolean\n",
						name);
					return false;
				}

	printf(" CONFIG:> failed to set (string) variable: '%s' - undefined\n",
		name);
	return false;
}

bool nse::ConfigParser::get_value(const char* name, bool* value) const
{
	cfgVariable var = get_variable(name);
	cfgVariable::VAR_TYPE type = var.get_type();

	if (type == cfgVariable::IS_INT)
	{
		printf(" CONFIG:> failed to set (bool) variable: '%s' - declared as int\n",
			name);
		return false;
	}
	else
		if (type == cfgVariable::IS_DOUBLE)
		{
			printf(" CONFIG:> failed to set (bool) variable: '%s' - declared as double\n",
				name);
			return false;
		}
		else
			if (type == cfgVariable::IS_STRING) {
				printf(" CONFIG:> failed to set (bool) variable: '%s' - declared as string\n",
					name);
				return false;
			}
			else
				if (type == cfgVariable::IS_BOOLEAN) return (var.get_value(value) > 0);

	printf(" CONFIG:> failed to set (bool) variable: '%s'\n", name);
	return false;
}

bool nse::ConfigParser::mpi_is_varname(const char* name, const MPI_Comm comm) const
{
	const int host_rank = 0;

	int rank;
	bool status;
	MPI_Comm_rank(comm, &rank);

	if (rank == host_rank) {
		status = is_varname(name);
	}
	mpi_broadcast(&status, 1, host_rank, comm);
	return status;
}


template< typename T >
bool nse::ConfigParser::mpi_get_value(const char* name,
	T* value, const MPI_Comm comm) const
{
	const int host_rank = 0;

	int rank, status = 0;
	MPI_Comm_rank(comm, &rank);

	if (rank == host_rank) {
		if (get_value(name, value)) status = 1;
	}
	mpi_broadcast(&status, 1, host_rank, comm);
	if (status) mpi_broadcast(value, 1, host_rank, comm);

	return (status == 1);
}

bool nse::ConfigParser::mpi_get_value(const char* name,
	char** value, const MPI_Comm comm) const
{
	const int host_rank = 0;

	int rank, status = 0;
	MPI_Comm_rank(comm, &rank);

	if (rank == host_rank) {
		if (get_value(name, value)) status = strlen(*value) + 1;
	}
	mpi_broadcast(&status, 1, host_rank, comm);
	if (status) {
		if (rank != host_rank) (*value) = new char[status];
		mpi_broadcast(*value, status, host_rank, comm);
	}

	return (status > 0);
}

bool nse::ConfigParser::mpi_get_value(const char* name,
	std::string& value, const MPI_Comm comm) const
{
	char* c_value;
	if (!mpi_get_value(name, &c_value, comm)) return false;

	value = std::string(c_value);

	delete[] c_value;
	return true;
}


template bool nse::ConfigParser::mpi_get_value(const char* name,
	int* value, const MPI_Comm comm) const;
template bool nse::ConfigParser::mpi_get_value(const char* name,
	float* value, const MPI_Comm comm) const;
template bool nse::ConfigParser::mpi_get_value(const char* name,
	double* value, const MPI_Comm comm) const;
template bool nse::ConfigParser::mpi_get_value(const char* name,
	bool* value, const MPI_Comm comm) const;