//
// 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 Record.h
 * @author Ronald Kluth
 * @date created at 2009/03/01
 * @brief Declaration and implementation of class Record
 * @since 0.1
 */

#ifndef LOG_RECORD_INCLUDED
#define LOG_RECORD_INCLUDED

#include "DeclareInfoType.h"
#include "StringLiteral.h"
#include "detail/InfoHolder.h"
#include "detail/InfoTypeLoop.h"

namespace Log {

/**
 * @struct FileInfo
 * @brief Record info type that holds filenames as @c std::string
 */
#ifndef DOXYGEN_SKIP
CPPLOG_DECLARE_INFO_TYPE( FileInfo, "file", StringLiteral );
#endif

/**
 * @struct LineInfo
 * @brief Record info type that holds line numbers as <tt>unsigned int</tt>
 */
#ifndef DOXYGEN_SKIP
CPPLOG_DECLARE_INFO_TYPE( LineInfo, "line", unsigned int );
#endif

/**
 * @struct ScopeInfo
 * @brief Record info type that holds scope information as @c std::string
 */
#ifndef DOXYGEN_SKIP
CPPLOG_DECLARE_INFO_TYPE( ScopeInfo, "scope", StringLiteral );
#endif

/**
 * @brief The default record type provided by the library
 * 
 * Objects of this class transport information passed through log channels
 *
 * By deriving from InfoHolder, record objects gain the ability to transport
 * information of arbitrary type. All that is needed to use the feature are
 * simple macro calls which declare the used information types.
 *
 * @code
 * CPPLOG_DECLARE_INFO_TYPE( SenderInfo, "Sender", std::string );
 * @endcode
 *
 * After this, the declared type can already be used to add more information
 * to log records. Usage of this feature is implemented through an overloaded
 * @c operator+.  The stored information can be retrieved by calling the method
 * template @c get, which is defined in the base class InfoHolder. The template
 * parameter is the information type.
 *
 * @code
 * Record rec( "log message" );
 * rec + SenderInfo( "class XYZ" );
 *
 * if( SenderInfo::ValueType* sender = rec.get< SenderInfo >() )
 * {
 *     std::cout << *sender;
 * }
 * @endcode
 *
 * The library by default provides three info types for log records:
 * @c FileInfo, @c LineInfo, and @c ScopeInfo. Class Record provides chainable
 * convenience methods to easily add these types. They can be used like this:
 *
 * @code
 * Log::Record rec( "message text" );
 * rec.file( __FILE__ ).line( __LINE__ ).scope( "foo()" );
 * @endcode
 */
class Record
:	public Detail::InfoHolder< Record >
{
public:
	/// Default construction
	Record() {}

	/// Construction with text message
	Record( const StringLiteral& text )
	:	text_( text )
	{}

	/// Destruction
	virtual ~Record() {}

	/// Add file information to the record, supports method chaining
	Record& file( const StringLiteral& file )
	{
		*this + FileInfo( file );
		return *this;
	}

	/// Add line information to the record, supports method chaining
	Record& line( const unsigned int lineNumber )
	{
		*this + LineInfo( lineNumber );
		return *this;
	}

	/// Add scope information to the record, supports method chaining
	Record& scope( const StringLiteral& scope )
	{
		*this + ScopeInfo( scope );
		return *this;
	}
	/// Get the text message sent with the log record
	const StringLiteral& getText() const
	{
		return text_;
	}

	/// Call @c func on the record object for all listed info types and return @c func
	template < typename InfoListT, typename FuncT >
	FuncT& iterateInfo( FuncT& func ) const
	{
		Detail::InfoTypeLoop<
			FuncT,
			Record,
			InfoListT,
			Detail::SizeOf< InfoListT >::value - 1
		>::call( func, *this );
		return func;
	}

private:
	/// Stores the message text transported by a record
	StringLiteral text_;
};

} // namespace Log

#endif /* LOG_RECORD_INCLUDED */
