/*
 * StringApi.hpp
 *
 * Created on: Apr 1, 2013
 * Author: Jan Travnicek
 */

#pragma once

#include <alib/functional>
#include <alib/list>
#include <alib/map>
#include <alib/string>
#include <alib/memory>
#include <alib/algorithm>
#include <alib/istream>
#include <alib/typeinfo>
#include <alib/algorithm>

#include <object/Object.h>
#include <object/AnyObject.h>

#include "exception/CommonException.h"

namespace core {

template < typename T >
struct stringApi;

template < >
struct stringApi < object::Object > {
public:
	class GroupReader {
	public:
		virtual object::Object parse ( std::istream & input ) = 0;

		virtual ~GroupReader ( ) = default;
	};

private:
	static ext::list < std::pair < std::function < bool ( std::istream & ) >, std::unique_ptr < GroupReader > > > & parseFunctions ( );

	template < class Type >
	class ReaderRegister : public GroupReader {
	public:
		~ReaderRegister ( ) override = default;

		object::Object parse ( std::istream & input ) override {
			return object::Object ( stringApi < Type >::parse ( input ) );
		}
	};

public:
	class GroupWriter {
	public:
		virtual void compose ( std::ostream & output, const object::Object & group ) = 0;

		virtual ~GroupWriter ( ) = default;
	};

private:
	static ext::map < std::string, std::unique_ptr < GroupWriter > > & composeFunctions ( );

	template < class Type >
	class WriterRegister : public GroupWriter {
	public:
		~WriterRegister ( ) override = default;

		void compose ( std::ostream & output, const object::Object & group ) override {
			stringApi < Type >::compose ( output, static_cast < const object::AnyObject < Type > & > ( group.getData ( ) ).getData ( ) );
		}
	};

public:
	static void unregisterStringReader ( ext::list < std::pair < std::function < bool ( std::istream & ) >, std::unique_ptr < GroupReader > > >::const_iterator iter );

	static ext::list < std::pair < std::function < bool ( std::istream & ) >, std::unique_ptr < GroupReader > > >::const_iterator registerStringReader ( std::function < bool ( std::istream & ) > first, std::unique_ptr < GroupReader > entry );

	template < class Type >
	static ext::list < std::pair < std::function < bool ( std::istream & ) >, std::unique_ptr < GroupReader > > >::const_iterator registerStringReader ( ) {
		return registerStringReader ( stringApi < Type >::first, std::unique_ptr < GroupReader > ( new ReaderRegister < Type > ( ) ) );
	}

	static void unregisterStringWriter ( const std::string & type, const std::string & typeName );

	template < class Type >
	static void unregisterStringWriter ( ) {
		unregisterStringWriter ( ext::to_string < object::AnyObject < Type > > ( ), ext::to_string < Type > ( ) );
	}

	static void registerStringWriter ( std::string type, const std::string & typeName, std::unique_ptr < GroupWriter > entry );

	template < class Type >
	static void registerStringWriter ( ) {
		registerStringWriter ( ext::to_string < object::AnyObject < Type > > ( ), ext::to_string < Type > ( ), std::unique_ptr < GroupWriter > ( new WriterRegister < Type > ( ) ) );
	}

	static object::Object parse ( std::istream & input );

	static bool first ( std::istream & input );

	static void compose ( std::ostream & output, const object::Object & data );
};

} /* namespace core */

