/*
    Access Hiketech XML data files.

    Copyright (C) 2004,2005 Robert Lipe, robertlipe+source@gpsbabel.org

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

 */

#include "defs.h"
#include "src/core/xmlstreamwriter.h"
#include "xmlgeneric.h"
#include <QtCore/QXmlStreamAttributes>
#include <cstdio>

static gbfile* ofd;
static QString ostring;
static gpsbabel::XmlStreamWriter writer(&ostring);

static Waypoint* wpt_tmp;
static route_head* trk_head;

#define MYNAME "hiketech"

static
QVector<arglist_t> hiketech_args = {
};

/* Waypoints */
static xg_callback 	ht_wpt_s;
static xg_callback 	ht_wpt_e;
static xg_callback 	ht_ident;
static xg_callback 	ht_sym;
static xg_callback 	ht_lat;
static xg_callback 	ht_long;
static xg_callback 	ht_alt;

/* Tracks */
static xg_callback	ht_trk_s, ht_trk_e;
static xg_callback	ht_trk_ident;
static xg_callback	ht_trk_pnt_s, ht_trk_pnt_e;
static xg_callback	ht_trk_utc;
static xg_callback	ht_trk_lat;
static xg_callback	ht_trk_long;
static xg_callback	ht_trk_alt;

static xg_tag_mapping ht_map[] = {
  { ht_wpt_s, 	cb_start, "/hiketech/gpsdata/wpt" },
  { ht_wpt_e, 	cb_end,   "/hiketech/gpsdata/wpt" },
  { ht_ident, 	cb_cdata, "/hiketech/gpsdata/wpt/ident" },
  { ht_sym, 	cb_cdata, "/hiketech/gpsdata/wpt/sym" },
  { ht_lat, 	cb_cdata, "/hiketech/gpsdata/wpt/lat" },
  { ht_long, 	cb_cdata, "/hiketech/gpsdata/wpt/long" },
  { ht_alt, 	cb_cdata, "/hiketech/gpsdata/wpt/alt" },

  { ht_trk_s, 	cb_start, "/hiketech/gpsdata/trk" },
  { ht_trk_e, 	cb_end,   "/hiketech/gpsdata/trk" },
  { ht_trk_ident,	cb_cdata, "/hiketech/gpsdata/trk/ident" },
  { ht_trk_pnt_s,	cb_start, "/hiketech/gpsdata/trk/pnt" },
  { ht_trk_pnt_e,	cb_end,   "/hiketech/gpsdata/trk/pnt" },
  { ht_trk_utc, 	cb_cdata, "/hiketech/gpsdata/trk/pnt/utc" },
  { ht_trk_lat, 	cb_cdata, "/hiketech/gpsdata/trk/pnt/lat" },
  { ht_trk_long, 	cb_cdata, "/hiketech/gpsdata/trk/pnt/long" },
  { ht_trk_alt, 	cb_cdata, "/hiketech/gpsdata/trk/pnt/alt" },
  { nullptr,	(xg_cb_type)0,         nullptr}
};

static void
hiketech_rd_init(const QString& fname)
{
  xml_init(fname, ht_map, nullptr);
}

static void
hiketech_read()
{
  xml_read();
}

static void
hiketech_rd_deinit()
{
  xml_deinit();
}

static void
hiketech_wr_init(const QString& fname)
{
  ofd = gbfopen(fname, "w", MYNAME);

}

static void
hiketech_wr_deinit()
{
  writer.writeEndDocument();
  gbfputs(ostring, ofd);
  gbfclose(ofd);
  ofd = nullptr;
}

static void
hiketech_trk_hdr(const route_head* rte)
{
  writer.writeStartElement(QStringLiteral("trk"));
  writer.setAutoFormattingIndent(1);
  writer.writeOptionalTextElement(QStringLiteral("ident"), rte->rte_name);
}

static void
hiketech_trk_tlr(const route_head*)
{
  writer.writeEndElement(); // trk
}

static QString
hiketech_format_time(const QDateTime& t)
{
  // FIXME: Find out why these two blocks of code aren't equivalent.
  // it produces times that are 12 hours too late.  Double TZ bump?
  // for now, just go back to the way we've done it for a decade.  -- robert
#if 0
  return t.toString("yyyy-MM-dd hh:mm:ss");
#else
  char tbuf[80];
  time_t tm = t.toTime_t();
  strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %I:%M:%S", gmtime(&tm));
  return QString(tbuf);
#endif
}

static void
hiketech_trkpt_pr(const Waypoint* waypointp)
{
  writer.writeStartElement(QStringLiteral("pnt")); 
  if (waypointp->creation_time.isValid()) {
    writer.writeTextElement(QStringLiteral("utc"), 
                            hiketech_format_time(waypointp->GetCreationTime()));
  }
  writer.writeTextElement(QStringLiteral("lat"), QString::number(waypointp->latitude,'f', 6));
  writer.writeTextElement(QStringLiteral("long"), QString::number(waypointp->longitude,'f', 6));
  if (waypointp->altitude != unknown_alt) {
    writer.writeTextElement(QStringLiteral("alt"), QString::number(waypointp->altitude,'f', 6));
  }
  writer.writeEndElement(); // png
}

static void
hiketech_waypt_pr(const Waypoint* wpt)
{
  writer.writeStartElement(QStringLiteral("wpt")); 
  writer.setAutoFormattingIndent(-1);
  writer.writeTextElement(QStringLiteral("ident"), wpt->shortname);
  writer.writeTextElement(QStringLiteral("sym"), wpt->icon_descr);
  writer.writeTextElement(QStringLiteral("lat"), QString::number(wpt->latitude, 'f', 6));
  writer.writeTextElement(QStringLiteral("long"), QString::number(wpt->longitude, 'f', 6));
  writer.writeStartElement(QStringLiteral("color")); 
  writer.writeTextElement(QStringLiteral("lbl"), QStringLiteral("FAFFB4"));
  writer.writeTextElement(QStringLiteral("obj"), QStringLiteral("FF8000"));
  writer.writeEndElement(); // color

  writer.writeEndElement(); // wpt
}

static void
hiketech_write()
{
  writer.writeStartElement(QStringLiteral("hiketech"));
  writer.writeAttribute(QStringLiteral("version"), QStringLiteral("1.2"));
  writer.writeAttribute(QStringLiteral("url"), QStringLiteral("http://www.hiketech.com"));
  writer.setAutoFormatting(true);
  writer.writeStartElement(QStringLiteral("gpsdata"));
  track_disp_all(hiketech_trk_hdr, hiketech_trk_tlr, hiketech_trkpt_pr);
  track_disp_all(nullptr, nullptr, hiketech_trkpt_pr);
  waypt_disp_all(hiketech_waypt_pr);
  writer.writeEndElement(); // gpsdata
  writer.writeEndElement(); // hiketech
}

static
void	 ht_wpt_s(xg_string, const QXmlStreamAttributes*)
{
  wpt_tmp = new Waypoint;
}

static
void  	ht_ident(xg_string args, const QXmlStreamAttributes*)
{
  wpt_tmp->shortname = args;
}

static
void 	ht_sym(xg_string args, const QXmlStreamAttributes*)
{
  wpt_tmp->icon_descr = args;
}

static
void  	ht_lat(xg_string args, const QXmlStreamAttributes*)
{
  wpt_tmp->latitude = args.toDouble();
}

static
void  	ht_long(xg_string args, const QXmlStreamAttributes*)
{
  wpt_tmp->longitude = args.toDouble();
}

static
void  	ht_alt(xg_string args, const QXmlStreamAttributes*)
{
  wpt_tmp->altitude = args.toDouble();
}

static
void  	ht_wpt_e(xg_string, const QXmlStreamAttributes*)
{
  waypt_add(wpt_tmp);
  wpt_tmp = nullptr;
}

static
void	ht_trk_s(xg_string, const QXmlStreamAttributes*)
{
  trk_head = new route_head;
  track_add_head(trk_head);
}

static
void	ht_trk_e(xg_string, const QXmlStreamAttributes*)
{
}

static
void	ht_trk_ident(xg_string args, const QXmlStreamAttributes*)
{
  trk_head->rte_name = args;
}

static
void	ht_trk_pnt_s(xg_string, const QXmlStreamAttributes*)
{
  wpt_tmp = new Waypoint;
}

static
void	ht_trk_pnt_e(xg_string, const QXmlStreamAttributes*)
{
  track_add_wpt(trk_head, wpt_tmp);
}

static
void	ht_trk_utc(xg_string args, const QXmlStreamAttributes*)
{
  struct tm tm;

  sscanf(CSTRc(args), "%d-%d-%d %d:%d:%d",
         &tm.tm_year, &tm.tm_mon,
         &tm.tm_mday, &tm.tm_hour,
         &tm.tm_min, &tm.tm_sec);
  tm.tm_mon -= 1;
  tm.tm_year -= 1900;
  tm.tm_isdst = 0;

  time_t utc = mkgmtime(&tm);

  wpt_tmp->SetCreationTime(utc);
}

static
void	ht_trk_lat(xg_string args, const QXmlStreamAttributes*)
{
  wpt_tmp->latitude = args.toDouble();
}

static
void	ht_trk_long(xg_string args, const QXmlStreamAttributes*)
{
  wpt_tmp->longitude = args.toDouble();
}

static
void	ht_trk_alt(xg_string args, const QXmlStreamAttributes*)
{
  wpt_tmp->altitude = args.toDouble();
}



ff_vecs_t hiketech_vecs = {
  ff_type_file,
  { (ff_cap)(ff_cap_read | ff_cap_write), (ff_cap)(ff_cap_read | ff_cap_write), ff_cap_none },
  hiketech_rd_init,
  hiketech_wr_init,
  hiketech_rd_deinit,
  hiketech_wr_deinit,
  hiketech_read,
  hiketech_write,
  nullptr,
  &hiketech_args,
  CET_CHARSET_ASCII, 0	/* CET-REVIEW */
  , NULL_POS_OPS,
  nullptr
};

