//------------------------------------------------------------------------------
//	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 LoggingManager.cpp
 * @author Ronald Kluth
 * @date created at 2009/03/18
 * @brief Implementation of odemx::data::LoggingManager
 * @sa LoggingManager.h
 * @since 3.0
 */

#include <odemx/data/LoggingManager.h>
#include <odemx/base/Simulation.h>
#include <odemx/data/Producer.h>
#include <odemx/data/buffer/StatisticsBuffer.h>
#include <odemx/data/output/DatabaseWriter.h>
#include <odemx/data/output/ErrorWriter.h>
#include <odemx/data/output/OStreamWriter.h>
#include <odemx/data/output/XmlWriter.h>
#include <odemx/data/output/OStreamReport.h>
#include <odemx/data/output/XmlReport.h>
#include <odemx/util/Exceptions.h>

#include <iostream> // std::cout for default logging

namespace odemx {
namespace data {

//------------------------------------------------------------------local struct

typedef std::tr1::shared_ptr< Log::Consumer<SimRecord> > ConsumerPtr;

struct DefaultLogConfig
{
	ConsumerPtr writer;
	std::tr1::shared_ptr< data::buffer::StatisticsBuffer > statsBuffer;
};

//------------------------------------------------------construction/destruction

LoggingManager::LoggingManager()
:	Log::ChannelManager< SimRecord >()
,	defaultLogConfig_( 0 )
{
	initErrorLogging();
}

LoggingManager::LoggingManager( const std::string& defLabel,
		const char defSpace )
:	Log::ChannelManager< SimRecord >( defLabel, defSpace )
,	defaultLogConfig_( 0 )
{
	initErrorLogging();
}

LoggingManager::~LoggingManager()
{
}

//---------------------------------------------------------------default logging

void LoggingManager::initErrorLogging()
{
	using namespace std::tr1;
	using namespace output;

	// we don't keep a pointer to the error writer as member
	// because it is not intended to be accessed by anyone
	shared_ptr< ErrorWriter > cerrWriter = ErrorWriter::create();
	getChannel( channel_id::warning )->addConsumer( cerrWriter );
	getChannel( channel_id::error )->addConsumer( cerrWriter );
	getChannel( channel_id::fatal )->addConsumer( cerrWriter );
}

bool LoggingManager::enableDefaultLogging( output::Type type,
		const std::string& location )
{
	using namespace buffer;
	using namespace output;

	// only initialize once
	if( ! defaultLogConfig_.get() )
	{
		// make sure the channels are initialized
		// error channels are active due to default error logging
		getChannel( channel_id::trace );
		getChannel( channel_id::debug );
		getChannel( channel_id::info );
		getChannel( channel_id::statistics );

		// create log config to keep a pointer to the statistics buffer
		std::auto_ptr< DefaultLogConfig > tmpLogConfig( new DefaultLogConfig );

		switch( type )
		{
		case DATABASE:
			if( location.empty() )
			{
				throw DataOutputException( "LogginManager::enableDefaultLogging():"
						"database connection string empty" );
			}
			tmpLogConfig->writer = DatabaseWriter::create( location );
			break;
		case STDOUT:
			tmpLogConfig->writer = OStreamWriter::create( std::cout );
			break;
		case XML:
			if( location.empty() )
			{
				throw DataOutputException( "LoggingManager::enableDefaultLogging():"
						"XML base file name empty" );
			}
			tmpLogConfig->writer = XmlWriter::create( location, 1000 );
			break;
		default:
			break;
		}

		defaultLogConfig_ = tmpLogConfig;

		// add the default output writer to all log channels
		addConsumer( defaultLogConfig_->writer );

		// create the default statistics buffer and add it as consumer
		defaultLogConfig_->statsBuffer =
				StatisticsBuffer::create(
						dynamic_cast< base::Simulation& >( *this ),
						"Default Statistics Buffer" );
		addConsumer( channel_id::statistics, defaultLogConfig_->statsBuffer );

		return true;
	}
	return false;
}

bool LoggingManager::disableDefaultLogging()
{
	using namespace buffer;
	using namespace output;

	if( defaultLogConfig_.get() )
	{
		removeConsumer( defaultLogConfig_->writer );
		removeConsumer( data::channel_id::statistics, defaultLogConfig_->statsBuffer );
		defaultLogConfig_.reset( 0 );
		return true;
	}
	return false;
}

bool LoggingManager::resetDefaultStatistics( base::SimTime currentTime )
{
	// check if default logging has been enabled
	if( ! defaultLogConfig_.get() )
	{
		return false;
	}
	// reset the statistics buffer
	defaultLogConfig_->statsBuffer->reset( currentTime );
	return true;
}

bool LoggingManager::reportDefaultStatistics( output::Type type,
		const std::string& location )
{
	using namespace data::output;

	// check if default logging has been enabled
	if( ! defaultLogConfig_.get() )
	{
		return false;
	}

	std::auto_ptr< Report > report;
	switch( type )
	{
	case STDOUT:
		report.reset( new OStreamReport( std::cout ) );
		break;
	case XML:
		if( location.empty() )
		{
			throw DataOutputException( "LoggingManager::reportDefaultStatistics(): "
					"XML file name empty" );
		}
		report.reset( new XmlReport( location ) );
		break;
	case DATABASE:
		throw DataOutputException( "LoggingManager::reportDefaultStatistics(): "
					"database output not supported" );
		break;
	}

	// generate report from the default statistics buffer
	report->addReportProducer( *defaultLogConfig_->statsBuffer );
	report->generateReport();
	return true;
}

} } // namespace odemx::data
