/***************************************************************************
 *   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 "fileimport/garmintrainingcenterimporter.h"

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

#include "util/xml.h"

#include <QString>
#include <QFile>
#include <QXmlStreamReader>
#include <QDateTime>
#include <QDebug>

GarminTrainingCenterImporter::GarminTrainingCenterImporter() :
	ImporterInterface("TrainingCenterDatabase")
{
}

static void parseTrackPoint(QXmlStreamReader& xml, Track& track)
{
	TrackPoint* tp = new TrackPoint();

	while (xmlReadNextStartElement(xml))
	{
		if (xml.name() == "Time")
			tp->setTimeStamp(QDateTime::fromString(xml.readElementText(), Qt::ISODate));
		else if (xml.name() == "Position")
		{
			double lat = Position::Invalid;
			double lon = Position::Invalid;

			while (xmlReadNextStartElement(xml))
			{
				if (xml.name() == "LatitudeDegrees")
					lat = xml.readElementText().toDouble();
				else if (xml.name() == "LongitudeDegrees")
					lon = xml.readElementText().toDouble();
				else
				{
					qDebug() << "unknown tag in <Position>: " << xml.name();
					xmlSkipCurrentElement(xml);
				}
			}

			if (lat != Position::Invalid && lon != Position::Invalid)
				tp->setPosition(Position(lat, lon));
		}
		else if (xml.name() == "AltitudeMeters")
			tp->setAltitude(xml.readElementText().toDouble() * 1000);
		else if (xml.name() == "HeartRateBpm")
		{
			while (xmlReadNextStartElement(xml))
			{
				if (xml.name() == "Value")
					tp->setHeartRate(xml.readElementText().toUInt());
				else
				{
					qDebug() << "unknown tag in <Value>: " << xml.name();
					xmlSkipCurrentElement(xml);
				}
			}
		}
		else if (xml.name() == "Cadence")
			tp->setCadence(xml.readElementText().toUInt());
		else if (xml.name() == "SensorState")
			xmlSkipCurrentElement(xml);
		else if (xml.name() == "DistanceMeters")
			xmlSkipCurrentElement(xml);
		else
		{
			qDebug() << "unknown tag in <Trackpoint>: " << xml.name();
			xmlSkipCurrentElement(xml);
		}
	}

	track.addTrackPoint(tp);
}

static void parseTrack(QXmlStreamReader& xml, Track& track)
{
	while (xmlReadNextStartElement(xml))
	{
		if (xml.name() == "Trackpoint")
			parseTrackPoint(xml, track);
		else
		{
			qDebug() << "unknown tag in <Track>: " << xml.name();
			xmlSkipCurrentElement(xml);
		}
	}
}

static void parseLap(QXmlStreamReader& xml, Lap& lap)
{
	lap.setStartTime(QDateTime::fromString(xml.attributes().value("StartTime").toString(), Qt::ISODate));

	while (xmlReadNextStartElement(xml))
	{
		if (xml.name() == "TotalTimeSeconds")
			lap.setDuration(xml.readElementText().toDouble() * 1000);
		else if (xml.name() == "DistanceMeters")
			lap.setDistance(xml.readElementText().toDouble() * 1000);
		else if (xml.name() == "MaximumSpeed")
			lap.setMaximumSpeed(3.6 * xml.readElementText().toDouble() * 1000);
		else if (xml.name() == "Calories")
			lap.setEnergyConsumption(4.1858 * xml.readElementText().toDouble());
		else if (xml.name() == "AverageHeartRateBpm")
		{
			while (xmlReadNextStartElement(xml))
			{
				if (xml.name() == "Value")
					lap.setAverageHeartRate(xml.readElementText().toUInt());
				else if (!xml.name().isEmpty())
			    {
					qDebug() << "unknown tag in <AVerageHeartRateBpm>: " << xml.name();
					xmlSkipCurrentElement(xml);
				}
			}
		}
		else if (xml.name() == "MaximumHeartRateBpm")
		{
			while (xmlReadNextStartElement(xml))
			{
				if (xml.name() == "Value")
					lap.setMaximumHeartRate(xml.readElementText().toUInt());
				else if (!xml.name().isEmpty())
				{
					qDebug() << "unknown tag in <MaximumHeartRateBpm>: " << xml.name();
					xmlSkipCurrentElement(xml);
				}
			}
		}
		else if (xml.name() == "Cadence")
			lap.setAverageCadence(xml.readElementText().toUInt());
		else if (xml.name() == "Intensity" || xml.name() == "TriggerMethod")
			xmlSkipCurrentElement(xml);
		else if (xml.name() == "Track")
		{
			Track* t = new Track();
			parseTrack(xml, *t);
			lap.addTrack(t);
		}
		else
		{
			qDebug() << "unknown tag in <Lap>: " << xml.name();
			xmlSkipCurrentElement(xml);
		}
	}
}

static void parseActivity(QXmlStreamReader& xml, Activities& activities)
{
	Activity* activity = new Activity();

	while (xmlReadNextStartElement(xml))
	{
		if (xml.name() == "Id")
			activity->setTimeStamp(QDateTime::fromString(xml.readElementText(), Qt::ISODate));
		else if (xml.name() == "Lap")
		{
			Lap* lap = new Lap();
			parseLap(xml, *lap);
			activity->addLap(lap);
		}
		else if (xml.name() == "Creator")
			xmlSkipCurrentElement(xml);
		else
		{
			qDebug() << "unknown tag in <Activity>: " << xml.name();
			xmlSkipCurrentElement(xml);
		}
	}

	activities.append(activity);
}

void GarminTrainingCenterImporter::parseActivities(QXmlStreamReader& xml, Activities& activities)
{
	int count = 0;

	while (xmlReadNextStartElement(xml))
	{
		if (xml.name() == "Activity")
		{
			parseActivity(xml, activities);
			emit progress(++count);
		}
		else
		{
			qDebug() << "unknown tag in <Activities>: " << xml.name();
			xmlSkipCurrentElement(xml);
		}
	}
}

void GarminTrainingCenterImporter::parseRootElement(QXmlStreamReader& xml, Activities& activities)
{
	while (xmlReadNextStartElement(xml))
	{
		if (xml.name() == "Activities")
			parseActivities(xml, activities);
		else if (xml.name() == "Author")
			xmlSkipCurrentElement(xml);
		else
		{
			qDebug() << "unknown tag in <TrainingCenterDatabase>: " << xml.name();
			xmlSkipCurrentElement(xml);
		}
	}
}

bool GarminTrainingCenterImporter::canImport(const QString& rootName)
{
	return rootName == m_RootElementTagName;
}

QString GarminTrainingCenterImporter::fileFormat() const
{
	return tr("*.tcx|Garmin Training Center(*.tcx)");
}
