/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* libwpd
 * 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) 2006 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 WPXCONTENTLISTENER_H
#define WPXCONTENTLISTENER_H

#include "WPXTable.h"
#include "WPXTableList.h"
#include "libwpd_internal.h"
#include "WPXSubDocument.h"
#include "WPXPageSpan.h"
#include "WPXListener.h"
#include <memory>
#include <vector>
#include <list>
#include <set>

struct WPXTableDefinition
{
	WPXTableDefinition() : m_positionBits(0), m_leftOffset(0.0), m_columns(), m_columnsProperties() {}
	unsigned char m_positionBits;
	double m_leftOffset;
	std::vector < WPXColumnDefinition > m_columns;
	std::vector < WPXColumnProperties > m_columnsProperties;
};

struct WPXContentParsingState
{
	WPXContentParsingState();
	~WPXContentParsingState();

	unsigned m_textAttributeBits;
	double m_fontSize;
	std::unique_ptr<librevenge::RVNGString> m_fontName;
	std::unique_ptr<RGBSColor> m_fontColor;
	std::unique_ptr<RGBSColor> m_highlightColor;

	bool m_isParagraphColumnBreak;
	bool m_isParagraphPageBreak;
	unsigned char m_paragraphJustification;
	unsigned char m_tempParagraphJustification; // TODO: remove this one after the tabs are properly implemented
	double m_paragraphLineSpacing;

	bool m_isDocumentStarted;
	bool m_isPageSpanOpened;
	bool m_isSectionOpened;
	bool m_isPageSpanBreakDeferred;
	bool m_isHeaderFooterWithoutParagraph;

	bool m_isSpanOpened;
	bool m_isParagraphOpened;
	bool m_isListElementOpened;

	bool m_firstParagraphInPageSpan;

	std::vector<unsigned int> m_numRowsToSkip;
	WPXTableDefinition m_tableDefinition;
	int m_currentTableCol;
	int m_currentTableRow;
	int m_currentTableCellNumberInRow;
	bool m_isTableOpened;
	bool m_isTableRowOpened;
	bool m_isTableColumnOpened;
	bool m_isTableCellOpened;
	bool m_wasHeaderRow;
	bool m_isCellWithoutParagraph;
	bool m_isRowWithoutCell;
	unsigned m_cellAttributeBits;
	unsigned char m_paragraphJustificationBeforeTable;

	unsigned m_currentPage;
	unsigned m_numPagesRemainingInSpan;
	unsigned m_currentPageNumber;

	bool m_sectionAttributesChanged;
	unsigned m_numColumns;
	std::vector < WPXColumnDefinition > m_textColumns;
	bool m_isTextColumnWithoutParagraph;

	double m_pageFormLength;
	double m_pageFormWidth;
	WPXFormOrientation m_pageFormOrientation;

	double m_pageMarginLeft;
	double m_pageMarginRight;
	double m_pageMarginTop;
	double m_pageMarginBottom;
	double m_paragraphMarginLeft;  // resulting paragraph margin that is one of the paragraph
	double m_paragraphMarginRight; // properties
	double m_paragraphMarginTop;
	double m_paragraphMarginBottom;
	double m_leftMarginByPageMarginChange;  // part of the margin due to the PAGE margin change
	double m_rightMarginByPageMarginChange; // inside a page that already has content.
	double m_sectionMarginLeft;  // In multicolumn sections, the above two will be rather interpreted
	double m_sectionMarginRight; // as section margin change
	double m_leftMarginByParagraphMarginChange;  // part of the margin due to the PARAGRAPH
	double m_rightMarginByParagraphMarginChange; // margin change (in WP6)
	double m_leftMarginByTabs;  // part of the margin due to the LEFT or LEFT/RIGHT Indent; the
	double m_rightMarginByTabs; // only part of the margin that is reset at the end of a paragraph

	double m_listReferencePosition; // position from the left page margin of the list number/bullet
	double m_listBeginPosition; // position from the left page margin of the beginning of the list

	double m_paragraphTextIndent; // resulting first line indent that is one of the paragraph properties
	double m_textIndentByParagraphIndentChange; // part of the indent due to the PARAGRAPH indent (WP6???)
	double m_textIndentByTabs; // part of the indent due to the "Back Tab" or "Left Tab"

	unsigned char m_currentListLevel;

	unsigned m_alignmentCharacter;
	std::vector<WPXTabStop> m_tabStops;
	bool m_isTabPositionRelative;

	std::set <const WPXSubDocument *> m_subDocuments;

	bool m_inSubDocument;
	bool m_isNote;
	WPXSubDocumentType m_subDocumentType;

private:
	WPXContentParsingState(const WPXContentParsingState &);
	WPXContentParsingState &operator=(const WPXContentParsingState &);
};

class WPXContentListener : public WPXListener
{
protected:
	WPXContentListener(std::list<WPXPageSpan> &pageList, librevenge::RVNGTextInterface *documentInterface);
	~WPXContentListener() override;

	void startDocument();
	void startSubDocument();
	void endDocument();
	void endSubDocument();
	void handleSubDocument(const WPXSubDocument *subDocument, WPXSubDocumentType subDocumentType, WPXTableList tableList, unsigned nextTableIndice);
	void insertBreak(const unsigned char breakType);
	void lineSpacingChange(const double lineSpacing);
	void justificationChange(const unsigned char justification);

	std::unique_ptr<WPXContentParsingState> m_ps; // parse state
	librevenge::RVNGTextInterface *m_documentInterface;
	librevenge::RVNGPropertyList m_metaData;

	virtual void _handleSubDocument(const WPXSubDocument *subDocument, WPXSubDocumentType subDocumentType, WPXTableList tableList, unsigned nextTableIndice) = 0;
	virtual void _flushText() = 0;
	virtual void _changeList() = 0;

	void _openSection();
	void _closeSection();

	void _openPageSpan();
	void _closePageSpan();

	void _appendParagraphProperties(librevenge::RVNGPropertyList &propList, const bool isListElement=false);
	void _getTabStops(librevenge::RVNGPropertyListVector &tabStops);
	void _appendJustification(librevenge::RVNGPropertyList &propList, int justification);
	void _resetParagraphState(const bool isListElement=false);
	virtual void _openParagraph();
	void _closeParagraph();

	void _openListElement();
	void _closeListElement();

	void _openSpan();
	void _closeSpan();

	void _openTable();
	void _closeTable();
	void _openTableRow(const double height, const bool isMinimumHeight, const bool isHeaderRow);
	void _closeTableRow();
	void _openTableCell(const unsigned char colSpan, const unsigned char rowSpan, const unsigned char borderBits,
	                    const RGBSColor *cellFgColor, const RGBSColor *cellBgColor,
	                    const RGBSColor *cellBorderColor,
	                    const WPXVerticalAlignment cellVerticalAlignment);
	void _closeTableCell();

	double _movePositionToFirstColumn(double position);

	double _getNextTabStop() const;
	double _getPreviousTabStop() const;

	void _insertText(const librevenge::RVNGString &textBuffer);

	void _insertBreakIfNecessary(librevenge::RVNGPropertyList &propList);

	void _insertPageNumberParagraph(WPXPageNumberPosition position, WPXNumberingType type, librevenge::RVNGString fontName, double fontSize);

	unsigned _mapNonUnicodeCharacter(unsigned character);

private:
	WPXContentListener(const WPXContentListener &);
	WPXContentListener &operator=(const WPXContentListener &);
	librevenge::RVNGString _colorToString(const RGBSColor *color);
	librevenge::RVNGString _mergeColorsToString(const RGBSColor *fgColor, const RGBSColor *bgColor);
	unsigned _mapSymbolFontCharacter(unsigned character);
	unsigned _mapDingbatsFontCharacter(unsigned character);
};

#endif /* WPXCONTENTLISTENER_H */
/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */
