/***************************************************************************
 *   Copyright (C) 2010 by Volker Lanz <vl@fidra.de>                       *
 *                                                                         *
 *   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 "fileexport/kmlexporter.h"

#include "core/activity.h"
#include "core/lap.h"
#include "core/track.h"
#include "core/trackpoint.h"

#include "veneer/datetime.h"

#include "util/unit.h"

#include <QXmlStreamWriter>
#include <QDateTime>
#include <QDebug>
#include <veneer/settings.h>

KmlExporter::KmlExporter(bool marbleMode) :
	ExporterInterface(),
	m_MarbleMode(marbleMode)
{
}

bool KmlExporter::canExport(const QString& suffix, const Activities&)
{
	return suffix == "kml";
}

static QString descRow(const QString& name, const QString& value)
{
	return "<tr><td style=\"font-weight:bold\">" + name + "</td><td>" + value + "</td></tr>\n";
}

static QString buildDescription(const TrackPoint& tp)
{
	QString s = "<table>\n";
	s += descRow(QObject::tr("Time"), Veneer::formatDateTime(tp.timeStamp()));
	s += descRow(QObject::tr("Speed"), Unit::formatSpeed(tp.speed()));
	s += descRow(QObject::tr("Cadence"), QString::number(tp.cadence()) + " rpm");
	s += descRow(QObject::tr("Heart Rate"), QString::number(tp.heartRate()) + " bpm");
	s += descRow(QObject::tr("Altitude"), QString::number(tp.altitude() / 1000.0) + 'm');
	s += "</table>";

	return s;
}

bool KmlExporter::writeTrack(QXmlStreamWriter& xml, const Track& trk) const
{
	foreach(const TrackPoint* tp, trk.trackPoints())
	{
		if (!tp->position().isValid())
			continue;

		xml.writeStartElement("Placemark");
		xml.writeTextElement("name", tp->timeStamp().toString(Qt::ISODate) + 'Z');
		xml.writeTextElement("Snippet", "");

		xml.writeStartElement("description");
		xml.writeCDATA(buildDescription(*tp));
		xml.writeEndElement();

		xml.writeStartElement("TimeStamp");
		xml.writeTextElement("when", tp->timeStamp().toString(Qt::ISODate) + 'Z');
		xml.writeEndElement();

		xml.writeTextElement("styleUrl", "#track");

		xml.writeStartElement("Point");
		const QString coordinates = QString("%1,%2,%3")
			.arg(QString::number(tp->position().longitude(), 'f', 9))
			.arg(QString::number(tp->position().latitude(), 'f', 9))
			.arg(QString::number(tp->altitude() / 1000.0));
		xml.writeTextElement("coordinates", coordinates);
		xml.writeEndElement();

		xml.writeEndElement();
	}

	return true;
}

static QString buildDescription(const Lap& lap)
{
	QString s = "<table>\n";
	s += descRow(QObject::tr("Distance"), Unit::formatDistance(lap.distance()));
	s += descRow(QObject::tr("Start Time"), Veneer::formatDateTime(lap.startTime()));
	s += descRow(QObject::tr("Max Speed"), Unit::formatSpeed(lap.maximumSpeed()));
	s += descRow(QObject::tr("Avg Heart Rate"), QObject::tr("%1 bpm").arg(lap.averageHeartRate()));
	s += descRow(QObject::tr("Max Heart Rate"), QObject::tr("%1 bpm").arg(lap.maximumHeartRate()));
	s += descRow(QObject::tr("Avg Cadence"), QObject::tr("%1 rpm").arg(lap.averageCadence()));
	s += descRow(QObject::tr("Energy Consumption"), Unit::formatEnergy(lap.energyConsumption()));
	s += descRow(QObject::tr("Total Ascent"), Unit::formatHeight(lap.ascent()));
	s += descRow(QObject::tr("Total Descent"), Unit::formatHeight(lap.descent()));
	s += "</table>\n";

	return s;
}

bool KmlExporter::writeLap(QXmlStreamWriter& xml, const Lap& lap, const quint32 activityNumber) const
{
	xml.writeStartElement("Folder");
	xml.writeTextElement("name", Veneer::formatDateTime(lap.startTime()));
	xml.writeTextElement("Snippet", "");

	if (!m_MarbleMode && Veneer::Settings::self()->kmlExportSummary())
	{
		xml.writeStartElement("description");
		xml.writeCDATA(buildDescription(lap));
		xml.writeEndElement();
	}

	if (!m_MarbleMode && Veneer::Settings::self()->kmlExportPoints())
	{
		xml.writeStartElement("Folder");
		xml.writeTextElement("name", "Points");

		foreach(const Track* track, lap.tracks())
			writeTrack(xml, *track);
	}

	xml.writeEndElement();

	xml.writeStartElement("Placemark");
	xml.writeTextElement("name", "Path");
	xml.writeTextElement("styleUrl", QString("#lineStyle_%1").arg(activityNumber));

	xml.writeStartElement("LineString");
	xml.writeTextElement("tessellate", "1");

	xml.writeStartElement("coordinates");
	foreach(const Track* trk, lap.tracks())
		foreach(const TrackPoint* tp, trk->trackPoints())
		{
			if (!tp->position().isValid())
				continue;

			const QString coordinates = QString("%1,%2,%3\n")
				.arg(QString::number(tp->position().longitude(), 'f', 9))
				.arg(QString::number(tp->position().latitude(), 'f', 9))
				.arg(QString::number(tp->altitude() / 1000.0));
			xml.writeCharacters(coordinates);
		}

	xml.writeEndElement();
	xml.writeEndElement();
	xml.writeEndElement();

	xml.writeEndElement();

	return true;
}

bool KmlExporter::writeActivity(QXmlStreamWriter& xml, const Activity& a, const quint32 activityNumber) const
{
	xml.writeStartElement("Folder");
	xml.writeTextElement("name", a.name());

	foreach(const Lap* lap, a.laps())
		writeLap(xml, *lap, activityNumber);

	xml.writeEndElement();

	return true;
}

static void writeStyleColor(QXmlStreamWriter& xml, quint32 count)
{
	// aabbggrr (alpha, blue, green red)
	static const char* cols[] =
	{
		"99ffcc55",
		"9988ff59",
		"9933ccff",
		"998822ff"
	};

	xml.writeStartElement("Style");
	xml.writeAttribute("id", QString("lineStyle_%1").arg(count));
	xml.writeStartElement("LineStyle");
	xml.writeTextElement("color", cols[count % (sizeof(cols) / sizeof(cols[0]))]);
	xml.writeTextElement("width", "6");
	xml.writeEndElement();
	xml.writeEndElement();
}

bool KmlExporter::writeStyles(QXmlStreamWriter& xml, const quint32 activityCount) const
{
	xml.writeStartElement("Style");
	xml.writeAttribute("id", "track_n");
	xml.writeStartElement("IconStyle");
	xml.writeStartElement("Icon");
	xml.writeTextElement("href", "http://earth.google.com/images/kml-icons/track-directional/track-none.png");
	xml.writeEndElement();
	xml.writeEndElement();
	xml.writeEndElement();

	xml.writeStartElement("Style");
	xml.writeAttribute("id", "track_h");
	xml.writeStartElement("IconStyle");
	xml.writeTextElement("scale", "1.2");
	xml.writeStartElement("Icon");
	xml.writeTextElement("href", "http://earth.google.com/images/kml-icons/track-directional/track-none.png");
	xml.writeEndElement();
	xml.writeEndElement();
	xml.writeEndElement();

	xml.writeStartElement("StyleMap");
	xml.writeAttribute("id", "track");
	xml.writeStartElement("Pair");
	xml.writeTextElement("key", "normal");
	xml.writeTextElement("styleUrl", "#track_n");
	xml.writeEndElement();
	xml.writeStartElement("Pair");
	xml.writeTextElement("key", "highlight");
	xml.writeTextElement("styleUrl", "#track_h");
	xml.writeEndElement();
	xml.writeEndElement();

	for (quint32 count = 0; count < activityCount; count++)
		writeStyleColor(xml, count);

	return true;
}

bool KmlExporter::writeRootElement(QXmlStreamWriter& xml, const Activities&)
{
	xml.writeStartElement("kml");
	xml.writeAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
	xml.writeAttribute("xmlns", "http://earth.google.com/kml/2.1");

	return true;
}

bool KmlExporter::writeActivities(QXmlStreamWriter& xml, const Activities& activities)
{
	xml.writeStartElement("Document");

	xml.writeTextElement("name", QObject::tr("Export from Workout"));
	xml.writeTextElement("Snippet", QObject::tr("Created: %1").arg(Veneer::formatDateTime(QDateTime::currentDateTime())));

	writeStyles(xml, activities.size());

	quint32 count = 0;
	foreach(const Activity* a, activities)
		writeActivity(xml, *a, count++);

	xml.writeEndElement();

	return true;
}

QString KmlExporter::fileFormat() const
{
	return QObject::tr("*.kml|Keyhole Markup (Google Earth) (*.kml)");
}
