//
// 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 CppLog/output/OStreamWriter.h
 * @author Ronald Kluth
 * @date 2009/06/17
 * @brief Declaration and implementation of class template OStreamWriter
 * @since 0.1
 */

#ifndef LOG_OUTPUT_OSTREAMWRITER_INCLUDED
#define LOG_OUTPUT_OSTREAMWRITER_INCLUDED

#include "../Consumer.h"
#include "../Record.h"

#include <ostream>
#include <sstream>
#ifdef _MSC_VER
#include <memory>
#else
#include <tr1/memory>
#endif

namespace Log {

/**
 * @brief Simple log consumer implementation that writes records to a stream
 * @tparam InfoListT List of info types to retrieve from log records
 *
 * This class is a very simple test output component. The @c consume method
 * simply transforms each record into a plain text line. Info type elements
 * are added automatically, according to the type list provided as template
 * parameter.
 */
template < typename InfoListT = Detail::NullList >
class OStreamWriter : public Consumer< Record >
{
public:
	/// List of info types to retrieve from log records
	typedef InfoListT InfoListType;
	/// Pointer type to manage instances
	typedef std::tr1::shared_ptr< OStreamWriter< InfoListType > > Ptr;

	/// Creation of OStreamWriter objects wrapped in a @c shared_ptr
	static Ptr create( std::ostream& os )
	{
		return Ptr( new OStreamWriter( os ) );
	}

	/// Redefinition of the log consumer interface method
	virtual void consume( const Log::ChannelId channelId, const Record& record )
	{
		if( ! record.getText().empty() )
		{
			os_ << record.getText();
		}
		MakeInfoString makeString;
		record.iterateInfo< InfoListType >( makeString );

		if( ! makeString.stream.str().empty() )
		{
			os_ << " [Info:" << makeString.stream.str() << "]";
		}
		os_ << std::endl;
	}
private:
	/// Construction, private, use @c create instead
	OStreamWriter( std::ostream& os ): os_( os ) {}

private:
	/// Reference to the stream the log information is written to
	std::ostream& os_;

private:
	/// Functor to transform record info into strings
	struct MakeInfoString
	{
		std::ostringstream stream;

		template < typename InfoValueT >
		void operator()( const Log::StringLiteral& name, const InfoValueT& value, bool found )
		{
			if( found )
			{
				stream << " " << name << "=" << value;
			}
		}
	};
};

} // namespace Log

#endif /* LOG_OUTPUT_OSTREAMWRITER_INCLUDED */
