/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* librvngabw
 * Version: MPL 2.0 / LGPLv2.1+
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Major Contributor(s):
 * Copyright (C) 2002-2004 William Lachance (wrlach@gmail.com)
 * Copyright (C) 2004 Fridrich Strba (fridrich.strba@bluewin.ch)
 *
 * For minor contributions see the git repository.
 *
 * Alternatively, the contents of this file may be used under the terms
 * of the GNU Lesser General Public License Version 2.1 or later
 * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
 * applicable instead of those above.
 *
 * For further information visit http://libwpd.sourceforge.net
 */

/* "This product is not manufactured, approved, or supported by
 * Corel Corporation or Corel Corporation Limited."
 */

#ifndef _ABW_GENERATOR_HXX_
#define _ABW_GENERATOR_HXX_

#include <map>
#include <set>
#include <stack>
#include <string>

#include <librevenge/librevenge.h>
#include <librvngabw/librvngabw.hxx>

#include "DocumentElement.hxx"
#include "FilterInternal.hxx"
#include "Frame.hxx"
#include "ListStyle.hxx"
#include "Picture.hxx"
#include "Table.hxx"
#include "TextRunStyle.hxx"

namespace librvngabw
{
/** a class used to store the intermediate elements before outputting
	them, mainly different managers, the actual state, ...
 */
class ABWGenerator
{
public:
	/** constructor

		\note m_currentElementVector is set to a dummy storage: the
		function which creates an element of this class must reset it
		to a most conveniant storage
	 */
	explicit ABWGenerator(ABWDocumentHandler *pHandler);
	//! destructor
	~ABWGenerator();

	//
	// embedded/check image type
	//

	//! checks if a mime type can be sent or not
	bool checkImage(librevenge::RVNGString &mimeType, const librevenge::RVNGBinaryData &image) const;
	//! stores a check image mimetypt
	void registerCheckImageHandler(ABWCheckImage checkHandler, bool useDefault)
	{
		m_imageCheckHandler=checkHandler;
		m_useImageMineTypeSet=useDefault;
	}

	//! returns a embedded image handler if it exists
	ABWEmbeddedImage findEmbeddedImageHandler(const librevenge::RVNGString &mimeType) const;
	//! stores a embedded image handler
	void registerEmbeddedImageHandler(const librevenge::RVNGString &mimeType, ABWEmbeddedImage imageHandler)
	{
		m_imageHandlerMap[mimeType]=imageHandler;
	}

	//! returns a embedded object handler if it exists
	ABWEmbeddedObject findEmbeddedObjectHandler(const librevenge::RVNGString &mimeType) const;
	//! stores a embedded object handler
	void registerEmbeddedObjectHandler(const librevenge::RVNGString &mimeType, ABWEmbeddedObject objectHandler)
	{
		m_objectHandlerMap[mimeType]=objectHandler;
	}

	//
	// storage
	//

	//! returns the current storage
	DocumentElementVector *getCurrentStorage() const
	{
		return m_currentElementVector;
	}

	//! returns the dummy storage
	DocumentElementVector &getDummyStorage()
	{
		return m_dummyElementVector;
	}

	//! returns the file data storage
	DocumentElementVector &getFileDataStorage()
	{
		return m_fileDataElementVector;
	}

	//! returns the note storage
	DocumentElementVector &getNoteStorage()
	{
		return m_noteElementVector;
	}

	//! push a storage
	void pushStorage(DocumentElementVector *newStorage);
	/** pop a storage */
	bool popStorage();
	//! write the storage data to a document handler
	static void sendStorage(DocumentElementVector const *storage, ABWDocumentHandler *pHandler);
	//! write the different styles to a document handler
	void writeStyles(ABWDocumentHandler *pHandler);

	//
	// font/paragraph
	//

	//! define a character style
	void defineCharacterStyle(const librevenge::RVNGPropertyList &propList);
	//! open a span
	void openSpan(const librevenge::RVNGPropertyList &propList);
	//! close a span
	void closeSpan();

	//! define a paragraph style
	void defineParagraphStyle(const librevenge::RVNGPropertyList &propList);
	//! open a paragraph
	void openParagraph(const librevenge::RVNGPropertyList &propList);
	//! close a paragraph
	void closeParagraph();
	std::string const getHeadingStyleName(int level);

	//
	// link/field
	//

	//! insert a field
	void insertField(const librevenge::RVNGPropertyList &propList);

	//! open a link
	void openLink(const librevenge::RVNGPropertyList &propList);
	//! close a link
	void closeLink();

	//
	// list function
	//

	/// pop the list state (if possible)
	void popListState();
	/// push the list state by adding an empty value
	void pushListState();

	//
	// footnote/endnote/annotation
	//

	//! open a footnote/endnote
	void openNote(const librevenge::RVNGPropertyList &propList, bool footnote);
	//! closes a footnote/endnote
	void closeNote(bool footnote);

	//! open an annotation
	void openAnnotation(const librevenge::RVNGPropertyList &propList);
	//! closes a annotation
	void closeAnnotation();

	//
	// image
	//

	//! inserts a binary object
	void insertBinaryObject(const librevenge::RVNGPropertyList &propList);
	//! inserts a binary object
	void insertSVGBinaryObject(const librevenge::RVNGString &picture,
	                           const librevenge::RVNGPropertyList &propList,
	                           double const &minx, double const &miny, double const &maxx, double const &maxy);
	//! write a binary object
	bool writeBinaryObject(const librevenge::RVNGString &picture, const librevenge::RVNGString &mimeType);

	//
	// frame
	//

	//! update the max frame page number
	void updateFramePageNumber(int pageNumber)
	{
		if (pageNumber>m_framePageNumber)
			m_framePageNumber=pageNumber;
	}
	//! returns the max frame page number
	int getFramePageNumber() const
	{
		return m_framePageNumber;
	}
	//
	// state gestion
	//

	//! the state we use for writing the final document
	struct State
	{
		//! constructor
		State() : m_paragraphOpenedAtCurrentLevel(false),
			m_listElementOpenedAtCurrentLevel(false),
			m_isInHeaderFooter(false), m_isInFrame(false), m_isInAnnotation(false), m_isInNote(false),
			m_isSectionOpened(false), m_isDummySectionOpened(false), m_isSheetOpened(false), m_isTableCellOpened(false), m_isTextBoxOpened(false)
		{
		}
		//! flag to know if a paragraph is opened
		bool m_paragraphOpenedAtCurrentLevel;
		//! flag to know if a list element is opened
		bool m_listElementOpenedAtCurrentLevel;
		//! flag to know if we have opened an header/footer
		bool m_isInHeaderFooter;
		//! flag to know if a abiword frame is opened
		bool m_isInFrame;
		//! flag to know if we have opened an annotation/comment zone
		bool m_isInAnnotation;
		//! flag to know if we have opened a endnote/footnote zone
		bool m_isInNote;
		//! flag to know if a section is opened
		bool m_isSectionOpened;
		//! flag to know if a dummy section is opened
		bool m_isDummySectionOpened;
		//! flag to know if we have opened a sheet zone
		bool m_isSheetOpened;
		//! flag to know if a table cell is opened
		bool m_isTableCellOpened;
		//! flag to know if we have opened a text box
		bool m_isTextBoxOpened;
	};

	//! returns the actual state
	State &getState()
	{
		if (m_stateStack.empty())
		{
			RVNGABW_DEBUG_MSG(("ABWGenerator::getState: no state\n"));
			m_stateStack.push(State());
		}
		return m_stateStack.top();
	}
	//! push a state
	void pushState()
	{
		if (m_stateStack.empty())
			m_stateStack.push(State());
		else
		{
			auto const &orig=m_stateStack.top();
			State newState;
			newState.m_isInHeaderFooter=orig.m_isInHeaderFooter;
			newState.m_isInFrame=orig.m_isInFrame;
			newState.m_isInAnnotation=orig.m_isInAnnotation;
			newState.m_isInNote=orig.m_isInNote;
			m_stateStack.push(newState);
		}

	}
	//! pop a state
	void popState()
	{
		if (!m_stateStack.empty())
			m_stateStack.pop();
		else
		{
			RVNGABW_DEBUG_MSG(("ABWGenerator::popState: no state\n"));
		}
	}
	//! the main document handler
	ABWDocumentHandler *m_documentHandler;
	//! the stack list
	std::stack<State> m_stateStack;

	//! the current set of elements that we're writing to
	DocumentElementVector *m_currentElementVector;
	//! the stack of all storage
	std::stack<DocumentElementVector *> m_elementVectorStack;
	//! note field elements
	DocumentElementVector m_noteElementVector;
	//! data elements
	DocumentElementVector m_fileDataElementVector;
	//! dummy elements
	DocumentElementVector m_dummyElementVector;

	//! the actual xId
	int m_xId;
	//! the anotation id
	int m_annotationId;
	//! the footnote id
	int m_footnoteId;
	//! the endnote id
	int m_endnoteId;
	//! the image id
	int m_imageId;

	//! span manager
	SpanStyleManager m_spanManager;
	//! paragraph manager
	ParagraphStyleManager m_paragraphManager;
	//! list manager
	ListManager m_listManager;
	//! frame manager
	FrameManager m_frameManager;
	//! table manager
	TableManager m_tableManager;

	//! id to span map
	std::map<int, librevenge::RVNGPropertyList> m_idSpanListMap;
	//! id to span name map
	std::map<int, librevenge::RVNGString> m_idSpanNameMap;
	//! the last span name
	librevenge::RVNGString m_lastSpanName;

	//! id to paragraph map
	std::map<int, librevenge::RVNGPropertyList> m_idParagraphListMap;

	//! the last frame page number
	int m_framePageNumber;

	//! map to convert some mime-type to more generic mime-type
	std::map<librevenge::RVNGString, librevenge::RVNGString> m_imageMineTypeToGenericTypeMap;
	//! list of allowed image type
	std::set<librevenge::RVNGString> m_imageMineTypeSet;
	//! true if we need to check the default type
	bool m_useImageMineTypeSet;
	//! image mime type's checker (if defined)
	ABWCheckImage m_imageCheckHandler;
	//! embedded image handlers
	std::map<librevenge::RVNGString, ABWEmbeddedImage > m_imageHandlerMap;
	//! embedded object handlers
	std::map<librevenge::RVNGString, ABWEmbeddedObject > m_objectHandlerMap;

	std::map<int, std::string> m_usedHeadingStyles;
private:
	ABWGenerator(const ABWGenerator &);
	ABWGenerator &operator=(const ABWGenerator &);

};
}

#endif

/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */
