/**********************************************************************
 * LeechCraft - modular cross-platform feature rich internet client.
 * Copyright (C) 2006-2014  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 "account.h"
#include <QInputDialog>
#include <QNetworkRequest>
#include <QStandardItem>
#include <QtDebug>
#include <util/passutils.h>
#include <util/util.h>
#include "yandexdisk.h"
#include "uploadmanager.h"
#include "authmanager.h"
#include "flgetter.h"
#include "simpleactor.h"

inline uint qHash (const QStringList& list)
{
	return qHash (list.join ("|"));
}

namespace LeechCraft
{
namespace NetStoreManager
{
namespace YandexDisk
{
	Account::Account (Plugin *plugin)
	: QObject (plugin)
	, Plugin_ (plugin)
	, AM_ (new AuthManager (this))
	{
	}

	QByteArray Account::Serialize () const
	{
		QByteArray result;
		QDataStream str (&result, QIODevice::WriteOnly);
		str << static_cast<quint8> (1)
			<< Name_
			<< Login_;
		return result;
	}

	Account_ptr Account::Deserialize (const QByteArray& data, Plugin *parent)
	{
		QDataStream str (data);
		quint8 version = 0;
		str >> version;

		if (version != 1)
		{
			qWarning () << Q_FUNC_INFO
					<< "unknown version"
					<< version;
			return Account_ptr ();
		}

		Account_ptr acc (new Account (parent));
		str >> acc->Name_
			>> acc->Login_;
		return acc;
	}

	AuthManager* Account::GetAuthManager () const
	{
		return AM_;
	}

	QString Account::GetLogin () const
	{
		return Login_;
	}

	QString Account::GetPassword ()
	{
		if (Login_.isEmpty ())
			return QString ();

		return Util::GetPassword ("org.LeechCraft.NetStoreManager.YandexDisk/" + Login_,
				tr ("Enter password for Yandex.Disk account %1 with login %2:")
					.arg (Name_)
					.arg (Login_),
				Plugin_);
	}

	bool Account::ExecConfigDialog ()
	{
		const QString& login = QInputDialog::getText (0,
				tr ("Account configuration"),
				tr ("Enter account login:"),
				QLineEdit::Normal,
				Login_);
		if (login.isEmpty ())
			return false;

		Login_ = login;
		return true;
	}

	void Account::SetAccountName (const QString& name)
	{
		Name_ = name;
	}

	QString Account::GetAccountName () const
	{
		return Name_;
	}

	QObject* Account::GetParentPlugin () const
	{
		return Plugin_;
	}

	QObject* Account::GetQObject ()
	{
		return this;
	}

	AccountFeatures Account::GetAccountFeatures () const
	{
		return AccountFeature::FileListings | AccountFeature::ProlongateFiles;
	}

	void Account::Upload (const QString& path)
	{
		auto mgr = new UploadManager (path, this);
		connect (mgr,
				SIGNAL (statusChanged (QString, QString)),
				this,
				SIGNAL (upStatusChanged (QString, QString)));
		connect (mgr,
				SIGNAL (gotError (QString, QString)),
				this,
				SIGNAL (upError (QString, QString)));
		connect (mgr,
				SIGNAL (gotUploadURL (QUrl, QString)),
				this,
				SIGNAL (gotURL (QUrl, QString)));
		connect (mgr,
				SIGNAL (uploadProgress (quint64, quint64, QString)),
				this,
				SIGNAL (upProgress (quint64, quint64, QString)));
		connect (mgr,
				SIGNAL (finished ()),
				this,
				SLOT (forceRefresh ()));
	}

	ListingOps Account::GetListingOps () const
	{
		return ListingOp::Delete | ListingOp::Prolongate | ListingOp::ToggleProtected;
	}

	void Account::RefreshListing ()
	{
		auto getter = new FLGetter (this);
		connect (getter,
				SIGNAL (gotFiles (QList<FLItem>)),
				this,
				SLOT (handleFileList (QList<FLItem>)));
	}

	QStringList Account::GetListingHeaders () const
	{
		QStringList result;
		result << tr ("File");
		result << tr ("Size");
		result << tr ("Valid for");
		result << tr ("Password");
		return result;
	}

	void Account::Delete (const QList<QStringList>& ids)
	{
		SimpleAction ("delete", ids);
	}

	void Account::Prolongate (const QList<QStringList>& ids)
	{
		SimpleAction ("prolongate", ids);
	}

	void Account::MoveToTrash (const QList<QStringList>&)
	{
	}

	void Account::RestoreFromTrash (const QList<QStringList>&)
	{
	}

	void Account::EmptyTrash (const QList<QStringList>&)
	{
	}

	void Account::RequestUrl (const QList<QStringList>& ids)
	{
		qDebug () << Q_FUNC_INFO << ids << ID2URL_;
		Q_FOREACH (const auto& id, ids)
			emit gotFileUrl (ID2URL_.value (id), id);
	}

	QNetworkRequest Account::MakeRequest (const QUrl& url) const
	{
		QNetworkRequest rq (url);
		rq.setRawHeader ("Cache-Control", "no-cache");
		rq.setRawHeader ("Accept", "*/*");
		rq.setHeader (QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
		return rq;
	}

	void Account::SimpleAction (const QString& act, const QList<QStringList>& ids)
	{
		if (ids.isEmpty ())
			return;

		QByteArray post = "action=" + act.toLatin1 ();
		Q_FOREACH (const QStringList& id, ids)
			post += QString ("&fid=%1&token-%1=%2")
					.arg (id.at (0))
					.arg (id.at (1))
					.toUtf8 ();

		auto actor = new SimpleActor (QUrl ("http://narod.yandex.ru/disk/all"), post, this);
		connect (actor,
				SIGNAL (finished ()),
				this,
				SLOT (forceRefresh ()));
	}

	void Account::forceRefresh ()
	{
		emit gotListing (QList<QList<QStandardItem*>> ());
		RefreshListing ();
	}

	void Account::handleFileList (const QList<FLItem>& items)
	{
		ID2URL_.clear ();

		QList<QList<QStandardItem*>> treeItems;

		qDebug () << Q_FUNC_INFO << items.size ();
		Q_FOREACH (const FLItem& item, items)
		{
			qDebug () << item.Name_ << item.Size_ << item.Date_ << item.Icon_;
			QList<QStandardItem*> row;
			row << new QStandardItem (item.Name_);
			row << new QStandardItem (item.Size_);
			row << new QStandardItem (item.Date_);
			row << new QStandardItem (item.PassSet_ ? tr ("yes") : tr ("no"));

			row.first ()->setIcon (item.Icon_);

			QStringList id;
			id << item.ID_
				<< item.Token_
				<< item.PassToken_;
			row.first ()->setData (id, ListingRole::ID);

			ID2URL_ [id] = QUrl::fromEncoded (item.URL_.toUtf8 ());

			treeItems << row;
		}

		emit gotListing (treeItems);
	}
}
}
}
