/*  This file is part of the KDE project
    Copyright (C) 2000 David Faure <faure@kde.org>
                  2000 Carsten Pfeiffer <pfeiffer@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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

// Qt includes
#include <qdir.h>
#include <qfile.h>

// KDE includes
#include <kdebug.h>
#include <kfileviewitem.h>
#include <kmdcodec.h>
#include <kstddirs.h>

// Our includes
#include "thumbnailloadjob.moc"

//#define ENABLE_LOG
#ifdef ENABLE_LOG
#define LOG(x) kdDebug() << k_funcinfo << x << endl
#else
#define LOG(x) ;
#endif



const QString& ThumbnailLoadJob::thumbnailDir() {
	static QString dir;
	if (!dir.isEmpty()) return dir;

	KGlobal::dirs()->addResourceType("thumbnails","share/thumbnails/");
	dir = QDir::cleanDirPath( KGlobal::dirs()->resourceDirs("thumbnails")[0] );
	return dir;
}


ThumbnailLoadJob::ThumbnailLoadJob(const KFileViewItemList* itemList,ThumbnailSize size)
: KIO::Job(false), mThumbnailSize(size)
{
	LOG("");

// Look for images and store the items in our todo list
	for (KFileViewItem* item=itemList->getFirst(); item; item=item->next()) {
		mItems.append(item);
	}

	if (mItems.isEmpty()) return;

	QString originalDir=QDir::cleanDirPath( mItems.first()->url().directory() );

// Check if we're already in a cache dir
// In that case the cache dir will be the original dir
/*
	KGlobal::dirs()->addResourceType("thumbnails","share/thumbnails/");
	QString cacheBaseDir = QDir::cleanDirPath( KGlobal::dirs()->resourceDirs("thumbnails")[0] );
*/
	QString cacheBaseDir = thumbnailDir();
	if ( originalDir.startsWith(cacheBaseDir) ) {
		mCacheDir=originalDir;
		return;
	}

// Generate the thumbnail dir name
	HASHHEX hash;
	KMD5 md5( QFile::encodeName(originalDir) );
	md5.hexDigest( hash );
	QString thumbPath = QString::fromLatin1( hash, 4 ) + "/" +
		QString::fromLatin1( &hash[4], 4 ) + "/" +
		QString::fromLatin1( &hash[8] ) + "/";

// Create the thumbnail cache dir
	mCacheDir = locateLocal( "thumbnails", thumbPath + "/" + QString(mThumbnailSize) + "/" );
	LOG("mCacheDir=" << mCacheDir);
}


ThumbnailLoadJob::~ThumbnailLoadJob() {
	LOG("");
}


void ThumbnailLoadJob::start() {
	if (mItems.isEmpty()) {
		LOG("Nothing to do");
		emit result(this);
		delete this;
		return;
	}

	determineNextIcon();
}


//-Internal--------------------------------------------------------------
void ThumbnailLoadJob::itemRemoved(const KFileViewItem* item) {
	mItems.removeRef(item);

	if (item == mCurrentItem) {
		// Abort
		subjobs.first()->kill();
		subjobs.removeFirst();
		determineNextIcon();
	}
}


void ThumbnailLoadJob::determineNextIcon() {
	// No more items ?
	if (mItems.isEmpty()) {
	// Done
		LOG("emitting result");
		emit result(this);
		delete this;
	} else {
	// First, stat the orig file
		mState = STATE_STATORIG;
		mCurrentItem = mItems.first();
		mCurrentURL = mCurrentItem->url();
		KIO::Job* job = KIO::stat(mCurrentURL,false);
		LOG( "KIO::stat orig " << mCurrentURL.url() );
		addSubjob(job);
		mItems.removeFirst();
	}
}


void ThumbnailLoadJob::slotResult(KIO::Job * job) {
	subjobs.remove(job);
	ASSERT(subjobs.isEmpty());	// We should have only one job at a time ...

	switch (mState) {
	case STATE_STATORIG: {
	// Could not stat original, drop this one and move on to the next one
		if (job->error()) {
			determineNextIcon();
			return;
		}

	// Get modification time of the original file
		KIO::UDSEntry entry = static_cast<KIO::StatJob*>(job)->statResult();
		KIO::UDSEntry::ConstIterator it= entry.begin();
		mOriginalTime = 0;
		for (; it!=entry.end(); it++) {
			if ((*it).m_uds == KIO::UDS_MODIFICATION_TIME) {
				mOriginalTime = (time_t)((*it).m_long);
				break;
			}
		}

	// Now stat the thumbnail
		mThumbURL.setPath(mCacheDir + "/" + mCurrentURL.fileName());
		mState = STATE_STATTHUMB;
		KIO::Job * job = KIO::stat(mThumbURL, false);
		LOG("Stat thumb " << mThumbURL.url());
		addSubjob(job);

		return;
	}


	case STATE_STATTHUMB:
	// Try to load this thumbnail - takes care of determineNextIcon
		if (statResultThumbnail(static_cast < KIO::StatJob * >(job)))
			return;

	// Not found or not valid, let's create a thumbnail
		createThumbnail(mCurrentURL.path());
		return;


	case STATE_CREATETHUMB:
	// Thumbnail saved, go on
		determineNextIcon();
		return;
	}
}


bool ThumbnailLoadJob::statResultThumbnail(KIO::StatJob * job) {
// Quit if thumbnail not found
	if (job->error()) return false;

// Get thumbnail modification time
	KIO::UDSEntry entry = job->statResult();
	KIO::UDSEntry::ConstIterator it = entry.begin();
	time_t thumbnailTime = 0;
	for (; it != entry.end(); it++) {
		if ((*it).m_uds == KIO::UDS_MODIFICATION_TIME) {
			thumbnailTime = (time_t) ((*it).m_long);
			break;
		}
	}

// Quit if thumbnail is older than file
	if (thumbnailTime<mOriginalTime) {
		return false;
	}

// Load thumbnail
	QPixmap pix;
	if (!pix.load(mThumbURL.path())) {
		return false;
	}

	emit thumbnailLoaded(mCurrentItem,pix);
	determineNextIcon();
	return true;
}


void ThumbnailLoadJob::createThumbnail(QString pixPath) {
	mState = STATE_CREATETHUMB;
	KURL thumbURL;
	thumbURL.setProtocol("thumbnail");
	thumbURL.setPath(pixPath);
	QString sizeStr=QString::number(mThumbnailSize.pixelSize());

	KIO::TransferJob * job = KIO::get(thumbURL, false, false);
	connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)),
			SLOT(slotThumbData(KIO::Job *, const QByteArray &)));

	job->addMetaData("mimeType", mCurrentItem->mimetype());
	job->addMetaData("iconSize", sizeStr);
	job->addMetaData("width",sizeStr);
	job->addMetaData("height",sizeStr);
	job->addMetaData("extent",sizeStr);
	job->addMetaData("plugin","imagethumbnail");
	addSubjob(job);
}


void ThumbnailLoadJob::slotThumbData(KIO::Job *, const QByteArray& imgData) {
	LOG("");
	QPixmap pix(imgData);
	emit thumbnailLoaded(mCurrentItem,pix);

	QFile file;
	file.setName(mThumbURL.path());
	if (!file.open(IO_WriteOnly)) return;

	file.writeBlock(imgData.data(), imgData.size());
	file.close();
}
