/* -*- 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-2003 William Lachance (wrlach@gmail.com)
 *
 * 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."
 */
#include "FilterInternal.hxx"
#include "PageSpan.hxx"
#include "DocumentElement.hxx"

#include <string.h>

namespace librvngabw
{
//
// page span's storage
//

void PageSpan::Storage::appendContent(librevenge::RVNGString const &type,
                                      librevenge::RVNGPropertyList const &pageSpanList,
                                      librevenge::RVNGPropertyList const &extra,
                                      DocumentElementVector &storage) const
{
	librevenge::RVNGPropertyList propList(extra);
	propList.insert("xid", m_xId);
	librevenge::RVNGPropertyList propPropList;
	if (!type.empty())
	{
		propList.insert("type", type);
		propList.insert("id", m_id);
	}
	else
	{
		// main page section
		double value=0;
		double margin=0;
		if (pageSpanList["fo:margin-left"] && getInchValue(*pageSpanList["fo:margin-left"], value))
			margin += value;
		if (m_sectionPropList["fo:start-indent"] && getInchValue(*m_sectionPropList["fo:start-indent"], value))
			margin += value;
		if (margin>0)
			propPropList.insert("page-margin-left", margin, librevenge::RVNG_INCH);

		margin=0;
		if (pageSpanList["fo:margin-right"] && getInchValue(*pageSpanList["fo:margin-right"], value))
			margin += value;
		if (m_sectionPropList["fo:end-indent"] && getInchValue(*m_sectionPropList["fo:end-indent"], value))
			margin += value;
		if (margin>0)
			propPropList.insert("page-margin-right", margin, librevenge::RVNG_INCH);

		if (pageSpanList["fo:margin-top"] && getInchValue(*pageSpanList["fo:margin-top"], value) && value>0)
			propPropList.insert("page-margin-top", value, librevenge::RVNG_INCH);
		if (pageSpanList["fo:margin-bottom"] && getInchValue(*pageSpanList["fo:margin-bottom"], value) && value>0)
			propPropList.insert("page-margin-bottom", value, librevenge::RVNG_INCH);
	}
	const librevenge::RVNGPropertyListVector *columns = m_sectionPropList.child("style:columns");
	if (columns && columns->count()>1)
	{
		propPropList.insert("columns", (int) columns->count());
		propPropList.insert("section-max-column-height", 0, librevenge::RVNG_INCH);
		propPropList.insert("column-line", "off");
		propPropList.insert("section-space-after", 0.1, librevenge::RVNG_INCH);
	}
	if (!propPropList.empty())
	{
		librevenge::RVNGPropertyListVector propPropVector;
		propPropVector.append(propPropList);
		propList.insert("props", propPropVector);
	}

	storage.push_back(std::make_shared<TagOpenElement>("section", propList));
	// will empty m_content, which is ok
	librvngabw::spliceOrigDest(const_cast<DocumentElementVector &>(m_content), storage);
	storage.push_back(std::make_shared<TagCloseElement>("section"));
}

//
// page span
//
PageSpan::PageSpan(PageSpanManager &manager, librevenge::RVNGPropertyList const &xPropList, bool isFirstPage) :
	m_pageSpanManager(manager),
	m_pagePropList(xPropList),
	m_storageList(), m_currentStorage(nullptr),
	m_isFirstPage(isFirstPage), m_hasSentMainSection(false),
	m_headerFooterToSent()
{
	m_storageList.resize(C_NumStorageTypes);
}

PageSpan::~PageSpan()
{
	resetAllContents();
}

void PageSpan::resetContent(StorageType type)
{
	if (type==C_NumStorageTypes)
	{
		RVNGABW_DEBUG_MSG(("PageSpan::resetContent: can not be called with numStorageTypes\n"));
		return;
	}
	m_storageList[type].reset();
}

void PageSpan::resetAllContents()
{
	for (size_t i=0; i<C_NumStorageTypes; ++i)
		m_storageList[i].reset();
	m_currentStorage=nullptr;
}

DocumentElementVector *PageSpan::openStorage(StorageType type, int &xId, bool createIfNeeded)
{
	if (type==C_NumStorageTypes)
	{
		RVNGABW_DEBUG_MSG(("PageSpan::openStorage: can not be called with numStorageTypes\n"));
		return nullptr;
	}
	if (createIfNeeded && !m_storageList[type])
		m_storageList[type].reset(new Storage(type==C_MainContent ? -1 : m_pageSpanManager.getNewSectionId(), ++xId));
	m_currentStorage=m_storageList[type].get();
	return m_currentStorage ? &m_currentStorage->m_content : nullptr;
}

void PageSpan::updateSectionPropList(librevenge::RVNGPropertyList const &sectionPropList)
{
	if (!m_currentStorage)
	{
		RVNGABW_DEBUG_MSG(("PageSpan::updateSectionPropList: can not be called with no storage\n"));
		return;
	}
	m_currentStorage->m_sectionPropList=sectionPropList;
}

void PageSpan::writePageSize(DocumentElementVector &storage) const
{
	librevenge::RVNGPropertyList propList;
	propList.insert("pagetype", "Custom"); // TODO: try to recognize Letter, A4, ...
	propList.insert("units", "in");
	propList.insert("page-scale", 1.0, librevenge::RVNG_GENERIC);
	double height=0, width=0;
	if (m_pagePropList["fo:page-height"])
		getInchValue(*m_pagePropList["fo:page-height"], height);
	if (m_pagePropList["fo:page-width"])
		getInchValue(*m_pagePropList["fo:page-width"], width);
	// default=letter
	if (width<=0) width=8.5;
	if (height<=0) height=11;
	propList.insert("width", width, librevenge::RVNG_GENERIC);
	propList.insert("height", height, librevenge::RVNG_GENERIC);
	propList.insert("orientation", width>height ? "landscape" : "portrait");
	storage.push_back(std::make_shared<TagOpenElement>("pagesize", propList));
	storage.push_back(std::make_shared<TagCloseElement>("pagesize"));
}

librevenge::RVNGString PageSpan::getTypeName(StorageType type)
{
	static char const *wh[]= { "header", "header-first", "header-even", "header-last",
	                           "footer", "footer-first", "footer-even", "footer-last",
	                           "",
	                           "" // bad
	                         };
	return wh[type];
}

void PageSpan::appendAuxiliaryContents(DocumentElementVector &storage)
{
	if (m_storageList[C_MainContent] && (!m_hasSentMainSection || !m_storageList[C_MainContent]->m_content.empty()))
	{
		RVNGABW_DEBUG_MSG(("PageSpan::appendMainContent: oops find a main contain\n"));
		appendMainContent(storage);
	}
	librevenge::RVNGPropertyList extra;
	for (size_t i=0; i< C_NumStorageTypes; ++i)
	{
		if (i==C_MainContent || !m_storageList[i])
			continue;
		if (m_headerFooterToSent.find(m_storageList[i]->m_id)==m_headerFooterToSent.end())
		{
			static bool first=true;
			if (first)
			{
				first=false;
				RVNGABW_DEBUG_MSG(("PageSpan::appendMainContent: the headers/footers which do not correspond to first section are ignored\n"));
			}
			continue;
		}
		m_storageList[i]->appendContent(getTypeName(StorageType(i)), m_pagePropList, extra, storage);
	}
}

void PageSpan::appendMainContent(DocumentElementVector &storage)
{
	if (!m_storageList[C_MainContent])
	{
		RVNGABW_DEBUG_MSG(("PageSpan::appendMainContent: can not find the main content\n"));
		return;
	}
	librevenge::RVNGPropertyList extra;
	if (m_isFirstPage && !m_hasSentMainSection)
	{
		for (size_t i=0; i< C_NumStorageTypes; ++i)
		{
			if (i==C_MainContent || !m_storageList[i]) continue;
			librevenge::RVNGString type=getTypeName(StorageType(i));
			if (type.empty())
			{
				RVNGABW_DEBUG_MSG(("PageSpan::appendMainContent: can not find a storage type\n"));
				continue;
			}
			m_headerFooterToSent.insert(m_storageList[i]->m_id);
			extra.insert(type.cstr(), m_storageList[i]->m_id);
		}
	}
	m_storageList[C_MainContent]->appendContent("", m_pagePropList, extra, storage);
	m_storageList[C_MainContent].reset();
	m_currentStorage=nullptr;
	m_hasSentMainSection=true;
}

//
// the page manager
//

void PageSpanManager::clean()
{
	m_pageSpanList.clear();
}

PageSpan *PageSpanManager::add(const librevenge::RVNGPropertyList &xPropList)
{
	std::shared_ptr<PageSpan> page(new PageSpan(*this, xPropList, m_pageSpanList.empty()));
	m_pageSpanList.push_back(page);

	return page.get();
}

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