/**********************************************************************
 * LeechCraft - modular cross-platform feature rich internet client.
 * Copyright (C) 2006-2013  Georg Rudoy
 *
 * Boost Software License - Version 1.0 - August 17th, 2003
 *
 * Permission is hereby granted, free of charge, to any person or organization
 * obtaining a copy of the software and accompanying documentation covered by
 * this license (the "Software") to use, reproduce, display, distribute,
 * execute, and transmit the Software, and to prepare derivative works of the
 * Software, and to permit third-parties to whom the Software is furnished to
 * do so, all subject to the following:
 *
 * The copyright notices in the Software and this entire statement, including
 * the above license grant, this restriction and the following disclaimer,
 * must be included in all copies of the Software, in whole or in part, and
 * all derivative works of the Software, unless such copies or derivative
 * works are solely in the form of machine-executable object code generated by
 * a source language processor.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 **********************************************************************/

#include "userlocation.h"
#include <QUrl>
#include <QDateTime>
#include <QDomElement>
#include <QtDebug>
#include <QXmppElement.h>

namespace LeechCraft
{
namespace Azoth
{
namespace Xoox
{
	const QString NsLocationNode = "http://jabber.org/protocol/geoloc";
	
	QString UserLocation::GetNodeString ()
	{
		return NsLocationNode;
	}
	
	QXmppElement UserLocation::ToXML () const
	{
		QXmppElement geoloc;
		geoloc.setTagName ("geoloc");
		geoloc.setAttribute ("xmlns", NsLocationNode);

		Q_FOREACH (const QString& key, Info_.keys ())
		{
			QXmppElement elem;
			elem.setTagName (key);

			const QVariant& val = Info_ [key];
			if (val.type () == QVariant::DateTime)
				elem.setValue (val.toDateTime ().toString (Qt::ISODate));
			else if (val.type () == QVariant::Url)
				elem.setValue (val.toUrl ().toEncoded ());
			else
				elem.setValue (val.toString ());

			geoloc.appendChild (elem);
		}

		QXmppElement result;
		result.setTagName ("item");
		result.appendChild (geoloc);
		return result;
	}
	
	namespace
	{
		template<typename T>
		struct Converter;
		
		template<>
		struct Converter<QString>
		{
			QString operator() (const QString& str) const
			{
				return str;
			}
		};
		
		template<>
		struct Converter<double>
		{
			double operator() (const QString& str) const
			{
				return str.toDouble ();
			}
		};
		
		template<>
		struct Converter<QUrl>
		{
			QUrl operator() (const QString& str) const
			{
				return QUrl::fromEncoded (str.toUtf8 ());
			}
		};
		
		template<>
		struct Converter<QDateTime>
		{
			QDateTime operator() (const QString& str) const
			{
				return QDateTime::fromString (str, Qt::ISODate);
			}
		};

		template<typename T>
		struct ParseElem
		{
			const QDomElement& R_;
			GeolocationInfo_t& I_;

			ParseElem (const QDomElement& root, GeolocationInfo_t& info)
			: R_ (root)
			, I_ (info)
			{
			}
			
			ParseElem operator() (const char *elemName)
			{
				const QDomElement& child = R_.firstChildElement (elemName);
				if (!child.isNull ())
					I_ [elemName] = Converter<T> () (child.text ());
				return *this;
			}
			
			template<typename U>
			ParseElem<U> operator() (const U&)
			{
				return ParseElem<U> (R_, I_);
			}
		};
	}
	
	void UserLocation::Parse (const QDomElement& elem)
	{
		Info_.clear ();
		
		const QDomElement& geolocElem = elem.firstChildElement ("geoloc");
		if (geolocElem.namespaceURI () != NsLocationNode)
			return;
		
		ParseElem<double> (geolocElem, Info_)
			("accuracy")
			("alt")
			("bearing")
			("lat")
			("lon")
			("speed")
			(QString ())
			("area")
			("building")
			("country")
			("countrycode")
			("datum")
			("description")
			("floor")
			("locality")
			("postalcode")
			("region")
			("room")
			("street")
			("text")
			(QDateTime ())
			("timestamp")
			(QUrl ())
			("uri");
	}
	
	QString UserLocation::Node () const
	{
		return GetNodeString ();
	}
	
	PEPEventBase* UserLocation::Clone () const
	{
		return new UserLocation (*this);
	}
	
	GeolocationInfo_t UserLocation::GetInfo () const
	{
		return Info_;
	}
	
	void UserLocation::SetInfo (const GeolocationInfo_t& info)
	{
		Info_ = info;
	}
}
}
}
