/*
 * RawDataFactory.h
 *
 *  Created on: Nov 23, 2013
 *      Author: Jan Travnicek
 */

#ifndef RAW_DATA_FACTORY
#define RAW_DATA_FACTORY

#include <alib/set>
#include <exception/CommonException.h>
#include <core/rawApi.hpp>
#include <fstream>
#include <sstream>
#include <global/GlobalData.h>

namespace factory {

class RawDataFactory {
public:
	class fromFile {
		const std::string & filename;

	public:
		fromFile ( const std::string & file ) : filename ( file ) {
		}

		template < class T >
		operator T ( ) {
			std::ifstream fileStream ( filename );

			return fromStream ( fileStream );
		}
	};

	class fromRaw {
		const std::string & string;

	public:
		fromRaw ( const std::string & str ) : string ( str ) {
		}

		template < class T >
		operator T ( ) {
			std::stringstream stringStream ( string );

			return fromStream ( stringStream );
		}
	};

	class fromString {
		const std::string & string;

	public:
		fromString ( const std::string & str ) : string ( str ) {
		}

		template < class T >
		operator T ( ) {
			std::stringstream stringStream ( string );

			return fromStream ( stringStream );
		}
	};

	class fromStdin {
	public:
		template < class T >
		operator T ( ) {
			return fromStream ( common::Streams::in );
		}
	};

	class fromStream {
		std::istream & in;

	public:
		fromStream ( std::istream & i ) : in ( i ) {
		}

		template < class T >
		operator T ( ) {
			if ( in.peek ( ) == EOF )
				throw exception::CommonException ( "Empty stream" );

			T res = core::rawApi < T >::parse ( in );

			while ( isspace ( in.peek ( ) ) )
				in.get ( );

			if ( in.peek ( ) != EOF )
				throw exception::CommonException ( "Unexpected characters at the end of the stream" );

			return res;
		}
	};

	template < class T >
	static void toFile ( const T & data, const std::string & filename) {
		std::ofstream fileStream ( filename );
		toStream < T > ( data, fileStream );
	}

	template < class T >
	static std::string toString ( const T & data ) {
		std::stringstream stringStream;
		toStream < T > ( data, stringStream );
		return stringStream.str ( );
	}

	template < class T >
	static void toStdout ( const T & data ) {
		toStream < T > ( data, common::Streams::out );
	}

	template < class T >
	static void toStream ( const T & data, std::ostream & out ) {
		core::rawApi < T >::compose ( out, data );
	}
};

} /* namespace factory */

#endif /* RAW_DATA_FACTORY */
