/***************************************************************************
**
**  This file is part of QGpCoreMath.
**
**  This library 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 2.1 of the License, or (at your option) any later version.
**
**  This file 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 library; if not, write to the Free Software
**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2011-03-02
**  Copyright: 2011-2019
**    Marc Wathelet (ISTerre, Grenoble, France)
**
***************************************************************************/

#include "GoogleEarthKML.h"

namespace QGpCoreMath {

  /*!
    \class GoogleEarthKML GoogleEarthKML.h
    \brief Brief description of class still missing

    Full description of class still missing
  */

  const QString GoogleEarthKML::xmlGoogleEarthKMLTag="kml";
  const QString GoogleEarthKML::Document::xmlDocumentTag="Document";
  const QString GoogleEarthKML::Folder::xmlFolderTag="Folder";
  const QString GoogleEarthKML::Placemark::xmlPlacemarkTag="Placemark";
  const QString GoogleEarthKML::Point::xmlPointTag="Point";

  /*!
    Description of constructor still missing
  */
  GoogleEarthKML::GoogleEarthKML()
    : XMLClass()
  {
    TRACE;
  }

  bool GoogleEarthKML::save(const QString& fileName)
  {
    TRACE;
    XMLHeader hdr(this);
    QFile f(fileName);
    if(!f.open(QIODevice::WriteOnly)) {
      Message::warning(MSG_ID, tr("Saving coordinates as KML ..."),
                       tr("Error while writing to file %1").arg(fileName), Message::cancel());
      return false;
    }
    QTextStream s(&f);
    s << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
    s << hdr.xml_saveString(false);
    return true;
  }

  void GoogleEarthKML::xml_attributes(XML_ATTRIBUTES_ARGS) const
  {
    TRACE;
    Q_UNUSED(context)
    static const QString keys[]={"xmlns", "xmlns:gx", "xmlns:kml", "xmlns:atom"};
    attributes.add(keys[0], "http://www.opengis.net/kml/2.2");
    attributes.add(keys[1], "http://www.google.com/kml/ext/2.2");
    attributes.add(keys[2], "http://www.opengis.net/kml/2.2");
    attributes.add(keys[3], "http://www.w3.org/2005/Atom");
  }

  void GoogleEarthKML::xml_writeChildren(XML_WRITECHILDREN_ARGS) const
  {
    TRACE;
    _document.xml_save(s, context);
  }

  XMLMember GoogleEarthKML::xml_member(XML_MEMBER_ARGS)
  {
    TRACE;
    Q_UNUSED(attributes)
    Q_UNUSED(context)
    if(tag=="Document") {
      return XMLMember(&_document);
    } else return XMLMember(XMLMember::Unknown);
  }

  /*!
    \class GoogleEarthKML::Document GoogleEarthKML.h
    \brief Brief description of class still missing

    Full description of class still missing
  */

  GoogleEarthKML::Document::Document()
    : XMLClass()
  {
    TRACE;
  }

  QList<NamedPoint> GoogleEarthKML::Document::points() const
  {
    TRACE;
    QList<NamedPoint> list;
    _root.collectPoints(list);
    return list;
  }

  void GoogleEarthKML::Document::xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const
  {
    TRACE;
    Q_UNUSED(context)
    writeProperty(s, "name", _name);
    // TODO: complete support for style customization
    s << s.indent() << "<StyleMap id=\"msn_ylw-pushpin\">\n";
    s.incrementIndent();
    s << s.indent() << "<Pair>\n";
    s.incrementIndent();
    s << s.indent() << "<key>normal</key>\n"
      << s.indent() << "<styleUrl>#sn_ylw-pushpin</styleUrl>\n";
    s.decrementIndent();
    s << s.indent() << "</Pair>\n"
      << s.indent() << "<Pair>\n";
    s.incrementIndent();
    s << s.indent() << "<key>normal</key>\n"
      << s.indent() << "<styleUrl>#sh_ylw-pushpin</styleUrl>\n";
    s.decrementIndent();
    s << s.indent() << "</Pair>\n";
    s.decrementIndent();
    s << s.indent() << "</StyleMap>\n"
      << s.indent() << "<Style id=\"sn_ylw-pushpin\">\n";
    s.incrementIndent();
    s << s.indent() << "<IconStyle>\n";
    s.incrementIndent();
    s << s.indent() << "<scale>1.1</scale>\n"
      << s.indent() << "<Icon>\n";
    s.incrementIndent();
    s << s.indent() << "<href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href>\n";
    s.decrementIndent();
    s << s.indent() << "</Icon>\n"
      << s.indent() << "<hotSpot x=\"20\" y=\"2\" xunits=\"pixels\" yunits=\"pixels\"/>\n";
    s.decrementIndent();
    s << s.indent() << "</IconStyle>\n";
    s.decrementIndent();
    s << s.indent() << "</Style>\n"
      << s.indent() << "<Style id=\"sh_ylw-pushpin\">\n";
    s.incrementIndent();
    s << s.indent() << "<IconStyle>\n";
    s.incrementIndent();
    s << s.indent() << "<scale>1.3</scale>\n"
      << s.indent() << "<Icon>\n";
    s.incrementIndent();
    s << s.indent() << "<href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href>\n";
    s.decrementIndent();
    s << s.indent() << "</Icon>\n"
      << s.indent() << "<hotSpot x=\"20\" y=\"2\" xunits=\"pixels\" yunits=\"pixels\"/>\n";
    s.decrementIndent();
    s << s.indent() << "</IconStyle>\n";
    s.decrementIndent();
    s << s.indent() << "</Style>\n";
  }

  void GoogleEarthKML::Document::xml_writeChildren(XML_WRITECHILDREN_ARGS) const
  {
    TRACE;
    _root.xml_save(s, context);
  }

  XMLMember GoogleEarthKML::Document::xml_member(XML_MEMBER_ARGS)
  {
    TRACE;
    Q_UNUSED(attributes)
    Q_UNUSED(context)
    if(tag=="Placemark") {
      Placemark * p=new Placemark;
      _root.addPlacemark(p);
      return XMLMember(p);
    } else if(tag=="Folder") {
      return XMLMember(&_root);
    } else if(tag=="name") return XMLMember(0);
    else if(tag=="StyleMap" || tag=="Style") {
      return XMLMember(XMLMember::Skip);
    } else return XMLMember(XMLMember::Unknown);
  }

  bool GoogleEarthKML::Document::xml_setProperty(XML_SETPROPERTY_ARGS)
  {
    TRACE;
    Q_UNUSED(attributes)
    Q_UNUSED(context)
    Q_UNUSED(tag)
    switch (memberID) {
    case 0:
      _name=content.toString();
      return true;
    default:
      return false;
    }
  }

  /*!
    \class GoogleEarthKML::Point GoogleEarthKML.h
    \brief Brief description of class still missing

    Full description of class still missing
  */

  GoogleEarthKML::Point::Point()
  {
    TRACE;
  }

  /*!
    Overload to avoid writting "folder" from TreeItem
  */
  void GoogleEarthKML::Point::xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const
  {
    TRACE;
    Q_UNUSED(context)
    writeProperty(s, "coordinates", _coordinates.toString(20).replace(" ", ","));
  }

  XMLMember GoogleEarthKML::Point::xml_member(XML_MEMBER_ARGS)
  {
    TRACE;
    Q_UNUSED(attributes)
    Q_UNUSED(context)
    if(tag=="coordinates") return XMLMember(0);
    else return XMLMember(XMLMember::Unknown);
  }

  bool GoogleEarthKML::Point::xml_setProperty(XML_SETPROPERTY_ARGS)
  {
    TRACE;
    Q_UNUSED(attributes)
    Q_UNUSED(context)
    Q_UNUSED(tag)
    switch (memberID) {
    case 0: {
        QString str=content.toString();
        _coordinates.fromString(str.replace(",", " "));
      }
      return true;
    default:
      return false;
    }
  }

  /*!
    \class GoogleEarthKML::Placemark GoogleEarthKML.h
    \brief Brief description of class still missing

    Full description of class still missing
  */

  GoogleEarthKML::Placemark::Placemark()
  {
    TRACE;
  }

  void GoogleEarthKML::Placemark::xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const
  {
    TRACE;
    Q_UNUSED(context)
    writeProperty(s, "name", _name);
    writeProperty(s, "styleUrl", "#msn_ylw-pushpin");
  }

  void GoogleEarthKML::Placemark::xml_writeChildren(XML_WRITECHILDREN_ARGS) const
  {
    TRACE;
    _point.xml_save(s, context);
  }

  XMLMember GoogleEarthKML::Placemark::xml_member(XML_MEMBER_ARGS)
  {
    TRACE;
    Q_UNUSED(attributes)
    Q_UNUSED(context)
    if(tag=="name") return XMLMember(0);
    else if(tag=="Point") {
      return XMLMember(&_point);
    } else if(tag=="LookAt" || tag=="styleUrl") {
      return XMLMember(XMLMember::Skip);
    } else {
      return XMLMember(XMLMember::Unknown);
    }
  }

  bool GoogleEarthKML::Placemark::xml_setProperty(XML_SETPROPERTY_ARGS)
  {
    TRACE;
    Q_UNUSED(attributes)
    Q_UNUSED(context)
    Q_UNUSED(tag)
    switch (memberID) {
    case 0:
      _name=content.toString();
      return true;
    default:
      return false;
    }
  }

  /*!
    \class GoogleEarthKML::Folder GoogleEarthKML.h
    \brief Brief description of class still missing

    Full description of class still missing
  */

  GoogleEarthKML::Folder::~Folder()
  {
    TRACE;
    qDeleteAll(_placemarks);
  }

  void GoogleEarthKML::Folder::clearPlacemarks()
  {
    TRACE;
    qDeleteAll(_placemarks);
    _placemarks.clear();
  }

  void GoogleEarthKML::Folder::collectPoints(QList<NamedPoint>& list) const
  {
    TRACE;
    for(const_iterator it=begin(); it!=end(); ++it) {
      static_cast<Folder *>(*it)->collectPoints(list);
    }
    for(QList<Placemark *>::const_iterator it=_placemarks.begin(); it!=_placemarks.end(); ++it) {
      list.append(NamedPoint((*it)->name(), (*it)->coordinates()));
    }
  }

  void GoogleEarthKML::Folder::xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const
  {
    TRACE;
    Q_UNUSED(context)
    writeProperty(s, "name", _name);
  }

  void GoogleEarthKML::Folder::xml_writeChildren(XML_WRITECHILDREN_ARGS) const
  {
    TRACE;
    for(QList<Placemark *>::const_iterator it=_placemarks.begin(); it!=_placemarks.end(); ++it) {
      (*it)->xml_save(s, context);
    }
    TreeContainer::xml_writeChildren(s, context);
  }

  XMLMember GoogleEarthKML::Folder::xml_member(XML_MEMBER_ARGS)
  {
    TRACE;
    Q_UNUSED(attributes)
    Q_UNUSED(context)
    if(tag=="name") return XMLMember(0);
    else if(tag=="Folder") {
      return XMLMember(new Folder(this));
    } else if(tag=="Placemark") {
      Placemark * p=new Placemark;
      _placemarks.append(p);
      return XMLMember(p);
    } else if(tag=="open") return XMLMember(XMLMember::Skip);
    else return XMLMember(XMLMember::Unknown);
  }

  bool GoogleEarthKML::Folder::xml_setProperty(XML_SETPROPERTY_ARGS)
  {
    TRACE;
    Q_UNUSED(attributes)
    Q_UNUSED(context)
    Q_UNUSED(tag)
    switch (memberID) {
    case 0:
      _name=content.toString();
      return true;
    default:
      return false;
    }
  }

} // namespace QGpCoreMath
