#pragma once

// [cfg-var.h]: 
// -------------------------------------------------------------------------------------------- //
// configurable variable class 'cfgValue'
// -------------------------------------------------------------------------------------------- //

#define _CRT_SECURE_NO_WARNINGS
#include <string>


namespace scm
{
	bool is_integer(const char* token, int* value);
	bool is_integer(const char* token);

	bool is_double(const char* token, double* value);
	bool is_double(const char* token);

	bool is_valid_c_name(const char* token);
	bool is_valid_string(const char* string);

	bool is_boolean(const char* token, bool* value);
	bool is_boolean(const char* token);

	// --- copy a = b and remove [sym]
	void strcpyrm(char* a, const char* b, const char sym);
	// -------------------------------------------------------------------------------------------- //

	class cfgValue {
	public:

		enum VAR_TYPE { IS_UNDEF, IS_INT, IS_DOUBLE, IS_STRING, IS_BOOLEAN };

		// -------------------------------------------------------------------------------------------- //
		cfgValue();
		cfgValue(const int x);
		cfgValue(const float x);
		cfgValue(const double x);
		cfgValue(const long double x);
		cfgValue(const char* c_str);
		cfgValue(const bool x);
		~cfgValue();
		// -------------------------------------------------------------------------------------------- //

		// -------------------------------------------------------------------------------------------- //
		cfgValue(const cfgValue& x);
		const cfgValue& operator=(cfgValue x);
		void swap(cfgValue& x);
		// -------------------------------------------------------------------------------------------- //

		// --- assuming that string should be in double quotation marks ""
		static cfgValue make_implicit(const char* x_in_string);
		// -------------------------------------------------------------------------------------------- //

		// clear --> type = IS_UNDEF
		// -------------------------------------------------------------------------------------------- //
		void clear();
		// -------------------------------------------------------------------------------------------- //

		// get & check calls
		// -------------------------------------------------------------------------------------------- //
		bool get(int* x) const;
		bool get(float* x) const;
		bool get(double* x) const;
		bool get(long double* x) const;
		bool get(char** c_str) const;
		bool get(std::string& x) const;
		bool get(bool* x) const;

		VAR_TYPE get_type() const;

		// : type != IS_UNDEF
		bool is_defined() const;	
		// -------------------------------------------------------------------------------------------- //

		// print
		// -------------------------------------------------------------------------------------------- //
		void print(FILE *ptr) const;
		void print() const;
		void print_typed() const;
		// -------------------------------------------------------------------------------------------- //

		// operators
		// -------------------------------------------------------------------------------------------- //
		cfgValue& operator+=(const cfgValue& x);
		cfgValue& operator-=(const cfgValue& x);
		cfgValue& operator*=(const cfgValue& x);
		cfgValue& operator/=(const cfgValue& x);
		cfgValue& operator%=(const cfgValue& x);
		cfgValue& operator^=(const cfgValue& x);

		const cfgValue operator+(const cfgValue& x) const;
		const cfgValue operator-(const cfgValue& x) const;
		const cfgValue operator*(const cfgValue& x) const;
		const cfgValue operator/(const cfgValue& x) const;
		const cfgValue operator%(const cfgValue& x) const;
		const cfgValue operator^(const cfgValue& x) const;

		const cfgValue operator==(const cfgValue& x) const;
		const cfgValue operator!=(const cfgValue& x) const;
		const cfgValue operator<(const cfgValue& x) const;
		const cfgValue operator>(const cfgValue& x) const;
		const cfgValue operator<=(const cfgValue& x) const;
		const cfgValue operator>=(const cfgValue& x) const;

		const cfgValue operator-() const;
		const cfgValue operator+() const;

		const cfgValue logical_and(const cfgValue& x) const;	// no short-circuit
		const cfgValue logical_or(const cfgValue& y) const;		// no short-circuit
		// -------------------------------------------------------------------------------------------- //

		// functions 
		// -------------------------------------------------------------------------------------------- //
		static const cfgValue cfg_sin(const cfgValue& x);
		static const cfgValue cfg_cos(const cfgValue& x);
		static const cfgValue cfg_tan(const cfgValue& x);
		static const cfgValue cfg_log(const cfgValue& x);
		static const cfgValue cfg_sqrt(const cfgValue& x);
		static const cfgValue cfg_abs(const cfgValue& x);
		static const cfgValue cfg_to_string(const cfgValue& x);

		static const cfgValue cfg_min(const cfgValue& a, const cfgValue& b);
		static const cfgValue cfg_max(const cfgValue& a, const cfgValue& b);
		// -------------------------------------------------------------------------------------------- //

	private:
		// data (private):
		// -------------------------------------------------------------------------------------------- //

		VAR_TYPE type;

		int eint;
		double edouble;
		char *estring;
		bool ebool;
	};
}
// -------------------------------------------------------------------------------------------- //