/**********************************************************************
 * 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 "resourcesmanager.h"
#include <QIcon>
#include <QtDebug>
#include <util/sys/resourceloader.h>
#include "xmlsettingsmanager.h"
#include "interfaces/azoth/iclentry.h"

namespace LeechCraft
{
namespace Azoth
{
	ResourcesManager::ResourcesManager ()
	{
		ResourceLoaders_ [RLTStatusIconLoader].reset (new Util::ResourceLoader ("azoth/iconsets/contactlist/", this));
		ResourceLoaders_ [RLTClientIconLoader].reset (new Util::ResourceLoader ("azoth/iconsets/clients/", this));
		ResourceLoaders_ [RLTAffIconLoader].reset (new Util::ResourceLoader ("azoth/iconsets/affiliations/", this));
		ResourceLoaders_ [RLTSystemIconLoader].reset (new Util::ResourceLoader ("azoth/iconsets/system/", this));
		ResourceLoaders_ [RLTActivityIconLoader].reset (new Util::ResourceLoader ("azoth/iconsets/activities/", this));
		ResourceLoaders_ [RLTMoodIconLoader].reset (new Util::ResourceLoader ("azoth/iconsets/moods/", this));

		for (const auto& rl : ResourceLoaders_)
		{
			rl->AddLocalPrefix ();
			rl->AddGlobalPrefix ();

			rl->SetCacheParams (1000, 0);
		}
	}

	ResourcesManager& ResourcesManager::Instance ()
	{
		static ResourcesManager rm;
		return rm;
	}

	Util::ResourceLoader* ResourcesManager::GetResourceLoader (LoaderType type) const
	{
		return ResourceLoaders_ [type].get ();
	}

	void ResourcesManager::HandleEntry (ICLEntry *clEntry)
	{
		connect (clEntry->GetQObject (),
				SIGNAL (availableVariantsChanged (const QStringList&)),
				this,
				SLOT (invalidateClientsIconCache ()));
		connect (clEntry->GetQObject (),
				SIGNAL (statusChanged (EntryStatus, QString)),
				this,
				SLOT (invalidateClientsIconCache ()));
		connect (clEntry->GetQObject (),
				SIGNAL (entryGenerallyChanged ()),
				this,
				SLOT (invalidateClientsIconCache ()));
	}

	void ResourcesManager::HandleRemoved (ICLEntry *entry)
	{
		EntryClientIconCache_.remove (entry);
		invalidateClientsIconCache (entry->GetQObject ());
	}

	namespace
	{
		QString GetStateIconFilename (State state)
		{
			QString iconName;
			switch (state)
			{
			case SOnline:
				iconName = "online";
				break;
			case SChat:
				iconName = "chatty";
				break;
			case SAway:
				iconName = "away";
				break;
			case SDND:
				iconName = "dnd";
				break;
			case SXA:
				iconName = "xa";
				break;
			case SOffline:
				iconName = "offline";
				break;
			case SConnecting:
				iconName = "connect";
				break;
			default:
				iconName = "perr";
				break;
			}

			QString filename = XmlSettingsManager::Instance ()
					.property ("StatusIcons").toString ();
			filename += '/';
			filename += iconName;

			return filename;
		}
	}

	Util::QIODevice_ptr ResourcesManager::GetIconPathForState (State state) const
	{
		const QString& filename = GetStateIconFilename (state);
		return ResourceLoaders_ [RLTStatusIconLoader]->GetIconDevice (filename, true);
	}

	QIcon ResourcesManager::GetIconForState (State state) const
	{
		const QString& filename = GetStateIconFilename (state);
		return ResourceLoaders_ [RLTStatusIconLoader]->LoadPixmap (filename);
	}

	QIcon ResourcesManager::GetAffIcon (const QByteArray& affName) const
	{
		QString filename = XmlSettingsManager::Instance ()
				.property ("AffIcons").toString ();
		filename += '/';
		filename += affName;

		return QIcon (ResourceLoaders_ [RLTAffIconLoader]->LoadPixmap (filename));
	}

	QMap<QString, QIcon> ResourcesManager::GetClientIconForEntry (ICLEntry *entry)
	{
		if (EntryClientIconCache_.contains (entry))
			return EntryClientIconCache_ [entry];

		QMap<QString, QIcon> result;

		const auto& pack = XmlSettingsManager::Instance ()
					.property ("ClientIcons").toString () + '/';
		for (const auto& variant : entry->Variants ())
		{
			const auto& info = entry->GetClientInfo (variant);
			if (info.contains ("client_image"))
			{
				const auto& image = info ["client_image"].value<QImage> ();
				result [variant] = QIcon (QPixmap::fromImage (image));
			}
			else
			{
				const auto& type = info ["client_type"].toString ();

				const auto& filename = pack + type;

				auto pixmap = ResourceLoaders_ [RLTClientIconLoader]->LoadPixmap (filename);
				if (pixmap.isNull ())
					pixmap = ResourceLoaders_ [RLTClientIconLoader]->LoadPixmap (pack + "unknown");

				result [variant] = QIcon (pixmap);
			}
		}

		EntryClientIconCache_ [entry] = result;
		return result;
	}

	QImage ResourcesManager::GetDefaultAvatar (int size) const
	{
		const auto& name = XmlSettingsManager::Instance ()
				.property ("SystemIcons").toString () + "/default_avatar";
		const auto& image = ResourceLoaders_ [RLTSystemIconLoader]->LoadPixmap (name).toImage ();

		if (image.isNull ())
			return {};

		if (size == -1)
			return image;

		return image.scaled (size, size,
				Qt::KeepAspectRatio, Qt::SmoothTransformation);
	}

	void ResourcesManager::invalidateClientsIconCache (QObject *passedObj)
	{
		QObject *obj = passedObj ? passedObj : sender ();
		ICLEntry *entry = qobject_cast<ICLEntry*> (obj);
		if (!entry)
		{
			qWarning () << Q_FUNC_INFO
					<< obj
					<< "could not be casted to ICLEntry";
			return;
		}

		invalidateClientsIconCache (entry);
	}

	void ResourcesManager::invalidateClientsIconCache (ICLEntry *entry)
	{
		EntryClientIconCache_.remove (entry);
	}

	void ResourcesManager::flushIconCaches ()
	{
		for (const auto& rl : ResourceLoaders_)
			rl->FlushCache ();
	}
}
}
