#ifndef ERRORSTREAM_H
#define ERRORSTREAM_H

#include <iostream>
#include <string>
using namespace std;

// predefined ExceptionStream functors------------------------------------

///Functor which pause program and after some key is pressed then terminate the program.
class PauseAndExitFunctor
{
public:
	void operator()(void);
};

///Functor which do absolutely nothing.
class ContinueFunctor
{
public:
	void operator()(void);
};
//------------------------------------------------------------------------

///Exception stream template, is stream with extended functionality
template <typename STREAM, typename EXCEPTION_FUNCTOR = continueFunctor >
class ExceptionStream
{
protected:
	STREAM stream;
	EXCEPTION_FUNCTOR functor;
	string rubric;	// 'zahlavi' in czech
	string body;
	string footer;	// 'zapati' in czech

	bool ignore;
public:
	ExceptionStream( STREAM stream, const string &rubric, const string &body, const string &footer, bool ingore = false);
	ExceptionStream& operator<<( const string& message); //TODO concat bug ( <<a<<b<<c doesnt work?!! )
	void onErrorFunctor(void);
};

template<typename STREAM, typename EXCEPTION_FUNCTOR> ExceptionStream<STREAM, EXCEPTION_FUNCTOR>::ExceptionStream( STREAM stream, const string &rubric, const string &body, const string &footer,  bool ingore ): stream( stream )
{
	this->rubric = rubric;
	this->body = body;
	this->footer = footer;

	this->ignore = ingore;
}

template<typename STREAM, typename EXCEPTION_FUNCTOR> ExceptionStream<STREAM, EXCEPTION_FUNCTOR>& ExceptionStream<STREAM, EXCEPTION_FUNCTOR>::operator<<( const string& message)
{
	if ( ! this->ignore )
	{
		this->stream<< rubric << body << message << footer;
		functor();
	}

	return *this;
}

///Class which provide operator<<, that do nothing.
class NoStream
{
public:
	NoStream & operator<<( const string& ignoredMessage) 
	{
		//do nothing, just throw messege away
		return *this;
	}
	NoStream & operator<<( const int ) 
	{
		//do nothing, just throw messege away
		return *this;
	}
};



#ifdef RELEASE_MODE
	typedef NoStream KODIAK_DEBUG_STREAM;
#else
	typedef ostream& KODIAK_DEBUG_STREAM;
#endif

const string KODIAK_ENDL ("\n");

#endif