//
// Copyright (c) 2009-2010 Ronald Kluth
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

/**
 * @file DeclareChannel.h
 * @author Ronald Kluth
 * @date created at 2009/06/05
 * @brief Declaration and implementation of macro CPPLOG_DECLARE_CHANNEL
 * @since 0.1
 */

#ifndef LOG_DECLARECHANNEL_INCLUDED
#define LOG_DECLARECHANNEL_INCLUDED

#include "Channel.h"
#include "ChannelManager.h"
#include "detail/ChannelField.h"

/**
 * @def CPPLOG_DECLARE_CHANNEL_WITH_ID( PP_NameSpace, PP_IdName, PP_RecordType, PP_Id )
 * @brief Declaration of a log channel, corresponding ID, name, and producer member
 * @param PP_NameSpace The namespace the ID should reside in
 * @param PP_IdName The name of the channel ID to be created, also the member name
 * @param PP_RecordType The type of records the channel transports
 * @param PP_Id The value of the ID, must be unique for each macro use
 *
 * This macro has the same effect as @c CPPLOG_DECLARE_CHANNEL, but it allows
 * the manual specification of the channel ID value. It is mainly provided for
 * legacy compilers that do not support the use of the @c __COUNTER__ macro and
 * thus cannot create ID values automatically.
 *
 * @note Since this macro creates template specializations, all uses must
 * have unique ID values in order to create different log channels.
 * @see CPPLOG_DECLARE_CHANNEL, Producer, ChannelManager
 */
#define CPPLOG_DECLARE_CHANNEL_WITH_ID( PP_NameSpace, PP_IdName, PP_RecordType, PP_Id ) \
	namespace PP_NameSpace { enum { PP_IdName = PP_Id }; }								\
	namespace Log {																		\
	namespace Detail {																	\
		template <>																		\
		struct ChannelField< ::PP_NameSpace::PP_IdName >								\
		{																				\
			ChannelField() {}															\
			ChannelField( ChannelManager< PP_RecordType >& manager )					\
			{																			\
				this->PP_IdName = manager.getChannel( ::PP_NameSpace::PP_IdName );		\
			}																			\
			protected:																	\
				std::tr1::shared_ptr< Log::Channel< PP_RecordType > > PP_IdName;		\
		};																				\
	} } // namespace Log::Detail

/**
 * @def CPPLOG_DECLARE_CHANNEL( PP_NameSpace, PP_IdName, PP_RecordType )
 * @brief Declares a log channel with corresponding ID and record type
 * @param PP_NameSpace The namespace the ID should reside in
 * @param PP_IdName The name of the channel ID to be created, also the member name
 * @param PP_RecordType The type of records the channel transports
 *
 * This macro is used to declare log channels which are intended for
 * use with producers and channel managers. In this pattern, the manager will
 * create and manage channel objects with the given IDs, and the producer can
 * automatically use these channels as @c shared_ptr members of the same name.
 *
 * Usage:
 * @code
 * CPPLOG_DECLARE_CHANNEL( channel_id, info, std::string )
 * @endcode
 *
 * The above declaration creates an anonymous enum in namespace
 * @c channel_id that contains @c info. Thus, the ID can be referred to as
 * @c channel_id::info. This identifier can then be used in conjunction
 * with the class templates @c Producer and @c Enable to activate log
 * channel access for a producer class by instantiating the template.
 * Log data producers can then be derived from that type and use the
 * log channel @c info (which is automatically initialized by calling
 * @c getChannel on the manager) as follows:
 *
 * @code
 * typedef Log::Producer< Log::Enable< channel_id::info > > InfoProducer;
 *
 * class DataProducer
 * {
 * public:
 *     DataProducer( Log::ChannnelManager< std::string >& mgr, const std::string& name )
 *     : InfoProducer( mgr, name )
 *     {
 *         info << std::string( "example message" );
 *     }
 * };
 * @endcode
 * @see Producer, ChannelManager
 */
#define CPPLOG_DECLARE_CHANNEL( PP_NameSpace, PP_IdName, PP_RecordType ) \
	CPPLOG_DECLARE_CHANNEL_WITH_ID( PP_NameSpace, PP_IdName, PP_RecordType, __COUNTER__ );

#endif /* LOG_DECLAREMANAGEDCHANNEL_INCLUDED */
