//------------------------------------------------------------------------------
//	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/output/XmlWriter.h
 * @author Ronald Kluth
 * @date created at 2009/02/18
 * @brief Declaration of class odemx::data::output::XmlWriter
 * @sa XmlWriter.cpp
 * @since 3.0
 */

#ifndef ODEMX_DATA_OUTPUT_XMLWRITER_INCLUDED
#define ODEMX_DATA_OUTPUT_XMLWRITER_INCLUDED

#include <odemx/data/SimRecord.h>
#include <CppLog/Consumer.h>

#include <Poco/XML/XMLWriter.h>
#include <Poco/SAX/AttributesImpl.h>

#include <fstream>
#include <string>
#ifdef _MSC_VER
#include <memory>
#else
#include <tr1/memory>
#endif

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

namespace odemx {
namespace data {
namespace output {

class TimeFormat;

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

/**
 * @brief A log consumer implementation that writes XML files
 * @ingroup data
 * @author Ronald Kluth
 * @since 3.0
 * @see odemx::data::Producer
 *
 * Using this consumer, all log output from ODEMx can be stored in XML files.
 * This can result in a huge amount of data. In order to prevent files from
 * becoming too large, a limit can be set. Usually, this means that a number
 * of files are generated, and they all receive a counter for unique names.
 * Furthermore, the class keeps track of all generated files and also outputs
 * an overview file containing the names and time periods of all XML files.
 * Finally, an HTML skeleton file is created. This is used to display the
 * XML data in web browsers. A Javascript is used to parse the XML files and
 * to offer interactive filtering of displayed log records.
 *
 * @note The schema for the XML output can be found in the file XmlWriter.xsd.
 */
class XmlWriter
:	public Log::Consumer< SimRecord >
{
public:

	/**
	 * @brief Creation by static method
	 * @param fileNamePrefix The prefix of the file name to be used
	 * @param fileRecordLimit The record limit per file
	 * @return A shared_ptr-managed XmlWriter object
	 *
	 * This method enforces the use of reference-counting pointers to data
	 * consumer objects in order to avoid manual memory management of these
	 * resources. ODEMx log channels maintain a set of shared pointers to
	 * their consumers, which guarantees that consumer objects stay alive while
	 * they are registered with a channel.
	 */
	static std::tr1::shared_ptr< XmlWriter > create( const std::string& fileNamePrefix,
			unsigned int fileRecordLimit = 10000 );

	/**
	 * @brief Destruction, finishes the last file
	 *
	 * Since there is no way of knowing when there are no more records to
	 * be logged, this class uses the destructor to finish the last open
	 * XML file. This also the place where the XML file with the file info
	 * gets generated.
	 */
	virtual ~XmlWriter();

	/**
	 * @brief Implementation of the consumer interface, creates XML data from records
	 * @param channelId ID of the forwarding log channel
	 * @param record A log record describing the current simulation event
	 *
	 * Each SimRecord is printed as a new @c record element in the XML file.
	 * Child elements are @c time, @c channel, @c text, @c scope, @c senderlabel,
	 * @c sendertype and @c detail. Details are optional and will only be printed
	 * of the record contains any.
	 */
	virtual void consume( const Log::ChannelId channelId, const SimRecord& record );

	/**
	 * @brief Set a new time formatter
	 * @param timeFormat Pointer to a dynamically allocated time formatter
	 * @see odemx::data::output::GermanTime odemx::data::output::Iso8601Time
	 *
	 * The default formatter simply outputs SimTime values. The function takes
	 * ownership of the pointer and deletes it automatically when the writer is
	 * destroyed or the format is changed.
	 */
	void setTimeFormat( TimeFormat* timeFormat );

private:

	/// Internal structure used for book-kepping about created XML files
	struct FileInfo
	{
		/// Construction
		FileInfo( const std::string& name, const std::string& startTime = "0",
				const std::string& endTime = "0" )
		:	name( name )
		,	startTime( startTime )
		,	endTime( endTime )
		{}

		std::string name; ///< The name of the file represented by the object
		std::string startTime; ///< The simulation time of the first record sent
		std::string endTime; ///< The simulation time of the last record in the file
	};

	/// Vector type to hold FileInfo objects
	typedef std::vector< FileInfo > FileInfoVec;

private:
	/// The prefix for the file names to be created
	std::string fileNamePrefix_;
	/// The limit for the amount of log records per file
	unsigned int fileRecordLimit_;
	/// The number of records contained in the current file
	unsigned int fileRecordCount_;
	/// The simulation time of the last record
	base::SimTime lastRecordTime_;
	/// Stores information about all generated XML files
	FileInfoVec fileInfos_;
	/// The file stream the records get written to
	std::ofstream fileStream_;
	/// A helper object that takes care of XML formatting
	std::auto_ptr< Poco::XML::XMLWriter > writer_;
	/// A helper object that takes care of SimTime formatting
	std::auto_ptr< TimeFormat > format_;
	/// A helper object that holds XML attributes
	Poco::XML::AttributesImpl attrs_; // Avoids repeated creation and fixes pure virtual call

private:
	/// Generates an HTML skeleton file for siplay of XML via Javascript and CSS
	void createHtml();
	/// Closes the previous XML file and starts a new one
	void startNewFile( base::SimTime currentRecordTime );
	/// Collects the file data and creates an XML file with the infos.
	void outputFileInfo();

	/// Construction only via create()
	XmlWriter( const std::string& fileNamePrefix, unsigned int fileRecordLimit );
	/// Non-copyable
	XmlWriter( const XmlWriter& );
	/// Non-assignable
	XmlWriter& operator=( const XmlWriter& );
};

/// Smart pointer type to manage XmlWriter objects
typedef std::tr1::shared_ptr< XmlWriter > XmlWriterPtr;

} } } // namespace odemx::data::output

#endif /* ODEMX_DATA_OUTPUT_XMLWRITER_INCLUDED */
