/**********************************************************************
 * 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 "videofindproxy.h"
#include <QMenu>
#include <QAction>
#include <QToolBar>
#include <QTextCodec>
#include <util/xpc/util.h>
#include <util/sys/paths.h>

Q_DECLARE_METATYPE (QToolBar*)
Q_DECLARE_METATYPE (QMenu*)

namespace LeechCraft
{
namespace vGrabber
{
	VideoFindProxy::VideoFindProxy (const Request& r, CategoriesSelector *cs)
	: FindProxy (r, cs, FPTVideo)
	, Type_ (PTInvalid)
	{
		SetError (tr ("Searching for %1...")
				.arg (r.String_));
	}

	QVariant VideoFindProxy::data (const QModelIndex& index, int role) const
	{
		if (!index.isValid ())
			return QVariant ();

		switch (role)
		{
			case Qt::DisplayRole:
				if (Error_)
				{
					switch (index.column ())
					{
						case 0:
							return *Error_;
						case 1:
							return tr ("Video vkontakte.ru");
						default:
							return QString ();
					}
				}
				else
				{
					const VideoResult& res = VideoResults_ [index.row ()];
					switch (index.column ())
					{
						case 0:
							return res.Title_;
						case 1:
							return tr ("Video");
						case 2:
							return res.URL_.toString ();
						default:
							return QString ();
					}
				}
			case LeechCraft::RoleControls:
				{
					UpdateURLActionsData (index.row ());
					return QVariant::fromValue<QToolBar*> (Toolbar_);
				}
			case LeechCraft::RoleContextMenu:
				{
					UpdateURLActionsData (index.row ());
					return QVariant::fromValue<QMenu*> (ContextMenu_);
				}
			default:
				return QVariant ();
		}
	}

	void VideoFindProxy::UpdateURLActionsData (int row) const
	{
		QUrl url;
		if (VideoResults_.size () > row)
			url = VideoResults_ [row].URL_;
		if (!url.isEmpty ())
		{
			ActionDownload_->setData (url);
			ActionHandle_->setData (url);
			ActionCopyToClipboard_->setData (url);
		}
		ActionDownload_->setEnabled (!url.isEmpty ());
		ActionHandle_->setEnabled (!url.isEmpty ());
		ActionCopyToClipboard_->setEnabled (!url.isEmpty ());
	}

	int VideoFindProxy::rowCount (const QModelIndex& parent) const
	{
		if (parent.isValid ())
			return 0;

		if (Error_)
			return 1;
		else
			return VideoResults_.size ();
	}

	QUrl VideoFindProxy::GetURL () const
	{
		QByteArray urlStr = "http://vk.com/gsearch.php?q=FIND&section=video";
		urlStr.replace ("FIND",
				QTextCodec::codecForName ("Windows-1251")->fromUnicode (R_.String_).toPercentEncoding ());
		QUrl result = QUrl::fromEncoded (urlStr);
		return result;
	}

	void VideoFindProxy::Handle (const QString& contents)
	{
		if (Type_ == PTInvalid)
			HandleSearchResults (contents);
		else
			HandleVideoPage (contents);
	}

	void VideoFindProxy::HandleSearchResults (const QString& contents)
	{
		QRegExp upt ("<div class=\"aname\" style='width:255px; overflow: hidden'><a href=\"video(.*)\\?noiphone\">(.*)</a></div>",
				Qt::CaseSensitive,
				QRegExp::RegExp2);
		upt.setMinimal (true);
		int pos = 0;
		while ((pos = upt.indexIn (contents, pos)) >= 0)
		{
			QStringList captured = upt.capturedTexts ();
			QUrl url = QUrl (QString ("http://vk.com/video%1")
					.arg (captured.at (1)));
			QString title = captured.at (2);
			title.remove ("<span class=\"match\">").remove ("</span>");

			VideoResult vr =
			{
				url,
				title
			};

			VideoResults_ << vr;
			pos += upt.matchedLength ();
		}

		if (VideoResults_.size ())
		{
			SetError (QString ());

			beginInsertRows (QModelIndex (), 0, VideoResults_.size () - 1);
			endInsertRows ();
		}
		else
			SetError (tr ("Nothing found for %1")
					.arg (R_.String_));
	}

	namespace
	{
		QString GetStringFromRX (const QString& pattern, const QString& contents)
		{
			QString result;
			QRegExp rx (pattern,
					Qt::CaseSensitive,
					QRegExp::RegExp2);
			rx.setMinimal (true);
			if (rx.indexIn (contents) != -1)
				result = rx.capturedTexts ().at (1);
			else
				qWarning () << Q_FUNC_INFO
					<< "nothing captured for pattern"
					<< rx.pattern ();
			return result;
		}
	};

	void VideoFindProxy::HandleVideoPage (const QString& contents)
	{
		// http://cs12739.vkontakte.ru/u16199765/video/1684dec3e6.240.mp4
		// -----------$host-----------/--$user--/video/---$vtag--.240.mp4
		QString host = GetStringFromRX (".*\"host\":\"([0-9a-z/\\:\\.\\\\]*)\".*", contents);
		QString user = GetStringFromRX (".*\"uid\":\"([0-9]*)\".*", contents);
		QString vtag = GetStringFromRX (".*\"vtag\":\"([0-9a-f\\-]*)\".*", contents);
		// Not needed anymore, but let's have it here just in case.
		// QString vkid = GetStringFromRX (".*\"vkid\":\"([0-9a-f]*)\".*", contents);

		host.replace ("\\/", "/");
		if (host.endsWith ('/'))
			host.chop (1);

		if (host.isEmpty () ||
				vtag.isEmpty () ||
				user.isEmpty ())
		{
			qWarning () << Q_FUNC_INFO
				<< "one of required attrs is empty"
				<< host
				<< vtag
				<< user
				<< "for"
				<< contents;
			return;
		}

		QString source = QString ("%1/u%2/video/%3.240.mp4")
				.arg (host)
				.arg (user)
				.arg (vtag);

		qDebug () << Q_FUNC_INFO
				<< source;

		LeechCraft::TaskParameter hd = OnlyHandle;
		switch (Type_)
		{
			case PTInvalid:
				qWarning () << Q_FUNC_INFO
					<< "invalid Type_, assuming both Download and Handle";
				break;
			case PTHandle:
				hd = OnlyHandle;
				break;
			case PTDownload:
				hd = OnlyDownload;
				break;
		}

		EmitWith (hd, QUrl (source));
	}

	void VideoFindProxy::handleDownload ()
	{
		Type_ = PTDownload;
		HandleAction ();
	}

	void VideoFindProxy::handleHandle ()
	{
		Type_ = PTHandle;
		HandleAction ();
	}

	void VideoFindProxy::HandleAction ()
	{
		QUrl url = qobject_cast<QAction*> (sender ())->data ().value<QUrl> ();

		QString fname = Util::GetTemporaryName ();
		Entity e =
			Util::MakeEntity (url,
				fname,
				LeechCraft::Internal |
					LeechCraft::DoNotNotifyUser |
					LeechCraft::DoNotSaveInHistory |
					LeechCraft::NotPersistent |
					LeechCraft::DoNotAnnounceEntity);

		int id = -1;
		QObject *pr = 0;
		emit delegateEntity (e, &id, &pr);
		if (id == -1)
		{
			emit error (tr ("Job for request<br />%1<br />wasn't delegated.")
					.arg (url.toString ()));
			return;
		}

		Jobs_ [id] = fname;
		HandleProvider (pr);
	}
}
}
