/**********************************************************************
 * 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 "vkchatentry.h"
#include <QStringList>
#include <QtDebug>
#include <interfaces/azoth/iproxyobject.h>
#include "vkaccount.h"
#include "vkentry.h"
#include "vkmessage.h"
#include "vkconnection.h"

namespace LeechCraft
{
namespace Azoth
{
namespace Murm
{
	VkChatEntry::VkChatEntry (const ChatInfo& chatInfo, VkAccount *acc)
	: EntryBase (acc)
	, Info_ (chatInfo)
	{
		for (const auto& info : chatInfo.Users_)
			if (const auto entry = acc->GetEntryOrCreate (info))
				entry->RegisterIn (this);

		connect (acc->GetConnection (),
				SIGNAL (gotUsers (QList<UserInfo>)),
				this,
				SLOT (handleGotUsers (QList<UserInfo>)));
	}

	void VkChatEntry::Send (VkMessage *msg)
	{
		Account_->Send (GetInfo ().ChatID_, VkConnection::Type::Chat, msg);
	}

	VkChatEntry::HandleMessageResult VkChatEntry::HandleMessage (const MessageInfo& info)
	{
		const auto from = info.Params_ ["from"].toULongLong ();
		if (from == 0)
		{
			qWarning () << Q_FUNC_INFO
					<< "unknown from"
					<< info.Params_;
			return HandleMessageResult::Rejected;
		}

		const auto entry = Account_->GetEntry (from);
		if (!entry)
		{
			qDebug () << Q_FUNC_INFO
					<< "unknown entry for"
					<< from;
			if (!PendingUserInfoRequests_.contains (from))
			{
				qDebug () << Q_FUNC_INFO
						<< "requesting user info for"
						<< from;
				Account_->GetConnection ()->GetUserInfo ({ from });
				PendingUserInfoRequests_ << from;
			}
			return HandleMessageResult::UserInfoRequested;
		}

		auto msg = new VkMessage (false, IMessage::Direction::In, IMessage::Type::MUCMessage, this, entry);
		msg->SetDateTime (info.TS_);
		msg->SetID (info.ID_);

		HandleAttaches (msg, info);

		Store (msg);

		return HandleMessageResult::Accepted;
	}

	const ChatInfo& VkChatEntry::GetInfo () const
	{
		return Info_;
	}

	void VkChatEntry::UpdateInfo (const ChatInfo& info)
	{
		for (const auto& userInfo : info.Users_)
			if (std::none_of (Info_.Users_.begin (), Info_.Users_.end (),
					[userInfo] (const UserInfo& other) { return other.ID_ == userInfo.ID_; }))
				HandleAdded (userInfo);
		for (const auto& userInfo : Info_.Users_)
			if (std::none_of (info.Users_.begin (), info.Users_.end (),
					[userInfo] (const UserInfo& other) { return other.ID_ == userInfo.ID_; }))
				HandleRemoved (userInfo.ID_);

		const bool titleChanged = info.Title_ != Info_.Title_;

		Info_ = info;
		if (titleChanged)
		{
			emit nameChanged (GetEntryName ());

			for (const auto& info : Info_.Users_)
				if (const auto entry = Account_->GetEntry (info.ID_))
					entry->ReemitGroups ();
		}
	}

	void VkChatEntry::HandleAdded (const UserInfo& info)
	{
		if (const auto entry = Account_->GetEntryOrCreate (info))
			entry->RegisterIn (this);
	}

	void VkChatEntry::HandleRemoved (qulonglong id)
	{
		if (id == Account_->GetSelf ()->GetInfo ().ID_)
		{
			for (const auto& otherInfo : Info_.Users_)
				if (auto entry = Account_->GetEntry (otherInfo.ID_))
					entry->UnregisterIn (this);

			emit removeEntry (this);
		}
		else if (const auto entry = Account_->GetEntry (id))
			entry->UnregisterIn (this);
	}

	ICLEntry::Features VkChatEntry::GetEntryFeatures () const
	{
		return FSessionEntry | FSupportsRenames;
	}

	ICLEntry::EntryType VkChatEntry::GetEntryType () const
	{
		return EntryType::MUC;
	}

	QString VkChatEntry::GetEntryName () const
	{
		return Info_.Title_;
	}

	void VkChatEntry::SetEntryName (const QString& title)
	{
		Account_->GetConnection ()->SetChatTitle (Info_.ChatID_, title);
	}

	QString VkChatEntry::GetEntryID () const
	{
		return Account_->GetAccountID () + QString::number (Info_.ChatID_);
	}

	QString VkChatEntry::GetHumanReadableID () const
	{
		return QString::number (Info_.ChatID_);
	}

	QStringList VkChatEntry::Groups () const
	{
		return { tr ("Chats") };
	}

	void VkChatEntry::SetGroups (const QStringList&)
	{
	}

	QStringList VkChatEntry::Variants () const
	{
		return {};
	}

	void VkChatEntry::SetChatPartState (ChatPartState, const QString&)
	{
		// TODO
	}

	EntryStatus VkChatEntry::GetStatus (const QString&) const
	{
		return { SOnline, {} };
	}

	QImage VkChatEntry::GetAvatar () const
	{
		return {};
	}

	void VkChatEntry::ShowInfo ()
	{
	}

	QList<QAction*> VkChatEntry::GetActions () const
	{
		return {};
	}

	QMap<QString, QVariant> VkChatEntry::GetClientInfo (const QString&) const
	{
		return {};
	}

	void VkChatEntry::MarkMsgsRead ()
	{
		Account_->GetParentProtocol ()->GetAzothProxy ()->MarkMessagesAsRead (this);
	}

	void VkChatEntry::ChatTabClosed ()
	{
	}

	IMUCEntry::MUCFeatures VkChatEntry::GetMUCFeatures () const
	{
		return MUCFCanInvite;
	}

	QString VkChatEntry::GetMUCSubject () const
	{
		return {};
	}

	bool VkChatEntry::CanChangeSubject () const
	{
		return false;
	}

	void VkChatEntry::SetMUCSubject (const QString&)
	{
	}

	QList<QObject*> VkChatEntry::GetParticipants ()
	{
		QList<QObject*> result;
		for (const auto& info : Info_.Users_)
			if (const auto entry = Account_->GetEntry (info.ID_))
				result << entry;
		return result;
	}

	bool VkChatEntry::IsAutojoined () const
	{
		return false;
	}

	void VkChatEntry::Join ()
	{
	}

	void VkChatEntry::Leave (const QString&)
	{
		const auto selfId = Account_->GetSelf ()->GetInfo ().ID_;
		Account_->GetConnection ()->RemoveChatUser (Info_.ChatID_, selfId);
	}

	QString VkChatEntry::GetNick () const
	{
		return Account_->GetOurNick ();
	}

	void VkChatEntry::SetNick (const QString&)
	{
	}

	QString VkChatEntry::GetGroupName () const
	{
		return tr ("Participants of %1").arg (Info_.Title_);
	}

	QString VkChatEntry::GetRealID (QObject*) const
	{
		return {};
	}

	QVariantMap VkChatEntry::GetIdentifyingData () const
	{
		return {};
	}

	void VkChatEntry::InviteToMUC (const QString& userId, const QString&)
	{
		bool ok = false;
		const auto numericId = userId.toULongLong (&ok);

		if (!ok)
		{
			qWarning () << Q_FUNC_INFO
					<< "incorrect user id"
					<< userId;
			return;
		}

		Account_->GetConnection ()->AddChatUser (Info_.ChatID_, numericId);
	}

	void VkChatEntry::handleGotUsers (const QList<UserInfo>& infos)
	{
		for (const auto& info : infos)
			PendingUserInfoRequests_.remove (info.ID_);
	}
}
}
}
