/* -*- 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."
 */

#include <math.h>
#include "FilterInternal.hxx"
#include "Frame.hxx"
#include "DocumentElement.hxx"

#ifdef _MSC_VER
#include <minmax.h>
#endif

#include <string.h>

namespace librvngabw
{
Frame::Frame(const librevenge::RVNGPropertyList &xPropList, int xId) :
	m_isOpened(false), m_propList(xPropList), m_xId(xId), m_frameType(""), m_imageName(""), m_anchor(Frame::A_Page), m_pageNumber(0), m_content()
{
	if (!xPropList["text:anchor-type"])
	{
		if (xPropList["table:end-cell-address"])
			m_anchor=A_Cell;
		return;
	}
	auto anchor=xPropList["text:anchor-type"]->getStr();
	if (anchor=="page")
	{
		m_anchor=A_Page;
		if (xPropList["text:anchor-page-number"])
			m_pageNumber=xPropList["text:anchor-page-number"]->getInt();
	}
	else if (anchor=="paragraph")
		m_anchor=A_Paragraph;
	else if (anchor=="section")
		m_anchor=A_Section;
	else if (anchor=="frame")
		m_anchor=A_Frame;
	else if (anchor=="char")
		m_anchor=A_Char;
	else if (anchor=="as-char")
		m_anchor=xPropList["style:vertical-rel"] && xPropList["style:vertical-rel"]->getStr()=="baseline" ?
		         A_CharBaseLine : A_Char;
	else
	{
		RVNGABW_DEBUG_MSG(("Frame::Frame: unknown frame position=%s\n", anchor.cstr()));
	}
}

Frame::~Frame()
{
}

void Frame::addDimensionsTo(librevenge::RVNGPropertyList &propList) const
{
	if (m_propList["svg:height"])
		propList.insert("height", m_propList["svg:height"]->getStr());
	else if (m_propList["fo:min-height"])
		propList.insert("height", m_propList["fo:min-height"]->getStr());
	if (m_propList["svg:width"])
		propList.insert("width", m_propList["svg:width"]->getStr());
	else if (m_propList["fo:min-width"])
		propList.insert("width", m_propList["fo:min-width"]->getStr());
}

void Frame::write(DocumentElementVector &storage, const librevenge::RVNGPropertyList &propExtra) const
{
	if (isEmpty())
	{
		RVNGABW_DEBUG_MSG(("Frame::Frame: do not find any content\n"));
		return;
	}
	librevenge::RVNGPropertyList propList;
	propList.insert("xid", m_xId);
	librevenge::RVNGPropertyList propPropList(propExtra);

	if (!m_frameType.empty())
		propPropList.insert("frame-type", m_frameType);
	if (!m_imageName.empty())
	{
		propList.insert("strux-image-dataid", m_imageName);
		const_cast<Frame *>(this)->m_imageName.clear();
	}
	librevenge::RVNGString xPos("0in"), yPos("0in");
	if (m_propList["svg:x"] && m_propList["svg:x"]->getDouble()>=0)
		xPos=m_propList["svg:x"]->getStr();
	if (m_propList["svg:y"] && m_propList["svg:y"]->getDouble()>=0)
		yPos=m_propList["svg:y"]->getStr();

	if (!xPos.empty()) propPropList.insert("xpos", xPos);
	if (!yPos.empty()) propPropList.insert("ypos", yPos);
	switch (m_anchor)
	{
	case A_Page:
		propPropList.insert("position-to", "page-above-text");
		if (m_pageNumber>0)
			propPropList.insert("frame-pref-page", m_pageNumber-1);
		if (!xPos.empty()) propPropList.insert("frame-page-xpos", xPos);
		if (!yPos.empty()) propPropList.insert("frame-page-ypos", yPos);
		break;
	case A_Frame:
	case A_Section:
		propPropList.insert("position-to", "column-above-text");
		propPropList.insert("frame-pref-column", 0);
		if (!xPos.empty()) propPropList.insert("frame-col-xpos", xPos);
		if (!yPos.empty()) propPropList.insert("frame-col-ypos", yPos);
		break;
	case A_Cell:
		break;
	case A_Paragraph:
	case A_Char:
	case A_CharBaseLine:
	default:
		propPropList.insert("position-to", "block-above-text");
		break;
	}
	// the dimension
	if (m_propList["svg:height"])
		propPropList.insert("frame-height", m_propList["svg:height"]->getStr());
	else if (m_propList["fo:min-height"])
		propPropList.insert("frame-height", m_propList["fo:min-height"]->getStr());
	if (m_propList["svg:width"])
		propPropList.insert("frame-width", m_propList["svg:width"]->getStr());
	else if (m_propList["fo:min-width"])
		propPropList.insert("frame-width", m_propList["fo:min-width"]->getStr());
	// now look the wrapping (checkme)
	if (m_propList["style:wrap"])
	{
		librevenge::RVNGString wrap=m_propList["style:wrap"]->getStr();
		if (wrap=="left")
			propPropList.insert("wrap-mode", "wrapped-to-left");
		else if (wrap=="right")
			propPropList.insert("wrap-mode", "wrapped-to-right");
		else if (wrap=="parallel")
			propPropList.insert("wrap-mode", "wrapped-both");
		else if (wrap=="dynamic")
		{
			if (m_propList["style:run-through"])
			{
				if (m_propList["style:run-through"]->getStr()=="foreground")
					propPropList.insert("wrap-mode", "above-text");
				else if (m_propList["style:run-through"]->getStr()=="background")
					propPropList.insert("wrap-mode", "below-text");
				else
					propPropList.insert("wrap-mode", "wrapped-both");
			}
			else
				propPropList.insert("wrap-mode", "wrapped-both");
		}
		// note: what does wrapped-topbot ? Can we use it ?
	}
	if (!propPropList.empty())
	{
		librevenge::RVNGPropertyListVector propPropVector;
		propPropVector.append(propPropList);
		propList.insert("props", propPropVector);
	}

	storage.push_back(std::make_shared<TagOpenElement>("frame", propList));
	librvngabw::spliceOrigDest(const_cast<DocumentElementVector &>(m_content), storage);
	storage.push_back(std::make_shared<TagCloseElement>("frame"));
}

FrameManager::FrameManager() : m_frameList(), m_openedFrameStack()
{
	for (bool &i : m_notSentFrameByAnchor)
		i=false;
}

FrameManager::~FrameManager()
{
}

void FrameManager::clean()
{
	m_frameList.clear();
	while (!m_openedFrameStack.empty()) m_openedFrameStack.pop();
}

std::shared_ptr<Frame> FrameManager::openFrame(const librevenge::RVNGPropertyList &xPropList, int &xId)
{
	std::shared_ptr<Frame> frame(new Frame(xPropList, ++xId));
	frame->setOpened(true);
	m_frameList.push_back(frame);
	m_openedFrameStack.push(frame);
	return frame;
}

bool FrameManager::closeFrame()
{
	if (m_openedFrameStack.empty())
	{
		RVNGABW_DEBUG_MSG(("FrameManager::closeFrame: oops, no frame are opened\n"));
		return false;
	}
	std::shared_ptr<Frame> frame=m_openedFrameStack.top();
	if (frame)
	{
		frame->setOpened(false);
		if (!frame->isEmpty())
			m_notSentFrameByAnchor[frame->getAnchorToUse()]=true;
	}
	m_openedFrameStack.pop();
	return true;
}

void FrameManager::writeContents(DocumentElementVector &storage, Frame::AnchorToUse anchor)
{
	if (anchor>=Frame::U_NumberAnchorToUse)
	{
		RVNGABW_DEBUG_MSG(("FrameManager::writeContents: the anchor is bad\n"));
		return;
	}
	if (!m_notSentFrameByAnchor[anchor])
		return;

	librevenge::RVNGPropertyList extra;
	std::vector<std::shared_ptr<Frame> > newList;
	for (auto &i : m_frameList)
	{
		if (!i)
			continue;
		if (i->isOpened() || i->getAnchorToUse()!=anchor)
		{
			newList.push_back(i);
			continue;
		}
		if (i->isEmpty())
			continue;
		i->write(storage, extra);
	}
	m_notSentFrameByAnchor[anchor]=false;
	if (newList.size() != m_frameList.size())
		m_frameList=newList;
}
}
/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */
