//------------------------------------------------------------------------------
//	Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin
//
//	This library is free software; you can redistribute it and/or
//	modify it under the terms of the GNU Lesser General Public
//	License as published by the Free Software Foundation; either
//	version 2.1 of the License, or (at your option) any later version.
//
//	This library is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//	Lesser General Public License for more details.
//
//	You should have received a copy of the GNU Lesser General Public
//	License along with this library; if not, write to the Free Software
//	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//------------------------------------------------------------------------------

/**
 * @file data/Producer.h
 * @author Ronald Kluth
 * @date created at 2009/03/18
 * @brief Declaration of class odemx::data::Producer
 * @sa Producer.cpp
 * @since 3.0
 */

#ifndef ODEMX_DATA_PRODUCER_INCLUDED
#define ODEMX_DATA_PRODUCER_INCLUDED

#include <odemx/setup.h>
#include <odemx/data/ManagedChannels.h>
#include <odemx/data/SimRecord.h>
#include <odemx/data/Label.h>

#include <CppLog/Producer.h>

namespace odemx {

//----------------------------------------------------------forward declarations

namespace base { class Simulation; }

//-----------------------------------------------------------header declarations

namespace data {

/**
 * @brief Producer base type that enables managed ODEMx log channels
 * @since 3.0
 *
 * The logging library included in ODEMx provides a configurable Producer
 * template. By passing the IDs of channels (created with macro
 * ODEMX_DECLARE_DATA_CHANNEL) as Arguments to the template parameter
 * Enable, the producer class receives shared_ptr members which are
 * initialized automatically during construction by the logging manager.
 */
typedef Log::Producer<
			Log::Enable<
				channel_id::trace,
				channel_id::debug,
				channel_id::info,
				channel_id::warning,
				channel_id::error,
				channel_id::fatal,
				channel_id::statistics
				>
		> ProducerBase;

/**
 * @brief Base class for all log-producing classes in ODEMx
 * @ingroup data
 * @author Ronald Kluth
 * @since 3.0
 * @see odemx::data::LoggingManager, ODEMX_DECLARE_DATA_CHANNEL
 *
 * The class odemx::data::Producer is the base class for all ODEMx components
 * that produce log records. This includes statistics producers. It is
 * primarily responsible for enabling access to the log channels that ODEMx
 * provides by default:
 * @li trace
 * @li debug
 * @li info
 * @li warning
 * @li error
 * @li fatal
 * @li statistics
 *
 * All of those channels use the record type @c odemx::data::SimRecord.
 * Access to the channels is automatically provided within subclasses of
 * this class. Channel initialization is based on the cooperation of
 * producer objects with the logging manager.
 *
 * Objects of class odemx::data::Producer are uniquely labeled within one
 * simulation context because all data producers must request a label from
 * the logging manager, which is a base class of odemx::base::Simulation.
 * Uniqueness of labels is ensured by appending numbers if a particular label
 * already exists within the name scope.
 *
 * @note This class replaces the interfaces LabeledObject and TraceProducer
 * from previous versions of ODEMx.
 */
class Producer
:	public ProducerBase
{
public:
	/// Destruction
	virtual ~Producer();

	/**
	 * @brief Enable logging for one producer object
	 * @see disableLogging
	 *
	 * The functionality of enabling and disabling log channels is based on
	 * shared_ptr members. If the pointer is set, logging is active. Otherwise,
	 * all logging statements involving a disabled channel are ignored. This
	 * method reactivates previously disabled log channels.
	 *
	 * @note By default, ODEMx logging functionality is enabled for all producers.
	 * @note The channels @c warning, @c error, and @c fatal are always active.
	 */
	void enableLogging();

	/**
	 * @brief Disable logging for one producer object
	 * @see enableLogging
	 *
	 * Disabling the logging functionality means resetting the shared_ptr
	 * members which reference the log channels. When sucha  pointer is not
	 * set all logging statements involving that channel are ignored.
	 *
	 * @note This only affects the channels @c trace, @c debug, @c info, and
	 * @c statistics. The channels @c warning, @c error, and @c fatal are
	 * always active.
	 */
	void disableLogging();

	/// Get the unique label of the object, used for logging and filtering sender names.
	const Label& getLabel() const;

	/// Get the real type of the object. This is useful for logging and filtering sender types
	const TypeInfo getType() const;

	/// Get a const reference to the simulation context
	const base::Simulation& getSimulation() const;

	/// Get a non-const Reference to the simulation context
	base::Simulation& getSimulation();

protected:
	/// Construction for subclasses only
	Producer( base::Simulation& sim, const Label& label );

	/**
	 * @brief Convenience method to create log records with required parameters
	 *
	 * Using this method is the preferred way of creating log records within
	 * producer classes. Users need only provide the text message of the record
	 * and additional data such as simulation context, time, and sender
	 * is added automatically.
	 *
	 * Usage:
	 * @code
	 *   info << log( "some simulation event" );
	 * @endcode
	 */
	SimRecord log( const StringLiteral& text ) const;

	/**
	 * @name Statistics convenience methods
	 *
	 * Statistical records in ODEMx fall within one of four categories:
	 * @li countable statistics events
	 * @li updated sequences of numbers
	 * @li parameters to be logged only once
	 * @li reset of accumulated data
	 *
	 * The following methods provide quick access to the creation of
	 * adequate log records for each category.
	 * @{
	 */
	/**
	 * @brief Log a countable statistics event
	 * @param name Name of the counted property
	 * @param value Amount to add to the counter, default is 1
	 * @return A log record with text "count" and a detail pair of @c name and @c value
	 */
	SimRecord count( const StringLiteral& name, int value = 1 ) const;

	/**
	 * @brief Log a parameter of a statistics producer
	 * @tparam ValueT Type of the parameter value
	 * @param name Name of the parameter
	 * @param value Value of the parameter, can be of arbitrary simple type
	 * @return A record with text "parameter" and a detail pair of @c name and @c value
	 */
	template < typename ValueT >
	SimRecord param( const StringLiteral& name, ValueT value ) const
	{
		return log( "parameter" ).detail( name, value );
	}

	/**
	 * @brief Log a record for a sequence of numbers
	 * @tparam ValueT Type of the parameter value
	 * @param name Name of the updated property
	 * @param value Value of the current update, must be a numeric type
	 * @return A record with text "update" and a detail pair of @c name and @c value
	 */
	template < typename ValueT >
	SimRecord update( const StringLiteral& name, ValueT value ) const
	{
		return log( "update" ).detail( name, value );
	}

	/**
	 * @brief Log a statistics reset
	 * @return A record with text "reset" and no additional details
	 */
	SimRecord reset() const;
	//@}

private:
	/// Pointer to the simulation context
	base::Simulation* sim_;
};

/**
 * @brief Global ostream inserter overload for data producer references
 *
 * This makes all data producers string-streamable by writing their label
 * to the stream.
 */
extern std::ostream& operator<<( std::ostream& os, const Producer& obj );

/**
 * @brief Global ostream inserter overload for data producer pointers
 *
 * This operator overload also writes the label of a data producer to the stream.
 */
extern std::ostream& operator<<( std::ostream& os, const Producer* obj );

} } // namespace odemx::data

#endif /* ODEMX_DATA_PRODUCER_INCLUDED */
