/*
Gwenview: an image viewer
Copyright 2007 Aurélien Gâteau <agateau@kde.org>

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

*/
#include "thumbnailloadjobtest.moc"

// Qt
#include <QDir>
#include <QImage>
#include <QPainter>

// KDE
#include <qtest_kde.h>
#include <kdebug.h>
#include <kio/copyjob.h>
#include <kio/deletejob.h>

// Local
#include "../lib/imageformats/imageformats.h"
#include "../lib/thumbnailloadjob.h"
#include "testutils.h"


using namespace Gwenview;


QTEST_KDEMAIN(ThumbnailLoadJobTest, GUI)


SandBox::SandBox()
: mPath(QDir::currentPath() + "/sandbox")
{}


void SandBox::initDir() {
	KIO::Job* job;
	QDir dir(mPath);
	if (dir.exists()) {
		KUrl sandBoxUrl("file://" + mPath);
		job = KIO::del(sandBoxUrl);
		QVERIFY2(job->exec(), "Couldn't delete sandbox");
	}
	dir.mkpath(".");
}


void SandBox::fill() {
	initDir();
	createTestImage("red.png", 300, 200, Qt::red);
	createTestImage("blue.png", 200, 300, Qt::blue);
	createTestImage("small.png", 50, 50, Qt::green);

	copyTestImage("orient6.jpg", 128, 256);
	copyTestImage("orient6-small.jpg", 32, 64);
}


void SandBox::copyTestImage(const QString& testFileName, int width, int height) {
	KIO::Job* job = KIO::copy(pathForTestFile(testFileName), KUrl(mPath + '/' + testFileName));
	QVERIFY2(job->exec(), "Couldn't copy test image");
	mSizeHash.insert(testFileName, QSize(width, height));
}


static QImage createColoredImage(int width, int height, const QColor& color) {
	QImage image(width, height, QImage::Format_RGB32);
	QPainter painter(&image);
	painter.fillRect(image.rect(), color);
	return image;
}


void SandBox::createTestImage(const QString& name, int width, int height, const QColor& color) {
	QImage image = createColoredImage(width, height, color);
	image.save(mPath + '/' + name, "png");
	mSizeHash.insert(name, QSize(width, height));
}


void ThumbnailLoadJobTest::initTestCase() {
	qRegisterMetaType<KFileItem>("KFileItem");
	Gwenview::ImageFormats::registerPlugins();
}


void ThumbnailLoadJobTest::init() {
	ThumbnailLoadJob::setThumbnailBaseDir(mSandBox.mPath + "/thumbnails/");
	mSandBox.fill();
}


void ThumbnailLoadJobTest::testLoadLocal() {
	QDir dir(mSandBox.mPath);

    // Create a list of items which will be thumbnailed
	KFileItemList list;
	Q_FOREACH(const QFileInfo& info, dir.entryInfoList(QDir::Files)) {
		KUrl url("file://" + info.absoluteFilePath());
		KFileItem item(KFileItem::Unknown, KFileItem::Unknown, url);
		list << item;
	}

    // Generate the thumbnails
	QPointer<ThumbnailLoadJob> job = new ThumbnailLoadJob(list, ThumbnailGroup::Normal);
	QSignalSpy spy(job, SIGNAL(thumbnailLoaded(KFileItem,QPixmap,QSize)));
	// FIXME: job->exec() causes a double free(), so wait for the job to be
	// deleted instead
	//job->exec();
	job->start();
	while (job) {
		QTest::qWait(100);
	}

	while (!ThumbnailLoadJob::isPendingThumbnailCacheEmpty()) {
		QTest::qWait(100);
	}

    // Check we generated the correct number of thumbnails
	QDir thumbnailDir = ThumbnailLoadJob::thumbnailBaseDir(ThumbnailGroup::Normal);
	// There should be one file less because small.png is a png and is too
	// small to have a thumbnail
	QStringList entryList = thumbnailDir.entryList(QStringList("*.png"));
	QCOMPARE(entryList.count(), mSandBox.mSizeHash.size() - 1);

	// Check what was in the thumbnailLoaded() signals
	QCOMPARE(spy.count(), mSandBox.mSizeHash.size());
	QSignalSpy::ConstIterator it = spy.constBegin(),
		end = spy.constEnd();
	for (;it != end; ++it) {
		const QVariantList args = *it;
		const KFileItem item = qvariant_cast<KFileItem>(args.at(0));
		const QSize size = args.at(2).toSize();
		const QSize expectedSize = mSandBox.mSizeHash.value(item.url().fileName());
		QCOMPARE(size, expectedSize);
	}
}


void ThumbnailLoadJobTest::testUseEmbeddedOrNot() {
	QImage expectedThumbnail;
	QPointer<ThumbnailLoadJob> job;
	QPixmap thumbnailPix;
	SandBox sandBox;
	sandBox.initDir();
	// This image is red and 256x128 but contains a white 128x64 thumbnail
	sandBox.copyTestImage("embedded-thumbnail.jpg", 256, 128);

	KFileItemList list;
	KUrl url("file://" + QDir(sandBox.mPath).absoluteFilePath("embedded-thumbnail.jpg"));
	list << KFileItem(KFileItem::Unknown, KFileItem::Unknown, url);

	// Loading a normal thumbnail should bring the white one
	job = new ThumbnailLoadJob(list, ThumbnailGroup::Normal);
	QSignalSpy spy1(job, SIGNAL(thumbnailLoaded(KFileItem,QPixmap,QSize)));
	// FIXME: job->exec() causes a double free(), so wait for the job to be
	// deleted instead
	//job->exec();
	job->start();
	while (job) {
		QTest::qWait(100);
	}

	QCOMPARE(spy1.count(), 1);
	expectedThumbnail = createColoredImage(128, 64, Qt::white);
	thumbnailPix = qvariant_cast<QPixmap>(spy1.at(0).at(1));
	fuzzyImageCompare(expectedThumbnail, thumbnailPix.toImage());

	// Loading a large thumbnail should bring the red one
	job = new ThumbnailLoadJob(list, ThumbnailGroup::Large);
	QSignalSpy spy2(job, SIGNAL(thumbnailLoaded(KFileItem,QPixmap,QSize)));
	job->start();
	while (job) {
		QTest::qWait(100);
	}

	QCOMPARE(spy2.count(), 1);
	expectedThumbnail = createColoredImage(256, 128, Qt::red);
	thumbnailPix = qvariant_cast<QPixmap>(spy2.at(0).at(1));
	fuzzyImageCompare(expectedThumbnail, thumbnailPix.toImage());
}


void ThumbnailLoadJobTest::testLoadRemote() {
	KUrl url = setUpRemoteTestDir("test.png");
	if (!url.isValid()) {
		return;
	}
	url.addPath("test.png");

	KFileItemList list;
	KFileItem item(KFileItem::Unknown, KFileItem::Unknown, url);
	list << item;

	QPointer<ThumbnailLoadJob> job = new ThumbnailLoadJob(list, ThumbnailGroup::Normal);
	// FIXME: job->exec() causes a double free(), so wait for the job to be
	// deleted instead
	//job->exec();
	job->start();
	while (job) {
		QTest::qWait(100);
	}
	while (!ThumbnailLoadJob::isPendingThumbnailCacheEmpty()) {
		QTest::qWait(100);
	}

	QDir thumbnailDir = ThumbnailLoadJob::thumbnailBaseDir(ThumbnailGroup::Normal);
	QStringList entryList = thumbnailDir.entryList(QStringList("*.png"));
	QCOMPARE(entryList.count(), 1);
}
