/*
    libodsstream is a library to read and write ODS documents as streams
    Copyright (C) 2013  Olivier Langella <Olivier.Langella@moulon.inra.fr>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <algorithm>
#include <QDebug>
#include "contentxml.h"
#include "metaxml.h"
#include "../../odsexception.h"

QString ContentXml::_xsdNamespaceURI = "http://www.w3.org/2001/XMLSchema";
QString ContentXml::_xsiNamespaceURI =
  "http://www.w3.org/2001/XMLSchema-instance";

ContentXml::ContentXml(QuaZip *p_quaZip, SettingsXml *p_settings_xml)
  : _outFile(p_quaZip)
{
  QuaZipNewInfo info("content.xml");
  _outFile.open(QIODevice::WriteOnly, info);
  _p_writer = new QXmlStreamWriter(&_outFile);
  _p_writer->setAutoFormatting(true);
  this->WriteHeader();
  _p_settings_xml = p_settings_xml;
}

ContentXml::~ContentXml()
{
}

void
ContentXml::WriteHeader()
{
  _tableRowStarted = false;
  _tableStarted    = false;
  _p_writer->writeStartDocument("1.0");
  /*
   * <office:document-content office:version="1.2"
   * xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0"
   * xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
   * xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0"
   * xmlns:db="urn:oasis:names:tc:opendocument:xmlns:database:1.0"
   * xmlns:dc="http://purl.org/dc/elements/1.1/"
   * xmlns:dom="http://www.w3.org/2001/xml-events"
   * xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
   * xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
   * xmlns:fo
   * ="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
   * xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0"
   * xmlns:grddl="http://www.w3.org/2003/g/data-view#"
   * xmlns:math="http://www.w3.org/1998/Math/MathML"
   * xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0"
   * xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"
   * xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2"
   * xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
   * xmlns:ooo="http://openoffice.org/2004/office"
   * xmlns:oooc="http://openoffice.org/2004/calc"
   * xmlns:ooow="http://openoffice.org/2004/writer" xmlns:presentation=
   * "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
   * xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0"
   * xmlns:
   * smil="urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0"
   * xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
   * xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
   * xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
   * xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
   * xmlns:xforms="http://www.w3.org/2002/xforms"
   * xmlns:xhtml="http://www.w3.org/1999/xhtml"
   * xmlns:xlink="http://www.w3.org/1999/xlink"
   * xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   * xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   */

  MetaXml::getNamespaceURI("office");

  auto it = MetaXml::_hash_namespace_uri.begin();
  while(it != MetaXml::_hash_namespace_uri.end())
    {
      _p_writer->writeNamespace(it->second, it->first);
      it++;
    }
  // xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  _p_writer->writeNamespace(_xsdNamespaceURI, "xsd");

  // xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  _p_writer->writeNamespace(_xsiNamespaceURI, "xsi");

  _p_writer->writeStartElement(MetaXml::getNamespaceURI("office"),
                               "document-content");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("office"), "version", "1.2");


  // <office:scripts/>
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("office"), "scripts");
  _p_writer->writeEndElement();

  // <office:font-face-decls>
  writeFontFaceDecls();
}


void
ContentXml::writeFontFaceDecls()
{
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("office"),
                               "font-face-decls");
  /**
   * <style:font-face style:font-family-generic="swiss"
   * style:font-pitch="variable" style:name="Arial"
   * svg:font-family="Arial"/>
   * */
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("style"), "font-face");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("style"), "font-family-generic", "swiss");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("style"), "font-pitch", "variable");
  _p_writer->writeAttribute(MetaXml::getNamespaceURI("style"), "name", "Arial");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("svg"), "font-family", "Arial");
  _p_writer->writeEndElement();

  _p_writer->writeEndElement();
}


void
ContentXml::startSpreadsheet()
{

  if(_spreadsheet_started)
    return;
  _spreadsheet_started = true;

  // <office:body>
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("office"), "body");
  // <office:spreadsheet>
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("office"),
                               "spreadsheet");
}

void
ContentXml::writeAutomaticStyles()
{

  if(_automatic_styles_writed)
    return;
  _automatic_styles_writed = true;

  /*
   * <office:automatic-styles>
   *
   *
   *
   *
   *
   *
   *
   *
   *
   *
   *
   *
   * </office:automatic-styles>
   */
  /*
   *
   * <office:automatic-styles>
   */
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("office"),
                               "automatic-styles");
  /*
   * <style:style style:name="ce1" style:family="table-cell"
   * style:parent-style-name="Default" style:data-style-name="N0" />
   */
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("style"), "style");
  _p_writer->writeAttribute(MetaXml::getNamespaceURI("style"), "name", "ce1");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("style"), "family", "table-cell");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("style"), "parent-style-name", "Default");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("style"), "data-style-name", "N0");
  _p_writer->writeEndElement();

  /*
   * <style:style style:name="ce2" style:family="table-cell"
   * style:parent-style-name="Default" style:data-style-name="N36" />
   */
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("style"), "style");
  _p_writer->writeAttribute(MetaXml::getNamespaceURI("style"), "name", "ce2");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("style"), "family", "table-cell");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("style"), "parent-style-name", "Default");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("style"), "data-style-name", "N36");
  _p_writer->writeEndElement();
  // <style:style style:name="co1" style:family="table-column">
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("style"), "style");
  _p_writer->writeAttribute(MetaXml::getNamespaceURI("style"), "name", "co1");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("style"), "family", "table-column");

  /*
   * <style:table-column-properties fo:break-before="auto"
   * style:column-width="2.27541666666667cm" />
   */
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("style"),
                               "table-column-properties");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("fo"), "break-before", "auto");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("style"), "column-width", "2.27541666666667cm");
  _p_writer->writeEndElement();
  // </style:style>
  _p_writer->writeEndElement();

  // <style:style style:name="co2" style:family="table-column">
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("style"), "style");
  _p_writer->writeAttribute(MetaXml::getNamespaceURI("style"), "name", "co2");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("style"), "family", "table-column");
  // <style:table-column-properties
  // fo:break-before="auto" style:column-width="2.11666666666667cm" />
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("style"),
                               "table-column-properties");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("fo"), "break-before", "auto");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("style"), "column-width", "2.27541666666667cm");
  _p_writer->writeEndElement();
  // </style:style>
  _p_writer->writeEndElement();
  // <style:style style:name="ro1" style:family="table-row">
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("style"), "style");
  _p_writer->writeAttribute(MetaXml::getNamespaceURI("style"), "name", "ro1");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("style"), "family", "table-row");

  // <style:table-row-properties
  // style:row-height="15pt" style:use-optimal-row-height="true"
  // fo:break-before="auto" />
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("style"),
                               "table-row-properties");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("style"), "row-height", "15pt");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("style"), "use-optimal-row-height", "true");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("fo"), "break-before", "auto");
  _p_writer->writeEndElement();
  // </style:style>
  _p_writer->writeEndElement();

  // <style:style style:name="ta1" style:family="table"
  // style:master-page-name="mp1">
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("style"), "style");
  _p_writer->writeAttribute(MetaXml::getNamespaceURI("style"), "name", "ta1");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("style"), "family", "table");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("style"), "master-page-name", "mp1");
  // <style:table-properties table:display="true"
  // style:writing-mode="lr-tb" />
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("style"),
                               "table-properties");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("table"), "display", "true");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("style"), "writing-mode", "lr-tb");
  _p_writer->writeEndElement();

  // </style:style>
  _p_writer->writeEndElement();

  /*
   *
  <style:style style:name="ce3" style:family="table-cell"
  style:parent-style-name="Default" style:data-style-name="N0">
  <style:table-cell-properties fo:background-color="#ffff00"/>
  <style:text-properties fo:color="#800000"/>
  </style:style>
  */

  for(unsigned int i = 0; i < _style2write.size(); i++)
    {
      _p_writer->writeStartElement(MetaXml::getNamespaceURI("style"), "style");
      _p_writer->writeAttribute(MetaXml::getNamespaceURI("style"),
                                "name",
                                _style_ref_list[i]->_ref_str);
      _p_writer->writeAttribute(
        MetaXml::getNamespaceURI("style"), "family", "table-cell");
      _p_writer->writeAttribute(
        MetaXml::getNamespaceURI("style"), "parent-style-name", "Default");
      _p_writer->writeAttribute(
        MetaXml::getNamespaceURI("style"), "data-style-name", "N0");

      if(_style2write[i]._background_color.isValid())
        {
          _p_writer->writeStartElement(MetaXml::getNamespaceURI("style"),
                                       "table-cell-properties");
          _p_writer->writeAttribute(MetaXml::getNamespaceURI("fo"),
                                    "background-color",
                                    _style2write[i]._background_color.name());
          _p_writer->writeEndElement();
        }
      if(_style2write[i]._text_color.isValid())
        {
          _p_writer->writeStartElement(MetaXml::getNamespaceURI("style"),
                                       "text-properties");
          _p_writer->writeAttribute(MetaXml::getNamespaceURI("fo"),
                                    "color",
                                    _style2write[i]._text_color.name());
          _p_writer->writeEndElement();
        }

      _p_writer->writeEndElement();
    }
  _p_writer->writeEndElement();
}

void
ContentXml::close()
{

  writeAutomaticStyles();
  startSpreadsheet();

  writeEndTable();
  _p_writer->writeEndDocument();

  this->_outFile.close();

  delete _p_writer;
}

std::vector<OdsColorScale>
ContentXml::getOdsColorScaleListBySheetName(const QString &sheet_name)
{
  std::vector<OdsColorScale> color_scale_list;

  for(OdsColorScale color_scale : _color_scale_list)
    {
      if(color_scale.isInSheet(sheet_name))
        {
          color_scale_list.push_back(color_scale);
        }
    }

  return color_scale_list;
}

void
ContentXml::writeEndTable()
{
  if(_tableRowStarted)
    {
      _p_writer->writeEndElement();
    }

  if(_tableStarted)
    {
      std::vector<OdsColorScale> sheet_color_scale_list =
        getOdsColorScaleListBySheetName(_current_sheet_name);
      if(sheet_color_scale_list.size() > 0)
        {
          /*
              <calcext:conditional-formats>
                  <calcext:conditional-format
          calcext:target-range-address="classeur.A5:classeur.E6" >
                      <calcext:color-scale>
                          <calcext:color-scale-entry calcext:value="0"
          calcext:type="minimum" calcext:color="#0000ff"/>
                          <calcext:color-scale-entry calcext:value="50"
          calcext:type="percentile" calcext:color="#ffffff"/>
                          <calcext:color-scale-entry calcext:value="0"
          calcext:type="maximum" calcext:color="#ff0000"/>
                      </calcext:color-scale>
                  </calcext:conditional-format>
              </calcext:conditional-formats>
          </table:table>*/
          //<calcext:conditional-formats>
          _p_writer->writeStartElement(MetaXml::getNamespaceURI("calcext"),
                                       "conditional-formats");

          for(OdsColorScale color_scale : sheet_color_scale_list)
            {
              color_scale.writeConditionalFormat(_p_writer);
            }

          //</calcext:conditional-formats>
          _p_writer->writeEndElement();
        }


      _p_writer->writeEndElement();
    }

  _tableStarted    = false;
  _tableRowStarted = false;
  _row_pos         = 0;
  _col_pos         = 0;
}


void
ContentXml::writeSheet(const QString &tableName)
{

  _p_settings_xml->addSheetName(tableName);
  writeAutomaticStyles();
  startSpreadsheet();

  writeEndTable();
  _current_sheet_name = tableName;
  _tableStarted       = true;

  /*
   * <table:table table:name="Feuille1" table:style-name="ta1"
   * table:print="false">
   */
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("table"), "table");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("table"), "name", tableName);
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("table"), "style-name", "ta1");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("table"), "print", "false");

  /*
   * <table:table-column table:style-name="co1"
   * table:default-cell-style-name="ce1" />
   */
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("table"),
                               "table-column");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("table"), "style-name", "co1");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("table"), "default-cell-style-name", "ce1");
  _p_writer->writeEndElement();

  _row_pos = 0;
  _col_pos = 0;
}

void
ContentXml::writeLine()
{

  writeAutomaticStyles();
  startSpreadsheet();

  if(_tableStarted == false)
    {
      writeSheet();
    }
  if(_tableRowStarted)
    {
      // close current row
      _p_writer->writeStartElement(MetaXml::getNamespaceURI("table"),
                                   "table-cell");
      _p_writer->writeEndElement();
      _p_writer->writeEndElement();
    }
  _row_pos++;
  _col_pos         = 0;
  _tableRowStarted = true;
  /*
   * <table:table-row table:style-name="ro1">
   */
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("table"), "table-row");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("table"), "style-name", "ro1");
}

void
ContentXml::writeSheet()
{
  writeSheet(_p_settings_xml->getDefaultSheetName());
}

void
ContentXml::writeCell(double value, const QString &annotation)
{
  writeCellFloat(QString::number(value, 'e', 20),
                 QString::number(value, 'g', 20),
                 annotation);
}

void
ContentXml::writeCell(std::size_t value, const QString &annotation)
{
  QString representation(QString::number(value));
  writeCellFloat(representation, representation, annotation);
}

void
ContentXml::writeCell(int value, const QString &annotation)
{
  QString representation(QString::number(value));
  writeCellFloat(representation, representation, annotation);
}


void
ContentXml::writeCellPercentage(double value, const QString &annotation)
{
  QString representation(QString("%1 %").arg(value * 100));
  writeAutomaticStyles();
  startSpreadsheet();

  if(_tableRowStarted == false)
    {
      writeLine();
    }
  /*
   * <table:table-cell office:value-type="percentage" office:value="0.5"
   * calcext:value-type="percentage">
   */
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("table"), "table-cell");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("office"), "value-type", "percentage");
  _p_writer->writeAttribute(MetaXml::getNamespaceURI("office"),
                            "value",
                            QString::number(value, 'f', 5));
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("calcext"), "value-type", "percentage");
  // table:style-name="ce1"
  if(_current_style_ref != nullptr)
    {
      _p_writer->writeAttribute(MetaXml::getNamespaceURI("table"),
                                "style-name",
                                _current_style_ref->_ref_str);
    }
  else
    {
      _p_writer->writeAttribute(
        MetaXml::getNamespaceURI("table"), "style-name", "ce1");
    }
  writeAnnotation(annotation);
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("text"), "p");
  //<text:p>50,00 %</text:p></table:table-cell>
  _p_writer->writeCharacters(representation);
  _p_writer->writeEndElement();

  /*
   * </table:table-cell>
   */
  _p_writer->writeEndElement();
  /*
   * </table:table-row> </table:table> </office:spreadsheet>
   * </office:body>
   */
  _col_pos++;
}


void
ContentXml::writeCellFloat(const QString &value,
                           const QString &representation,
                           const QString &annotation)
{

  writeAutomaticStyles();
  startSpreadsheet();

  if(_tableRowStarted == false)
    {
      writeLine();
    }
  /*
   * <table:table-cell office:value-type="float" office:value="45">
   */
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("table"), "table-cell");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("office"), "value-type", "float");
  _p_writer->writeAttribute(MetaXml::getNamespaceURI("office"), "value", value);
  // table:style-name="ce1"
  if(_current_style_ref != nullptr)
    {
      _p_writer->writeAttribute(MetaXml::getNamespaceURI("table"),
                                "style-name",
                                _current_style_ref->_ref_str);
    }
  else
    {
      _p_writer->writeAttribute(
        MetaXml::getNamespaceURI("table"), "style-name", "ce1");
    }
  /*
   * <text:p>45</text:p>
   */
  writeAnnotation(annotation);
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("text"), "p");
  _p_writer->writeCharacters(representation);
  _p_writer->writeEndElement();

  /*
   * </table:table-cell>
   */
  _p_writer->writeEndElement();
  /*
   * </table:table-row> </table:table> </office:spreadsheet>
   * </office:body>
   */
  _col_pos++;
}


void
ContentXml::writeEmptyCell(const QString &annotation)
{

  writeAutomaticStyles();
  startSpreadsheet();

  if(_tableRowStarted == false)
    {
      writeLine();
    }
  /*
   * <table:table-cell office:value-type="string">
   */
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("table"), "table-cell");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("office"), "value-type", "string");
  // table:style-name="ce1"
  if(_current_style_ref != nullptr)
    {
      _p_writer->writeAttribute(MetaXml::getNamespaceURI("table"),
                                "style-name",
                                _current_style_ref->_ref_str);
    }
  else
    {
      _p_writer->writeAttribute(
        MetaXml::getNamespaceURI("table"), "style-name", "ce1");
    }
  /*
   * <text:p>45</text:p>
   */
  writeAnnotation(annotation);
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("text"), "p");
  _p_writer->writeCharacters("");
  _p_writer->writeEndElement();

  _p_writer->writeEndElement();
  _col_pos++;
}


void
ContentXml::writeAnnotation(const QString &annotation)
{
  //<office:annotation draw:style-name="gr1" draw:text-style-name="P2"
  // svg:width="28.99mm" svg:height="10.69mm" svg:x="96.48mm" svg:y="0mm"
  // draw:caption-point-x="-6.1mm"
  // draw:caption-point-y="10.68mm"><dc:date>2016-08-19T00:00:00</dc:date>
  //<text:p text:style-name="P1">Ceci est un commentaire</text:p>
  //</office:annotation>
  if(!annotation.isEmpty())
    {
      _p_writer->writeStartElement(MetaXml::getNamespaceURI("office"),
                                   "annotation");
      _p_writer->writeStartElement(MetaXml::getNamespaceURI("text"), "p");
      _p_writer->writeCharacters(annotation);
      _p_writer->writeEndElement();

      _p_writer->writeEndElement(); // annotation
    }
}

void
ContentXml::writeCell(const QString &value, const QString &annotation)
{

  writeAutomaticStyles();
  startSpreadsheet();

  if(_tableRowStarted == false)
    {
      writeLine();
    }
  /*
   * <table:table-cell office:value-type="string">
   */
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("table"), "table-cell");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("office"), "value-type", "string");
  // table:style-name="ce1"


  if(_current_style_ref != nullptr)
    {
      _p_writer->writeAttribute(MetaXml::getNamespaceURI("table"),
                                "style-name",
                                _current_style_ref->_ref_str);
    }
  else
    {
      _p_writer->writeAttribute(
        MetaXml::getNamespaceURI("table"), "style-name", "ce1");
    }
  /*
   * <text:p>45</text:p>
   */
  writeAnnotation(annotation);
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("text"), "p");
  _p_writer->writeCharacters(value);
  _p_writer->writeEndElement();

  _p_writer->writeEndElement();
  _col_pos++;
}

void
ContentXml::writeCell(const QDateTime &cal, const QString &annotation)
{

  writeAutomaticStyles();
  startSpreadsheet();


  if(_tableRowStarted == false)
    {
      writeLine();
    }
  // cal..setTimezone(0);
  /*
   * <table:table-cell office:value-type="date"
   * office:date-value="2011-07-16"
   * ><text:p>16/07/11</text:p></table:table-cell>
   */
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("table"), "table-cell");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("office"), "value-type", "date");
  _p_writer->writeAttribute(MetaXml::getNamespaceURI("office"),
                            "date-value",
                            cal.toString("yyyy-MM-dd'T'HH:mm:ss"));
  // table:style-name="ce1"
  if(_current_style_ref != nullptr)
    {
      _p_writer->writeAttribute(MetaXml::getNamespaceURI("table"),
                                "style-name",
                                _current_style_ref->_ref_str);
    }
  else
    {
      _p_writer->writeAttribute(
        MetaXml::getNamespaceURI("table"), "style-name", "ce2");
    }
  /*
   * <text:p>45</text:p>
   */
  writeAnnotation(annotation);
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("text"), "p");
  // writer.writeCharacters(cal.getDay()+"/"+cal.getMonth()+"/11");
  _p_writer->writeCharacters(cal.toString("dd/MM/yyyy"));
  _p_writer->writeEndElement();

  /*
   * </table:table-cell>
   */
  _p_writer->writeEndElement();
  /*
   * </table:table-row> </table:table> </office:spreadsheet>
   * </office:body>
   */
  _col_pos++;
}

void
ContentXml::writeCell(const QDate &date, const QString &annotation)
{

  writeCell(date.startOfDay(), annotation);
}

void
ContentXml::writeCell(bool value, const QString &annotation)
{

  writeAutomaticStyles();
  startSpreadsheet();

  if(_tableRowStarted == false)
    {
      writeLine();
    }
  /*
   * <table:table-cell office:value-type="date"
   * office:date-value="2011-07-16"
   * ><text:p>16/07/11</text:p></table:table-cell>
   */
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("table"), "table-cell");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("office"), "value-type", "boolean");
  if(_current_style_ref != nullptr)
    {
      _p_writer->writeAttribute(MetaXml::getNamespaceURI("table"),
                                "style-name",
                                _current_style_ref->_ref_str);
    }
  else
    {
      _p_writer->writeAttribute(
        MetaXml::getNamespaceURI("table"), "style-name", "ce1");
    }

  QString bvalue = "false";
  if(value)
    {
      bvalue = "true";
    }
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("office"), "boolean-value", bvalue);
  writeAnnotation(annotation);
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("text"), "p");
  _p_writer->writeCharacters(bvalue);
  _p_writer->writeEndElement();

  /*
   * </table:table-cell>
   */
  _p_writer->writeEndElement();
  _col_pos++;
}

// public void writeCell(Duration duration) throws XMLStreamException {
//     if (duration == null) {
//         this.writeCell("");
//     } else {
//         if (this.tableRowStarted == false) {
//             this.writeLine();
//         }
//         /*
//          * <table:table-cell office:value-type="date"
//          * office:date-value="2011-07-16"
//          * ><text:p>16/07/11</text:p></table:table-cell>
//          */
//         writer.writeStartElement("table", "table-cell",
//         hashNamespaceURI.get("table"));
//         writer.writeAttribute("office", hashNamespaceURI.get("office"),
//         "value-type", "time");
//         writer.writeAttribute("office", hashNamespaceURI.get("office"),
//         "time-value", duration.toString());
//         writer.writeAttribute("table", hashNamespaceURI.get("table"),
//         "style-name", "ce2");
//         /*
//          * <text:p>12:00:00</text:p>
//          */
//         writer.writeStartElement("text", "p", hashNamespaceURI.get("text"));
//         writer.writeCharacters(duration.getHours() + ":"
//         + duration.getMinutes() + ":" + duration.getSeconds());
//         writer.writeEndElement();
//
//         /*
//          * </table:table-cell>
//          */
//         writer.writeEndElement();
//         /*
//          * </table:table-row> </table:table> </office:spreadsheet>
//          * </office:body>
//          */
//     }
// }

void
ContentXml::writeCell(const QUrl &theUri,
                      const QString &description,
                      const QString &annotation)
{
  // <table:table-cell office:value-type="string"><text:p><text:a
  // xlink:href="http://linuxfr.org/">linuxfr</text:a></text:p></table:table-cell>

  //<table:table-cell office:value-type="string" calcext:value-type="string">
  //<text:p>
  //<text:a xlink:href="http://pappso.inra.fr/" xlink:type="simple">
  // ceci est un lien</text:a></text:p>
  //</table:table-cell>

  //<table:table-cell table:style-name="ce1" office:value-type="string">
  //<text:p>
  //<text:a xlink:href="http://linuxfr.org/" xlink:type="simple">
  // linux fr</text:a></text:p>
  //</table:table-cell>
  writeAutomaticStyles();
  startSpreadsheet();

  if(_tableRowStarted == false)
    {
      writeLine();
    }
  /*
   * <table:table-cell office:value-type="string">
   */
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("table"), "table-cell");

  if(_current_style_ref != nullptr)
    {
      _p_writer->writeAttribute(MetaXml::getNamespaceURI("table"),
                                "style-name",
                                _current_style_ref->_ref_str);
    }
  else
    {
      _p_writer->writeAttribute(
        MetaXml::getNamespaceURI("table"), "style-name", "ce1");
    }

  //_p_writer->writeAttribute(MetaXml::getNamespaceURI("office"),"value-type",
  //"string");
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("calcext"), "value-type", "string");

  writeAnnotation(annotation);

  _p_writer->setAutoFormatting(false);
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("text"), "p");
  _p_writer->writeStartElement(MetaXml::getNamespaceURI("text"), "a");
  // xlink:href="http://linuxfr.org/"
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("xlink"), "href", theUri.toString());
  _p_writer->writeAttribute(
    MetaXml::getNamespaceURI("xlink"), "type", "simple");
  _p_writer->writeCharacters(description);
  _p_writer->writeEndElement();
  _p_writer->writeEndElement();

  _p_writer->setAutoFormatting(true);

  _p_writer->writeEndElement();

  _col_pos++;
}

OdsTableCellStyleRef
ContentXml::getTableCellStyleRef(const OdsTableCellStyle &style)
{
  if(_automatic_styles_writed)
    {
      throw OdsException(
        QObject::tr("unable to get style reference : styles already written"));
    }

  _style2write.push_back(style);

  OdsTableCellStyleRef _p_ref =
    new OdsTableCellStyleRefInternal(_style2write.size());
  _style_ref_list.push_back(_p_ref);
  return _p_ref;
}


void
ContentXml::setTableCellStyleRef(OdsTableCellStyleRef style_ref)
{
  if(style_ref != nullptr)
    {
      auto it = find(_style_ref_list.begin(), _style_ref_list.end(), style_ref);
      if(it == _style_ref_list.end())
        {
          throw OdsException(QObject::tr(
            "this style reference was not registered in this document"));
        }
    }

  _current_style_ref = style_ref;
}


void
ContentXml::addColorScale(const OdsColorScale &ods_color_scale)
{
  _color_scale_list.push_back(ods_color_scale);
}


QString
ContentXml::getCellCoordinate()
{
  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__ << " "
           << _current_sheet_name << " " << _col_pos << " " << _row_pos;

  int size_col = _col_pos - 1; // supports more than 26 columns
  QString ods_column_coord;
  while(size_col >= 0)
    {
      ods_column_coord.prepend((char)(((size_col) % 26) + 65));
      size_col = (size_col / 26);
      if(size_col == 0)
        break;
      size_col--;
    }

  return QString("%1.%2%3")
    .arg(_current_sheet_name)
    .arg(ods_column_coord)
    .arg(_row_pos);
}
