/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
 * This file is part of the libepubgen project.
 *
 * 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/.
 */

#include "EPUBPageElements.h"

namespace libepubgen
{

namespace
{

static void separateTabsAndInsertText(librevenge::RVNGDrawingInterface *iface, const librevenge::RVNGString &text)
{
  if (!iface || text.empty())
    return;
  librevenge::RVNGString tmpText;
  librevenge::RVNGString::Iter i(text);
  for (i.rewind(); i.next();)
  {
    if (*(i()) == '\t')
    {
      if (!tmpText.empty())
      {
        if (iface)
          iface->insertText(tmpText);
        tmpText.clear();
      }

      if (iface)
        iface->insertTab();
    }
    else if (*(i()) == '\n')
    {
      if (!tmpText.empty())
      {
        if (iface)
          iface->insertText(tmpText);
        tmpText.clear();
      }

      if (iface)
        iface->insertLineBreak();
    }
    else
    {
      tmpText.append(i());
    }
  }
  if (iface && !tmpText.empty())
    iface->insertText(tmpText);
}

static void separateSpacesAndInsertText(librevenge::RVNGDrawingInterface *iface, const librevenge::RVNGString &text)
{
  if (!iface)
    return;
  if (text.empty())
  {
    iface->insertText(text);
    return;
  }
  librevenge::RVNGString tmpText;
  int numConsecutiveSpaces = 0;
  librevenge::RVNGString::Iter i(text);
  for (i.rewind(); i.next();)
  {
    if (*(i()) == ' ')
      numConsecutiveSpaces++;
    else
      numConsecutiveSpaces = 0;

    if (numConsecutiveSpaces > 1)
    {
      if (!tmpText.empty())
      {
        separateTabsAndInsertText(iface, tmpText);
        tmpText.clear();
      }

      if (iface)
        iface->insertSpace();
    }
    else
    {
      tmpText.append(i());
    }
  }
  separateTabsAndInsertText(iface, tmpText);
}

} // anonymous namespace

class EPUBPageElement
{
public:
  EPUBPageElement() {}
  virtual ~EPUBPageElement() {}
  virtual void draw(librevenge::RVNGDrawingInterface *painter) = 0;
  virtual EPUBPageElement *clone() = 0;
};

namespace
{

class CDRStyleOutputElement : public EPUBPageElement
{
public:
  CDRStyleOutputElement(const librevenge::RVNGPropertyList &propList);
  virtual ~CDRStyleOutputElement() {}
  virtual void draw(librevenge::RVNGDrawingInterface *painter);
  virtual EPUBPageElement *clone()
  {
    return new CDRStyleOutputElement(m_propList);
  }
private:
  librevenge::RVNGPropertyList m_propList;
};


class CDRPathOutputElement : public EPUBPageElement
{
public:
  CDRPathOutputElement(const librevenge::RVNGPropertyList &propList);
  virtual ~CDRPathOutputElement() {}
  virtual void draw(librevenge::RVNGDrawingInterface *painter);
  virtual EPUBPageElement *clone()
  {
    return new CDRPathOutputElement(m_propList);
  }
private:
  librevenge::RVNGPropertyList m_propList;
};


class CDRGraphicObjectOutputElement : public EPUBPageElement
{
public:
  CDRGraphicObjectOutputElement(const librevenge::RVNGPropertyList &propList);
  virtual ~CDRGraphicObjectOutputElement() {}
  virtual void draw(librevenge::RVNGDrawingInterface *painter);
  virtual EPUBPageElement *clone()
  {
    return new CDRGraphicObjectOutputElement(m_propList);
  }
private:
  librevenge::RVNGPropertyList m_propList;
};


class CDRStartTextObjectOutputElement : public EPUBPageElement
{
public:
  CDRStartTextObjectOutputElement(const librevenge::RVNGPropertyList &propList);
  virtual ~CDRStartTextObjectOutputElement() {}
  virtual void draw(librevenge::RVNGDrawingInterface *painter);
  virtual EPUBPageElement *clone()
  {
    return new CDRStartTextObjectOutputElement(m_propList);
  }
private:
  librevenge::RVNGPropertyList m_propList;
};


class CDROpenParagraphOutputElement : public EPUBPageElement
{
public:
  CDROpenParagraphOutputElement(const librevenge::RVNGPropertyList &propList);
  virtual ~CDROpenParagraphOutputElement() {}
  virtual void draw(librevenge::RVNGDrawingInterface *painter);
  virtual EPUBPageElement *clone()
  {
    return new CDROpenParagraphOutputElement(m_propList);
  }
private:
  librevenge::RVNGPropertyList m_propList;
};


class CDROpenSpanOutputElement : public EPUBPageElement
{
public:
  CDROpenSpanOutputElement(const librevenge::RVNGPropertyList &propList);
  virtual ~CDROpenSpanOutputElement() {}
  virtual void draw(librevenge::RVNGDrawingInterface *painter);
  virtual EPUBPageElement *clone()
  {
    return new CDROpenSpanOutputElement(m_propList);
  }
private:
  librevenge::RVNGPropertyList m_propList;
};


class CDRInsertTextOutputElement : public EPUBPageElement
{
public:
  CDRInsertTextOutputElement(const librevenge::RVNGString &text);
  virtual ~CDRInsertTextOutputElement() {}
  virtual void draw(librevenge::RVNGDrawingInterface *painter);
  virtual EPUBPageElement *clone()
  {
    return new CDRInsertTextOutputElement(m_text);
  }
private:
  librevenge::RVNGString m_text;
};


class CDRCloseSpanOutputElement : public EPUBPageElement
{
public:
  CDRCloseSpanOutputElement();
  virtual ~CDRCloseSpanOutputElement() {}
  virtual void draw(librevenge::RVNGDrawingInterface *painter);
  virtual EPUBPageElement *clone()
  {
    return new CDRCloseSpanOutputElement();
  }
};


class CDRCloseParagraphOutputElement : public EPUBPageElement
{
public:
  CDRCloseParagraphOutputElement();
  virtual ~CDRCloseParagraphOutputElement() {}
  virtual void draw(librevenge::RVNGDrawingInterface *painter);
  virtual EPUBPageElement *clone()
  {
    return new CDRCloseParagraphOutputElement();
  }
};


class CDREndTextObjectOutputElement : public EPUBPageElement
{
public:
  CDREndTextObjectOutputElement();
  virtual ~CDREndTextObjectOutputElement() {}
  virtual void draw(librevenge::RVNGDrawingInterface *painter);
  virtual EPUBPageElement *clone()
  {
    return new CDREndTextObjectOutputElement();
  }
};

class CDRStartLayerOutputElement : public EPUBPageElement
{
public:
  CDRStartLayerOutputElement(const librevenge::RVNGPropertyList &propList);
  virtual ~CDRStartLayerOutputElement() {}
  virtual void draw(librevenge::RVNGDrawingInterface *painter);
  virtual EPUBPageElement *clone()
  {
    return new CDRStartLayerOutputElement(m_propList);
  }
private:
  librevenge::RVNGPropertyList m_propList;
};

class CDREndLayerOutputElement : public EPUBPageElement
{
public:
  CDREndLayerOutputElement();
  virtual ~CDREndLayerOutputElement() {}
  virtual void draw(librevenge::RVNGDrawingInterface *painter);
  virtual EPUBPageElement *clone()
  {
    return new CDREndLayerOutputElement();
  }
};

CDRStyleOutputElement::CDRStyleOutputElement(const librevenge::RVNGPropertyList &propList) :
  m_propList(propList) {}

void CDRStyleOutputElement::draw(librevenge::RVNGDrawingInterface *painter)
{
  if (painter)
    painter->setStyle(m_propList);
}


CDRPathOutputElement::CDRPathOutputElement(const librevenge::RVNGPropertyList &propList) :
  m_propList(propList) {}

void CDRPathOutputElement::draw(librevenge::RVNGDrawingInterface *painter)
{
  if (painter)
    painter->drawPath(m_propList);
}


CDRGraphicObjectOutputElement::CDRGraphicObjectOutputElement(const librevenge::RVNGPropertyList &propList) :
  m_propList(propList) {}

void CDRGraphicObjectOutputElement::draw(librevenge::RVNGDrawingInterface *painter)
{
  if (painter)
    painter->drawGraphicObject(m_propList);
}


CDRStartTextObjectOutputElement::CDRStartTextObjectOutputElement(const librevenge::RVNGPropertyList &propList) :
  m_propList(propList) {}

void CDRStartTextObjectOutputElement::draw(librevenge::RVNGDrawingInterface *painter)
{
  if (painter)
    painter->startTextObject(m_propList);
}

CDROpenSpanOutputElement::CDROpenSpanOutputElement(const librevenge::RVNGPropertyList &propList) :
  m_propList(propList) {}

void CDROpenSpanOutputElement::draw(librevenge::RVNGDrawingInterface *painter)
{
  if (painter)
    painter->openSpan(m_propList);
}


CDROpenParagraphOutputElement::CDROpenParagraphOutputElement(const librevenge::RVNGPropertyList &propList) :
  m_propList(propList) {}

void CDROpenParagraphOutputElement::draw(librevenge::RVNGDrawingInterface *painter)
{
  if (painter)
    painter->openParagraph(m_propList);
}


CDRInsertTextOutputElement::CDRInsertTextOutputElement(const librevenge::RVNGString &text) :
  m_text(text) {}

void CDRInsertTextOutputElement::draw(librevenge::RVNGDrawingInterface *painter)
{
  if (painter)
    separateSpacesAndInsertText(painter, m_text);
}

CDRCloseSpanOutputElement::CDRCloseSpanOutputElement() {}

void CDRCloseSpanOutputElement::draw(librevenge::RVNGDrawingInterface *painter)
{
  if (painter)
    painter->closeSpan();
}


CDRCloseParagraphOutputElement::CDRCloseParagraphOutputElement() {}

void CDRCloseParagraphOutputElement::draw(librevenge::RVNGDrawingInterface *painter)
{
  if (painter)
    painter->closeParagraph();
}


CDREndTextObjectOutputElement::CDREndTextObjectOutputElement() {}

void CDREndTextObjectOutputElement::draw(librevenge::RVNGDrawingInterface *painter)
{
  if (painter)
    painter->endTextObject();
}


CDREndLayerOutputElement::CDREndLayerOutputElement() {}

void CDREndLayerOutputElement::draw(librevenge::RVNGDrawingInterface *painter)
{
  if (painter)
    painter->endLayer();
}


CDRStartLayerOutputElement::CDRStartLayerOutputElement(const librevenge::RVNGPropertyList &propList) :
  m_propList(propList) {}

void CDRStartLayerOutputElement::draw(librevenge::RVNGDrawingInterface *painter)
{
  if (painter)
    painter->startLayer(m_propList);
}

}

EPUBPageElements::EPUBPageElements()
  : m_elements()
{
}

EPUBPageElements::EPUBPageElements(const EPUBPageElements &elementList)
  : m_elements()
{
  std::vector<EPUBPageElement *>::const_iterator iter;
  for (iter = elementList.m_elements.begin(); iter != elementList.m_elements.end(); ++iter)
    m_elements.push_back((*iter)->clone());
}

EPUBPageElements &EPUBPageElements::operator=(const EPUBPageElements &elementList)
{
  for (std::vector<EPUBPageElement *>::iterator iter = m_elements.begin(); iter != m_elements.end(); ++iter)
    delete(*iter);

  m_elements.clear();

  for (std::vector<EPUBPageElement *>::const_iterator cstiter = elementList.m_elements.begin(); cstiter != elementList.m_elements.end(); ++cstiter)
    m_elements.push_back((*cstiter)->clone());

  return *this;
}

EPUBPageElements::~EPUBPageElements()
{
  for (std::vector<EPUBPageElement *>::iterator iter = m_elements.begin(); iter != m_elements.end(); ++iter)
    delete(*iter);
  m_elements.clear();
}

void EPUBPageElements::draw(librevenge::RVNGDrawingInterface *painter) const
{
  for (std::vector<EPUBPageElement *>::const_iterator iter = m_elements.begin(); iter != m_elements.end(); ++iter)
    (*iter)->draw(painter);
}

void EPUBPageElements::addStyle(const librevenge::RVNGPropertyList &propList)
{
  m_elements.push_back(new CDRStyleOutputElement(propList));
}

void EPUBPageElements::addPath(const librevenge::RVNGPropertyList &propList)
{
  m_elements.push_back(new CDRPathOutputElement(propList));
}

void EPUBPageElements::addGraphicObject(const librevenge::RVNGPropertyList &propList)
{
  m_elements.push_back(new CDRGraphicObjectOutputElement(propList));
}

void EPUBPageElements::addStartTextObject(const librevenge::RVNGPropertyList &propList)
{
  m_elements.push_back(new CDRStartTextObjectOutputElement(propList));
}

void EPUBPageElements::addOpenParagraph(const librevenge::RVNGPropertyList &propList)
{
  m_elements.push_back(new CDROpenParagraphOutputElement(propList));
}

void EPUBPageElements::addOpenSpan(const librevenge::RVNGPropertyList &propList)
{
  m_elements.push_back(new CDROpenSpanOutputElement(propList));
}

void EPUBPageElements::addInsertText(const librevenge::RVNGString &text)
{
  m_elements.push_back(new CDRInsertTextOutputElement(text));
}

void EPUBPageElements::addCloseSpan()
{
  m_elements.push_back(new CDRCloseSpanOutputElement());
}

void EPUBPageElements::addCloseParagraph()
{
  m_elements.push_back(new CDRCloseParagraphOutputElement());
}

void EPUBPageElements::addEndTextObject()
{
  m_elements.push_back(new CDREndTextObjectOutputElement());
}

void EPUBPageElements::addStartGroup(const librevenge::RVNGPropertyList &propList)
{
  m_elements.push_back(new CDRStartLayerOutputElement(propList));
}

void EPUBPageElements::addEndGroup()
{
  m_elements.push_back(new CDREndLayerOutputElement());
}

}

/* vim:set shiftwidth=2 softtabstop=2 expandtab: */
