#pragma once

#include <alib/string>

namespace abstraction {

class Operators {
public:
	enum class BinaryOperators {
		LOGICAL_AND,
		LOGICAL_OR,
		BINARY_XOR,
		BINARY_AND,
		BINARY_OR,
		ADD,
		SUB,
		MUL,
		MOD,
		DIV,
		EQUALS,
		NOT_EQUALS,
		LESS,
		LESS_OR_EQUAL,
		MORE,
		MORE_OR_EQUAL,
		ASSIGN
	};

	enum class PrefixOperators {
		PLUS,
		MINUS,
		LOGICAL_NOT,
		BINARY_NEG,
		INCREMENT,
		DECREMENT
	};

	enum class PostfixOperators {
		INCREMENT,
		DECREMENT
	};

	static std::string toString ( BinaryOperators type ) {
		switch ( type ) {
		case BinaryOperators::BINARY_AND :
			return "binary_and";
		case BinaryOperators::BINARY_OR :
			return "binary_or";
		case BinaryOperators::BINARY_XOR :
			return "binary_xor";
		case BinaryOperators::LOGICAL_AND :
			return "logical_and";
		case BinaryOperators::LOGICAL_OR :
			return "logical_or";
		case BinaryOperators::ADD :
			return "add";
		case BinaryOperators::SUB :
			return "sub";
		case BinaryOperators::MUL :
			return "mul";
		case BinaryOperators::MOD :
			return "mod";
		case BinaryOperators::DIV :
			return "div";
		case BinaryOperators::EQUALS :
			return "equals";
		case BinaryOperators::NOT_EQUALS :
			return "not_equals";
		case BinaryOperators::LESS :
			return "less";
		case BinaryOperators::LESS_OR_EQUAL :
			return "less_or_equal";
		case BinaryOperators::MORE :
			return "more";
		case BinaryOperators::MORE_OR_EQUAL :
			return "more_or_equal";
		case BinaryOperators::ASSIGN :
			return "assign";
		}
		throw std::invalid_argument ( "Undefined option" );
	}

	static std::string toString ( PrefixOperators type ) {
		switch ( type ) {
		case PrefixOperators::PLUS :
			return "plus";
		case PrefixOperators::MINUS :
			return "minus";
		case PrefixOperators::LOGICAL_NOT :
			return "logical_not";
		case PrefixOperators::BINARY_NEG :
			return "binary_neg";
		case PrefixOperators::INCREMENT :
			return "increment";
		case PrefixOperators::DECREMENT :
			return "decrement";
		}
		throw std::invalid_argument ( "Undefined option" );
	}

	static std::string toString ( PostfixOperators type ) {
		switch ( type ) {
		case PostfixOperators::INCREMENT :
			return "increment";
		case PostfixOperators::DECREMENT :
			return "decrement";
		}
		throw std::invalid_argument ( "Undefined option" );
	}


};

std::ostream & operator << ( std::ostream & os, Operators::BinaryOperators oper );

std::ostream & operator << ( std::ostream & os, Operators::PrefixOperators oper );

std::ostream & operator << ( std::ostream & os, Operators::PostfixOperators oper );

} /* namespace abstraction */

