/*
 * PrimitiveRegistrator.cpp
 *
 *  Created on: 11. 7. 2017
 *	  Author: Jan Travnicek
 */

#include <registry/CastRegistry.hpp>
#include <registry/ValuePrinterRegistry.hpp>
#include <registry/ContainerRegistry.hpp>

#include <object/Object.h>

#include <alib/trie>
#include <alib/exception>
#include <exception/CommonException.h>

#include <registration/OperatorRegistration.hpp>

namespace {

class PrimitiveRegistrator {
	static const ext::set < object::Object > & denormalizeSetObject ( const object::Object & o ) {
		const object::AnyObjectBase & data = o.getData ( );
		const object::AnyObject < ext::set < object::Object > > * innerData = dynamic_cast < const object::AnyObject < ext::set < object::Object > > * > ( & data );
		if ( innerData )
			return innerData->getData ( );
		throw std::invalid_argument ( "Casted object does not contain data of type " + ext::to_string < ext::set < object::Object > > ( ) + "." );
	}

	static ext::set < ext::pair < object::Object, object::Object > > denormalizeSetObjectPair ( const object::Object & o ) {
		const object::AnyObjectBase & data = o.getData ( );
		const object::AnyObject < ext::set < ext::pair < object::Object, object::Object > > > * innerData = dynamic_cast < const object::AnyObject < ext::set < ext::pair < object::Object, object::Object > > > * > ( & data );
		if ( innerData )
			return innerData->getData ( );

		const object::AnyObject < ext::set < object::Object > > * innerData2 = dynamic_cast < const object::AnyObject < ext::set < object::Object > > * > ( & data );
		if ( innerData2 ) {
			ext::set < ext::pair < object::Object, object::Object > > res;
			for ( const object::Object & inner : innerData2->getData ( ) ) {
				const object::AnyObjectBase & dataTmp = inner.getData ( );
				const object::AnyObject < ext::pair < object::Object, object::Object > > * innerDataTmp = dynamic_cast < const object::AnyObject < ext::pair < object::Object, object::Object > > * > ( & dataTmp );
				if ( innerDataTmp ) {
					res.insert ( innerDataTmp->getData ( ) );
					continue;
				}

				const object::AnyObject < ext::pair < unsigned, unsigned > > * innerDataTmp2 = dynamic_cast < const object::AnyObject < ext::pair < unsigned, unsigned > > * > ( & dataTmp );
				if ( innerDataTmp2 ) {
					res.insert ( ext::make_pair ( object::Object ( innerDataTmp2->getData ( ).first ), object::Object ( innerDataTmp2->getData ( ).second ) ) );
					continue;
				}
				throw std::invalid_argument ( "Casted object does not contain data of type " + ext::to_string < ext::set < ext::pair < object::Object, object::Object > > > ( ) + "." );
			}
			return res;
		}
		throw std::invalid_argument ( "Casted object does not contain data of type " + ext::to_string < ext::set < ext::pair < object::Object, object::Object > > > ( ) + "." );
	}

public:
	PrimitiveRegistrator ( ) {
		alib::ExceptionHandler::addHandler < 3 > ( [] ( alib::ExceptionHandler::NestedExceptionContainer & exceptions, const exception::CommonException & exception ) {
			exceptions.push_back ( "Common exception", std::string ( exception ) );
		} );

		abstraction::CastRegistry::registerCast < double, int > ( );
		abstraction::CastRegistry::registerCast < int, double > ( );

		abstraction::CastRegistry::registerCastAlgorithm < std::string, int > ( ext::to_string );
		abstraction::CastRegistry::registerCastAlgorithm < int, std::string > ( static_cast < int ( * ) ( const std::string & ) > ( ext::from_string < int > ) );

		abstraction::CastRegistry::registerCast < bool, int > ( );
		abstraction::CastRegistry::registerCast < char, int > ( );
		abstraction::CastRegistry::registerCastAlgorithm < bool, std::string > ( static_cast < bool ( * ) ( const std::string & ) > ( ext::from_string < bool > ) );
		abstraction::CastRegistry::registerCastAlgorithm < unsigned, std::string > ( "unsigned", ext::to_string < std::string > ( ), static_cast < unsigned ( * ) ( const std::string & ) > ( ext::from_string < unsigned > ) );
		abstraction::CastRegistry::registerCastAlgorithm < double, std::string > ( static_cast < double ( * ) ( const std::string & ) > ( ext::from_string < double > ) );

		abstraction::CastRegistry::registerCast < size_t, int > ( "size_t", ext::to_string < int > ( ) );
		abstraction::CastRegistry::registerCast < size_t, int > ( );
		abstraction::CastRegistry::registerCast < int, size_t > ( );
		abstraction::CastRegistry::registerCast < unsigned, int > ( );

		abstraction::CastRegistry::registerCast < long, int > ( "long", ext::to_string < int > ( ) );

		abstraction::CastRegistry::registerCastAlgorithm < const ext::set < object::Object > &, const object::Object & > ( "SetOfObjects", ext::to_string < object::Object > ( ), denormalizeSetObject, true );
		abstraction::CastRegistry::registerCastAlgorithm < ext::set < ext::pair < object::Object, object::Object > >, const object::Object & > ( "SetOfObjectPairs", ext::to_string < object::Object > ( ), denormalizeSetObjectPair, true );
		abstraction::CastRegistry::registerCast < object::Object, const ext::set < object::Object > & > ( "DefaultStateType", ext::to_string < const ext::set < object::Object > & > ( ), true );

		abstraction::ContainerRegistry::registerSet < int > ( );

		abstraction::ValuePrinterRegistry::registerValuePrinter < int > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < unsigned > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < double > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < std::string > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < void > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < bool > ( );

		abstraction::ValuePrinterRegistry::registerValuePrinter < object::Object > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::set < object::Object > > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::set < ext::pair < object::Object, object::Object > > > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::set < ext::set < object::Object > > > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::trie < object::Object, bool > > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::set < unsigned > > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::vector < int > > ( );

		//abstraction::ValuePrinterRegistry::registerValuePrinter < ext::set < string::LinearString > > ( );

		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::vector < object::Object > > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::vector < unsigned > > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::vector < unsigned long > > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::vector < ext::pair < object::Object, object::Object > > > ( );

		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::vector < ext::vector < ext::set < object::Object > > > > ( );

		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::pair < ext::vector < object::Object >, double > > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::pair < ext::vector < object::Object >, int > > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::pair < ext::vector < object::Object >, long > > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::pair < ext::vector < ext::pair < object::Object, object::Object > >, double > > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::pair < ext::vector < ext::pair < object::Object, object::Object > >, int > > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::pair < ext::vector < ext::pair < object::Object, object::Object > >, long > > ( );
        abstraction::ValuePrinterRegistry::registerValuePrinter < ext::map < object::Object, unsigned > > ( );
        abstraction::ValuePrinterRegistry::registerValuePrinter < ext::map < object::Object, unsigned long > > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::map < object::Object, ext::set < object::Object > > > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::map < object::Object, ext::map < object::Object, double > > > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::map < object::Object, ext::map < object::Object, int > > > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::map < object::Object, ext::map < object::Object, long > > > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::map < ext::pair < object::Object, object::Object >, ext::map < ext::pair < object::Object, object::Object >, double > > > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::map < ext::pair < object::Object, object::Object >, ext::map < ext::pair < object::Object, object::Object >, int > > > ( );
		abstraction::ValuePrinterRegistry::registerValuePrinter < ext::map < ext::pair < object::Object, object::Object >, ext::map < ext::pair < object::Object, object::Object >, long > > > ( );
		abstraction::ContainerRegistry::registerSet < object::Object > ( );
	}

	~PrimitiveRegistrator ( ) {
		abstraction::CastRegistry::unregisterCast < double, int > ( );
		abstraction::CastRegistry::unregisterCast < int, double > ( );

		abstraction::CastRegistry::unregisterCast < std::string, int > ( );
		abstraction::CastRegistry::unregisterCast < int, std::string > ( );

		abstraction::CastRegistry::unregisterCast < bool, int > ( );
		abstraction::CastRegistry::unregisterCast < char, int > ( );
		abstraction::CastRegistry::unregisterCast < bool, std::string > ( );
		abstraction::CastRegistry::unregisterCast ( "unsigned", ext::to_string < std::string > ( ) );
		abstraction::CastRegistry::unregisterCast < double, std::string > ( );

		abstraction::CastRegistry::unregisterCast ( "size_t", ext::to_string < int > ( ) );
		abstraction::CastRegistry::unregisterCast < size_t, int > ( );
		abstraction::CastRegistry::unregisterCast < int, size_t > ( );
		abstraction::CastRegistry::unregisterCast < unsigned, int > ( );

		abstraction::CastRegistry::unregisterCast ( "long", ext::to_string < int > ( ) );
		abstraction::CastRegistry::unregisterCast ( "SetOfObjects", ext::to_string < object::Object > ( ) );
		abstraction::CastRegistry::unregisterCast ( "SetOfObjectPairs", ext::to_string < object::Object > ( ) );
		abstraction::CastRegistry::unregisterCast ( "DefaultStateType", ext::to_string < const ext::set < object::Object > & > ( ) );

		abstraction::ContainerRegistry::unregisterSet < int > ( );

		abstraction::ValuePrinterRegistry::unregisterValuePrinter < int > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < unsigned > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < double > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < std::string > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < void > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < bool > ( );

		abstraction::ValuePrinterRegistry::unregisterValuePrinter < object::Object > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::set < object::Object > > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::set < ext::pair < object::Object, object::Object > > > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::set < ext::set < object::Object > > > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::trie < object::Object, bool > > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::set < unsigned > > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::vector < int > > ( );

		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::vector < object::Object > > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::vector < unsigned > > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::vector < ext::pair < object::Object, object::Object > > > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::vector < ext::vector < ext::set < object::Object > > > > ( );

		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::pair < ext::vector < object::Object >, double > > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::pair < ext::vector < object::Object >, int > > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::pair < ext::vector < object::Object >, long > > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::pair < ext::vector < ext::pair < object::Object, object::Object > >, double > > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::pair < ext::vector < ext::pair < object::Object, object::Object > >, int > > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::pair < ext::vector < ext::pair < object::Object, object::Object > >, long > > ( );
        abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::map < object::Object, unsigned > > ( );
        abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::map < object::Object, unsigned long > > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::map < object::Object, ext::set < object::Object > > > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::map < object::Object, ext::map < object::Object, double > > > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::map < object::Object, ext::map < object::Object, int > > > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::map < object::Object, ext::map < object::Object, long > > > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::map < ext::pair < object::Object, object::Object >, ext::map < ext::pair < object::Object, object::Object >, double > > > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::map < ext::pair < object::Object, object::Object >, ext::map < ext::pair < object::Object, object::Object >, int > > > ( );
		abstraction::ValuePrinterRegistry::unregisterValuePrinter < ext::map < ext::pair < object::Object, object::Object >, ext::map < ext::pair < object::Object, object::Object >, long > > > ( );
		abstraction::ContainerRegistry::unregisterSet < object::Object > ( );
	}
};

auto primitiveRegistrator = PrimitiveRegistrator ( );

auto addInts = registration::BinaryOperatorRegister < abstraction::Operators::BinaryOperators::ADD, int, int > ( );
auto subInts = registration::BinaryOperatorRegister < abstraction::Operators::BinaryOperators::SUB, int, int > ( );
auto modInts = registration::BinaryOperatorRegister < abstraction::Operators::BinaryOperators::MOD, int, int > ( );
auto mulInts = registration::BinaryOperatorRegister < abstraction::Operators::BinaryOperators::MUL, int, int > ( );
auto divInts = registration::BinaryOperatorRegister < abstraction::Operators::BinaryOperators::DIV, int, int > ( );

auto equalsInts = registration::BinaryOperatorRegister < abstraction::Operators::BinaryOperators::EQUALS, int, int > ( );
auto notEqualsInts = registration::BinaryOperatorRegister < abstraction::Operators::BinaryOperators::NOT_EQUALS, int, int > ( );

auto lessInts = registration::BinaryOperatorRegister < abstraction::Operators::BinaryOperators::LESS, int, int > ( );
auto lessOrEqualInts = registration::BinaryOperatorRegister < abstraction::Operators::BinaryOperators::LESS_OR_EQUAL, int, int > ( );
auto moreInts = registration::BinaryOperatorRegister < abstraction::Operators::BinaryOperators::MORE, int, int > ( );
auto moreOrEqualInts = registration::BinaryOperatorRegister < abstraction::Operators::BinaryOperators::MORE_OR_EQUAL, int, int > ( );

auto andInts = registration::BinaryOperatorRegister < abstraction::Operators::BinaryOperators::BINARY_AND, int, int > ( );
auto orInts = registration::BinaryOperatorRegister < abstraction::Operators::BinaryOperators::BINARY_OR, int, int > ( );
auto xorInts = registration::BinaryOperatorRegister < abstraction::Operators::BinaryOperators::BINARY_XOR, int, int > ( );

auto plusInt = registration::PrefixOperatorRegister < abstraction::Operators::PrefixOperators::PLUS, int > ( );
auto minusInt = registration::PrefixOperatorRegister < abstraction::Operators::PrefixOperators::MINUS, int > ( );

auto negInt = registration::PrefixOperatorRegister < abstraction::Operators::PrefixOperators::BINARY_NEG, int > ( );

auto postIncrementInt = registration::PostfixOperatorRegister < abstraction::Operators::PostfixOperators::INCREMENT, int & > ( );
auto postDecrementInt = registration::PostfixOperatorRegister < abstraction::Operators::PostfixOperators::DECREMENT, int & > ( );

auto prefixIncrementInt = registration::PrefixOperatorRegister < abstraction::Operators::PrefixOperators::INCREMENT, int & > ( );
auto prefixDecrementInt = registration::PrefixOperatorRegister < abstraction::Operators::PrefixOperators::DECREMENT, int & > ( );

auto assignInt = registration::BinaryOperatorRegister < abstraction::Operators::BinaryOperators::ASSIGN, int &, int > ( );



auto andBools = registration::BinaryOperatorRegister < abstraction::Operators::BinaryOperators::LOGICAL_AND, bool, bool > ( );
auto orBools = registration::BinaryOperatorRegister < abstraction::Operators::BinaryOperators::LOGICAL_OR, bool, bool > ( );

auto notBools = registration::PrefixOperatorRegister < abstraction::Operators::PrefixOperators::LOGICAL_NOT, bool > ( );

auto equalsBools = registration::BinaryOperatorRegister < abstraction::Operators::BinaryOperators::EQUALS, bool, bool > ( );
auto notEqualsBools = registration::BinaryOperatorRegister < abstraction::Operators::BinaryOperators::NOT_EQUALS, bool, bool > ( );

} /* namespace */
