/*
 * GlobalData.h
 *
 *  Created on: 9. 2. 2014
 *      Author: Jan Travnicek
 */

#pragma once

#include <alib/functional>
#include <alib/istream>
#include <ostream>

namespace common {

/**
 * \brief
 * Class to represent some global modifiers and data.
 */
class GlobalData {
public:
	/**
	 * \brief
	 * Verbose flag. Some algorithms print additional runtime information about internal datastructures or their trace. Set the variable to true to enable.
	 */
	static bool verbose;

	/**
	 * \brief
	 * Measure flag. Some algorithms support measurements of runtime properties (time, memory, etc.) Set the variable to true to enable.
	 */
	static bool measure;

	/**
	 * Xml internal representation optimize flag. The xml representation of datatypes may contain references to previous nodes to remove duplicty. Set the variable to true to enable.
	 */
	static bool optimizeXml;

	/**
	 * \brief
	 * The number of argument values as provided by the shell to the main function.
	 */
	static int argc;

	/**
	 * \brief
	 * The agrument values as provided by the shell to the main function.
	 */
	static char * * argv;
};

/**
 * \brief
 * Aggregation class for various standard streams defined by the library.
 */
class Streams {
public:
	/**
	 * \brief
	 * Standard input stream. Mapped to descriptor 0.
	 */
	static ext::reference_wrapper < std::istream > in;

	/**
	 * \brief
	 * Standard output stream. Mapped to descriptor 1.
	 */
	static ext::reference_wrapper < std::ostream > out;

	/**
	 * \brief
	 * Standard error stream. Mapped to descriptor 2.
	 */
	static ext::reference_wrapper < std::ostream > err;

	/**
	 * \brief
	 * Standard loging stream. Mapped to descriptor 4.
	 */
	static ext::reference_wrapper < std::ostream > log;

	/**
	 * \brief
	 * Standard measurement stream. Mapped to descriptor 5.
	 */
	static ext::reference_wrapper < std::ostream > measure;
};

} /* common */

namespace ext {

/**
 * \brief
 * Overloaded function allowing same operations on wrapped output stream as on the actual output stream, specific for constant lvalue referenced objects.
 */
template < class T >
std::ostream & operator << ( ext::reference_wrapper < std::ostream > & os, const T & data ) {
	os.get ( ) << data;
	return os;
}

/**
 * \brief
 * Overloaded function allowing same operations on wrapped output stream as on the actual output stream, specific for rvalue referenced objects.
 */
template < class T >
std::ostream & operator << ( ext::reference_wrapper < std::ostream > & os, T && data ) {
	os.get ( ) << data;
	return os;
}

/**
 * \brief
 * Overloaded function allowing same operations on wrapped output stream as on the actual output stream, specific for modifiers from inside of ostream class.
 */
std::ostream & operator << ( ext::reference_wrapper < std::ostream > & os, std::ostream & ( * func ) ( std::ostream & ) );

/**
 * \brief
 * Overloaded function allowing same operations on wrapped output stream as on the actual output stream, specific for modifiers from inside of ios_base class.
 */
std::ostream & operator << ( ext::reference_wrapper < std::ostream > & os, std::ios_base & ( * func ) ( std::ios_base & ) );



/**
 * \brief
 * Overloaded function allowing same operations on wrapped input stream as on the actual input stream, specific for lvalue referenced objects.
 */
template < class T >
std::istream & operator >> ( ext::reference_wrapper < std::istream > & is, T & data ) {
	is.get ( ) >> data;
	return is;
}

/**
 * \brief
 * Overloaded function allowing same operations on wrapped input stream as on the actual input stream, specific for modifiers from inside of istream class.
 */
std::istream & operator >> ( ext::reference_wrapper < std::istream > & is, std::istream & ( * func ) ( std::istream & ) );

/**
 * \brief
 * Overloaded function allowing same operations on wrapped input stream as on the actual input stream, specific for modifiers from inside of ios_base class.
 */
std::istream & operator >> ( ext::reference_wrapper < std::istream > & is, std::ios_base & ( * func ) ( std::ios_base & ) );

} /* namespace ext */

