/**
 * \file odsstream/writer/structure/settings.cpp
 * \date 20/04/2018
 * \author Olivier Langella
 * \brief XML file to store ODS document settings
 */

/*******************************************************************************
 * Copyright (c) 2013 Olivier Langella <Olivier.Langella@u-psud.fr>.
 *
 * This file is part of the libodsstream library.
 *
 *    libodsstream is a library to read and write ODS documents as streams
 *    Copyright (C) 2013  Olivier Langella <Olivier.Langella@u-psud.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/>.
 *
 * Contributors:
 *     Olivier Langella <Olivier.Langella@u-psud.fr> - initial API and
 *implementation
 ******************************************************************************/

#include "settingsxml.h"
#include "metaxml.h"

#include <quazipfile.h>
#include <QDebug>
#include "../../odsexception.h"


SettingsXml::SettingsXml()
{
}
SettingsXml::~SettingsXml()
{
}
void
SettingsXml::setCurrentOdsTableSettings(const OdsTableSettings &settings_in)
{
  if(_sheet_list.size() == 0)
    {
      throw OdsException(
        QObject::tr("unable to set current sheet settings : no sheet started"));
    }
  OdsTableSettings settings(settings_in);
  settings.setSheetName(_sheet_list.back());
  auto it = std::find_if(_table_settings_list.begin(),
                         _table_settings_list.end(),
                         [&settings](OdsTableSettings settings_other) -> bool {
                           return settings.getSheetName() ==
                                  settings_other.getSheetName();
                         });
  if(it != _table_settings_list.end())
    {
      *it = settings;
    }
  else
    {
      _table_settings_list.push_back(settings);
    }

  qDebug() << __FILE__ << " " << __FUNCTION__ << " "
           << settings.getValue("VerticalSplitPosition");
}
const QString
SettingsXml::getDefaultSheetName() const
{
  return QString("Sheet%1").arg(_sheet_list.size() + 1);
}

void
SettingsXml::addSheetName(const QString &name)
{
  if(name.isEmpty())
    {
      throw OdsException(QObject::tr("Error in %1 %2 : sheet name is empty")
                           .arg(__FILE__)
                           .arg(__FUNCTION__));
    }

  if(std::find(_sheet_list.begin(), _sheet_list.end(), name) !=
     _sheet_list.end())
    {
      throw OdsException(
        QObject::tr(
          "Error in %1 %2 :\n the sheet named %3 already exists in the "
          "document. Sheet names has to be unique in the same document.")
          .arg(__FILE__)
          .arg(__FUNCTION__)
          .arg(name));
    }
  // throw OdsException(QObject::tr("addSheetName"));
  _sheet_list.push_back(name);
  // qDebug() << QObject::tr("addSheetName") << _sheet_list.size();
}

void
SettingsXml::write(QuaZip *p_quazip)
{
  if(_sheet_list.size() == 0)
    {
      throw OdsException(QObject::tr("_sheet_list is empty"));
    }
  QuaZipFile out_file(p_quazip);
  QuaZipNewInfo info("settings.xml");
  out_file.open(QIODevice::WriteOnly, info);
  QXmlStreamWriter writer(&out_file);
  writer.setAutoFormatting(true);


  writer.writeStartDocument("1.0");

  // <?xml version="1.0" encoding="UTF-8"?>
  //<office:document-settings
  //xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
  //xmlns:xlink="http://www.w3.org/1999/xlink"
  //xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0"
  //xmlns:ooo="http://openoffice.org/2004/office" office:version="1.2">
  writer.writeNamespace(MetaXml::getNamespaceURI("office"), "office");
  writer.writeNamespace(MetaXml::getNamespaceURI("xlink"), "xlink");
  writer.writeNamespace(MetaXml::getNamespaceURI("config"), "config");
  writer.writeNamespace(MetaXml::getNamespaceURI("ooo"), "ooo");
  writer.writeStartElement(MetaXml::getNamespaceURI("office"),
                           "document-settings");
  writer.writeAttribute(MetaXml::getNamespaceURI("office"), "version", "1.2");

  //<office:settings>
  writer.writeStartElement(MetaXml::getNamespaceURI("office"), "settings");


  //<config:config-item-set config:name="ooo:view-settings">
  writer.writeStartElement(MetaXml::getNamespaceURI("config"),
                           "config-item-set");
  writer.writeAttribute(
    MetaXml::getNamespaceURI("config"), "name", "ooo:view-settings");
  //<config:config-item config:name="VisibleAreaTop" config:type="int">0
  writeConfigItem(&writer, "VisibleAreaTop", "int", "0");
  //<config:config-item config:name="VisibleAreaLeft" config:type="int">0
  writeConfigItem(&writer, "VisibleAreaLeft", "int", "0");
  // <config:config-item config:name="VisibleAreaWidth" config:type="int">18062
  writeConfigItem(&writer, "VisibleAreaWidth", "int", "18062");
  //<config:config-item config:name="VisibleAreaHeight" config:type="int">5418
  writeConfigItem(&writer, "VisibleAreaHeight", "int", "5418");

  //<config:config-item-map-indexed config:name="Views">
  writer.writeStartElement(MetaXml::getNamespaceURI("config"),
                           "config-item-map-indexed");
  writer.writeAttribute(MetaXml::getNamespaceURI("config"), "name", "Views");

  //  <config:config-item-map-entry>
  writer.writeStartElement(MetaXml::getNamespaceURI("config"),
                           "config-item-map-entry");
  //<config:config-item config:name="ViewId" config:type="string">view1
  writeConfigItem(&writer, "ViewId", "string", "view1");

  //  <config:config-item-map-named config:name="Tables">
  writer.writeStartElement(MetaXml::getNamespaceURI("config"),
                           "config-item-map-named");
  writer.writeAttribute(MetaXml::getNamespaceURI("config"), "name", "Tables");

  for(const QString &sheet_name : _sheet_list)
    {
      writeSheetSettings(&writer, sheet_name);
    }

  //</config:config-item-map-named>
  writer.writeEndElement();

  //<config:config-item config:name="ActiveTable" config:type="string">Feuille1
  writeConfigItem(&writer, "ActiveTable", "string", _sheet_list[0]);

  //<config:config-item config:name="HorizontalScrollbarWidth"
  //config:type="int">1857
  writeConfigItem(&writer, "HorizontalScrollbarWidth", "int", "1857");

  //<config:config-item config:name="ZoomType" config:type="short">0
  writeConfigItem(&writer, "ZoomType", "short", "0");

  //<config:config-item config:name="ZoomValue"
  //config:type="int">100</config:config-item>
  writeConfigItem(&writer, "ZoomValue", "int", "100");

  //<config:config-item config:name="PageViewZoomValue"
  //config:type="int">60</config:config-item>
  writeConfigItem(&writer, "PageViewZoomValue", "int", "60");

  //<config:config-item config:name="ShowPageBreakPreview"
  //config:type="boolean">false</config:config-item>
  writeConfigItem(&writer, "ShowPageBreakPreview", "boolean", "false");

  //<config:config-item config:name="ShowZeroValues"
  //config:type="boolean">true</config:config-item>
  writeConfigItem(&writer, "ShowZeroValues", "boolean", "true");
  //<config:config-item config:name="ShowNotes"
  //config:type="boolean">true</config:config-item>
  writeConfigItem(&writer, "ShowNotes", "boolean", "true");
  //<config:config-item config:name="ShowGrid"
  //config:type="boolean">true</config:config-item>
  writeConfigItem(&writer, "ShowGrid", "boolean", "true");
  //<config:config-item config:name="GridColor"
  //config:type="long">12632256</config:config-item>
  writeConfigItem(&writer, "GridColor", "long", "12632256");
  // <config:config-item config:name="ShowPageBreaks"
  // config:type="boolean">true</config:config-item>
  writeConfigItem(&writer, "ShowPageBreaks", "boolean", "true");
  // <config:config-item config:name="HasColumnRowHeaders"
  // config:type="boolean">true</config:config-item>
  writeConfigItem(&writer, "HasColumnRowHeaders", "boolean", "true");
  // <config:config-item config:name="HasSheetTabs"
  // config:type="boolean">true</config:config-item>
  writeConfigItem(&writer, "HasSheetTabs", "boolean", "true");
  // <config:config-item config:name="IsOutlineSymbolsSet"
  // config:type="boolean">true</config:config-item>
  writeConfigItem(&writer, "IsOutlineSymbolsSet", "boolean", "true");
  //<config:config-item config:name="IsValueHighlightingEnabled"
  //config:type="boolean">false</config:config-item>
  writeConfigItem(&writer, "IsValueHighlightingEnabled", "boolean", "false");
  //<config:config-item config:name="IsSnapToRaster"
  //config:type="boolean">false</config:config-item>
  writeConfigItem(&writer, "IsSnapToRaster", "boolean", "false");
  // <config:config-item config:name="RasterIsVisible"
  // config:type="boolean">false</config:config-item>
  writeConfigItem(&writer, "RasterIsVisible", "boolean", "false");
  //<config:config-item config:name="RasterResolutionX"
  //config:type="int">1000</config:config-item>
  writeConfigItem(&writer, "RasterResolutionX", "int", "1000");
  //<config:config-item config:name="RasterResolutionY"
  //config:type="int">1000</config:config-item>
  writeConfigItem(&writer, "RasterResolutionY", "int", "1000");
  // <config:config-item config:name="RasterSubdivisionX"
  // config:type="int">1</config:config-item>
  writeConfigItem(&writer, "RasterSubdivisionX", "int", "1");
  //<config:config-item config:name="RasterSubdivisionY"
  //config:type="int">1</config:config-item>
  writeConfigItem(&writer, "RasterSubdivisionY", "int", "1");
  //<config:config-item config:name="IsRasterAxisSynchronized"
  //config:type="boolean">true</config:config-item>
  writeConfigItem(&writer, "IsRasterAxisSynchronized", "boolean", "true");

  //</config:config-item-map-entry>
  writer.writeEndElement();

  // </config:config-item-map-indexed>
  writer.writeEndElement();


  writeConfigurationSettings(&writer);

  //</config:config-item-set>
  writer.writeEndElement();


  //</office:settings>
  writer.writeEndElement();

  //</office:document-settings>
  writer.writeEndElement();

  writer.writeEndDocument();
  out_file.close();
}

void
SettingsXml::writeSheetSettings(QXmlStreamWriter *p_writer,
                                const QString &sheet_name)
{

  const OdsTableSettings *p_table_settings = &_default_table_settings;

  auto it = std::find_if(_table_settings_list.begin(),
                         _table_settings_list.end(),
                         [&sheet_name](OdsTableSettings settings) -> bool {
                           return sheet_name == settings.getSheetName();
                         });
  if(it != _table_settings_list.end())
    {
      p_table_settings = &(*it);
    }
  // <config:config-item-map-entry config:name="Feuille1">
  p_writer->writeStartElement(MetaXml::getNamespaceURI("config"),
                              "config-item-map-entry");
  p_writer->writeAttribute(
    MetaXml::getNamespaceURI("config"), "name", sheet_name);

  //<config:config-item config:name="CursorPositionX" config:type="int">3
  writeConfigItem(p_writer, "CursorPositionX", "int", "0");

  //<config:config-item config:name="CursorPositionY" config:type="int">0
  writeConfigItem(p_writer, "CursorPositionY", "int", "0");

  //<config:config-item config:name="HorizontalSplitMode" config:type="short">0
  writeConfigItem(p_writer,
                  "HorizontalSplitMode",
                  "short",
                  p_table_settings->getValue("HorizontalSplitMode"));

  //<config:config-item config:name="VerticalSplitMode" config:type="short">2
  writeConfigItem(p_writer,
                  "VerticalSplitMode",
                  "short",
                  p_table_settings->getValue("VerticalSplitMode"));

  //<config:config-item config:name="HorizontalSplitPosition"
  //config:type="int">0
  writeConfigItem(p_writer,
                  "HorizontalSplitPosition",
                  "int",
                  p_table_settings->getValue("HorizontalSplitPosition"));

  //<config:config-item config:name="VerticalSplitPosition" config:type="int">1
  writeConfigItem(p_writer,
                  "VerticalSplitPosition",
                  "int",
                  p_table_settings->getValue("VerticalSplitPosition"));

  //<config:config-item config:name="ActiveSplitRange" config:type="short">0
  writeConfigItem(p_writer, "ActiveSplitRange", "short", "2");


  //<config:config-item config:name="PositionLeft" config:type="int">0
  writeConfigItem(p_writer, "PositionLeft", "int", "0");
  //<config:config-item config:name="PositionRight" config:type="int">0
  writeConfigItem(p_writer, "PositionRight", "int", "0");

  //<config:config-item config:name="PositionTop" config:type="int">0
  writeConfigItem(p_writer, "PositionTop", "int", "0");

  //<config:config-item config:name="PositionBottom" config:type="int">1
  writeConfigItem(p_writer, "PositionBottom", "int", "1");
  //<config:config-item config:name="ZoomType" config:type="short">0
  writeConfigItem(p_writer, "ZoomType", "short", "0");
  //<config:config-item config:name="ZoomValue" config:type="int">100
  writeConfigItem(p_writer, "ZoomValue", "int", "100");
  //<config:config-item config:name="PageViewZoomValue" config:type="int">60
  writeConfigItem(p_writer, "PageViewZoomValue", "int", "60");
  //<config:config-item config:name="ShowGrid" config:type="boolean">true
  writeConfigItem(p_writer, "ShowGrid", "boolean", "true");
  //</config:config-item-map-entry>
  p_writer->writeEndElement();
}


void
SettingsXml::writeConfigItem(QXmlStreamWriter *p_writer,
                             const QString &name,
                             const QString &type,
                             const QString &value)
{
  //<config:config-item config:name="CursorPositionX" config:type="int">3
  p_writer->writeStartElement(MetaXml::getNamespaceURI("config"),
                              "config-item");
  p_writer->writeAttribute(MetaXml::getNamespaceURI("config"), "name", name);
  p_writer->writeAttribute(MetaXml::getNamespaceURI("config"), "type", type);
  if(!value.isEmpty())
    p_writer->writeCharacters(value);
  //</config:config-item>
  p_writer->writeEndElement();
}

void
SettingsXml::writeConfigurationSettings(QXmlStreamWriter *p_writer)
{

  // <config:config-item-set config:name="ooo:configuration-settings">
  p_writer->writeStartElement(MetaXml::getNamespaceURI("config"),
                              "config-item-set");
  p_writer->writeAttribute(
    MetaXml::getNamespaceURI("config"), "name", "ooo:configuration-settings");

  // <config:config-item config:name="IsDocumentShared"
  // config:type="boolean">false
  writeConfigItem(p_writer, "IsDocumentShared", "boolean", "false");

  //<config:config-item config:name="LoadReadonly"
  //config:type="boolean">false</config:config-item>
  writeConfigItem(p_writer, "LoadReadonly", "boolean", "false");
  //<config:config-item config:name="AllowPrintJobCancel"
  //config:type="boolean">true</config:config-item>
  writeConfigItem(p_writer, "AllowPrintJobCancel", "boolean", "true");
  //<config:config-item config:name="UpdateFromTemplate"
  //config:type="boolean">true</config:config-item>
  writeConfigItem(p_writer, "UpdateFromTemplate", "boolean", "true");
  //<config:config-item config:name="IsKernAsianPunctuation"
  //config:type="boolean">false</config:config-item>
  writeConfigItem(p_writer, "IsKernAsianPunctuation", "boolean", "false");
  //<config:config-item config:name="EmbedFonts"
  //config:type="boolean">false</config:config-item>
  writeConfigItem(p_writer, "EmbedFonts", "boolean", "false");
  //<config:config-item config:name="IsSnapToRaster"
  //config:type="boolean">false</config:config-item>
  writeConfigItem(p_writer, "IsSnapToRaster", "boolean", "false");
  //<config:config-item config:name="RasterResolutionX"
  //config:type="int">1000</config:config-item>
  writeConfigItem(p_writer, "RasterResolutionX", "int", "1000");
  //<config:config-item config:name="RasterResolutionY"
  //config:type="int">1000</config:config-item>
  writeConfigItem(p_writer, "RasterResolutionY", "int", "1000");
  ///< config:config-item config:name="HasSheetTabs"
  ///< config:type="boolean">true</config:config-item>
  writeConfigItem(p_writer, "HasSheetTabs", "boolean", "true");
  //<config:config-item config:name="IsRasterAxisSynchronized"
  //config:type="boolean">true</config:config-item>
  writeConfigItem(p_writer, "IsRasterAxisSynchronized", "boolean", "true");
  //<config:config-item config:name="ShowPageBreaks"
  //config:type="boolean">true</config:config-item>
  writeConfigItem(p_writer, "ShowPageBreaks", "boolean", "true");
  //<config:config-item config:name="ShowGrid"
  //config:type="boolean">true</config:config-item>
  writeConfigItem(p_writer, "ShowGrid", "boolean", "true");
  //<config:config-item config:name="ShowNotes"
  //config:type="boolean">true</config:config-item>
  writeConfigItem(p_writer, "ShowNotes", "boolean", "true");
  //<config:config-item config:name="IsOutlineSymbolsSet"
  //config:type="boolean">true</config:config-item>
  writeConfigItem(p_writer, "IsOutlineSymbolsSet", "boolean", "true");
  //<config:config-item config:name="ShowZeroValues"
  //config:type="boolean">true</config:config-item>
  writeConfigItem(p_writer, "ShowZeroValues", "boolean", "true");
  //<config:config-item config:name="SaveVersionOnClose"
  //config:type="boolean">false</config:config-item>
  writeConfigItem(p_writer, "SaveVersionOnClose", "boolean", "false");
  //<config:config-item config:name="GridColor"
  //config:type="long">12632256</config:config-item>
  writeConfigItem(p_writer, "GridColor", "long", "12632256");
  //<config:config-item config:name="RasterIsVisible"
  //config:type="boolean">false</config:config-item>
  writeConfigItem(p_writer, "RasterIsVisible", "boolean", "false");
  //<config:config-item config:name="PrinterName" config:type="string"/>
  writeConfigItem(p_writer, "PrinterName", "string", "");
  //<config:config-item config:name="LinkUpdateMode"
  //config:type="short">3</config:config-item>
  writeConfigItem(p_writer, "LinkUpdateMode", "short", "3");
  //<config:config-item config:name="RasterSubdivisionX"
  //config:type="int">1</config:config-item>
  writeConfigItem(p_writer, "RasterSubdivisionX", "int", "1");
  //<config:config-item config:name="HasColumnRowHeaders"
  //config:type="boolean">true</config:config-item>
  writeConfigItem(p_writer, "HasColumnRowHeaders", "boolean", "true");
  //<config:config-item config:name="RasterSubdivisionY"
  //config:type="int">1</config:config-item>
  writeConfigItem(p_writer, "RasterSubdivisionY", "int", "1");
  //<config:config-item config:name="AutoCalculate"
  //config:type="boolean">true</config:config-item>
  writeConfigItem(p_writer, "AutoCalculate", "boolean", "true");
  //<config:config-item config:name="PrinterSetup" config:type="base64Binary"/>
  writeConfigItem(p_writer, "PrinterSetup", "base64Binary", "");
  //<config:config-item config:name="ApplyUserData"
  //config:type="boolean">true</config:config-item>
  writeConfigItem(p_writer, "ApplyUserData", "boolean", "true");
  //<config:config-item config:name="CharacterCompressionType"
  //config:type="short">0</config:config-item>
  writeConfigItem(p_writer, "CharacterCompressionType", "short", "0");


  //</config:config-item-set>
  p_writer->writeEndElement();
}
