#include <noatun/downloader.h>
#include <noatun/app.h>
#include <assert.h>
#include <qfile.h>
#include <qtimer.h>
#include <job.h>
#include <klocale.h>

DownloadItem::DownloadItem()
{

}

DownloadItem::~DownloadItem()
{
	dequeue();
}

bool DownloadItem::isDownloaded() const
{
	return true;
}

QString DownloadItem::localFilename() const
{
	return mLocalFilename;
}

void DownloadItem::setLocalFilename(const QString &filename)
{
	mLocalFilename=filename;
}

void DownloadItem::downloadFinished()
{
}

void DownloadItem::downloaded(int )
{
}

void DownloadItem::downloadTimeout()
{
}

bool DownloadItem::enqueue(const KURL &url)
{
	if (url.isLocalFile())
	{
		setLocalFilename(url.path());
		return false;
	}
	else
	{
		napp->downloader()->enqueue(this, url);
		return true;
	}
}

void DownloadItem::dequeue()
{
	napp->downloader()->dequeue(this);
}




Downloader::Downloader(QObject *parent)
	: QObject(parent), localfile(0), current(0), mJob(0), mTimeout(0)
{
	mStarted=false;
	mUnstartedQueue=new QPtrList<Downloader::QueueItem>;
}

Downloader::~Downloader()
{

}

void Downloader::start()
{
	assert(!mStarted);
	mStarted=true;
	if (current)
		emit enqueued(current->notifier, current->file);

	for (QPtrListIterator<Downloader::QueueItem> i(*mUnstartedQueue); i.current(); ++i)
	{
		(*i)->notifier->mLocalFilename = (*i)->local;
		mQueue.append(*i);
		emit enqueued((*i)->notifier, (*i)->file);
	}
	
	delete mUnstartedQueue;
	mUnstartedQueue=0;
	QTimer::singleShot(0, this, SLOT(getNext()));
}

static QString nonExistantFile(const QString &file)
{
	if (file.right(1)=="/") return i18n("Unknown");
	int i=0;
	QString f(file);
	while (QFile(f).exists())
	{
		i++;
		f=file;
		f.insert(f.findRev('.'), '_'+QString::number(i));
	}
	return f;
}

QString Downloader::enqueue(DownloadItem *notifier, const KURL &file)
{
	if (file.isLocalFile()) return 0;
	QueueItem *i=new QueueItem;
	i->notifier=notifier;
	i->file=file;
	
	if (!mStarted)
	{
		i->local=notifier->mLocalFilename;
		if (!notifier->localFilename().length())
		{
			i->local = 
				nonExistantFile(napp->saveDirectory()+'/'+file.fileName());
		}
		mUnstartedQueue->append(i);
		return i->local;
	}
	
	
	if (!notifier->localFilename().length())
	{
		notifier->mLocalFilename=
			i->local =
				nonExistantFile(napp->saveDirectory()+'/'+file.fileName());
	}
	else
	{
		i->local = notifier->mLocalFilename;
	}

	mQueue.append(i);
	QTimer::singleShot(0, this, SLOT(getNext()));
	emit enqueued(notifier, file);
	return i->local;
}

void Downloader::dequeue(DownloadItem *notifier)
{
	if (current && notifier==current->notifier)
	{
		mJob->kill();
		jobDone(mJob);
		return;
	}
	for (QPtrListIterator<Downloader::QueueItem> i(mQueue); i.current(); ++i)
	{
		if ((*i)->notifier==notifier)
		{
			mQueue.removeRef(*i);
			if (mStarted)
				emit dequeued(notifier);
			delete *i;
		}
	}
}

void Downloader::getNext()
{
	if (current) return;
	if (!mStarted) return;

	current=mQueue.take(0);
	if (!current)
		return;

	// open the QFile
	localfile=new QFile(current->local);
	localfile->open(IO_ReadWrite | IO_Append);

	mJob= KIO::get(current->file, true, false);
	connect(mJob, SIGNAL(data(KIO::Job*, const QByteArray&)), SLOT(data(KIO::Job*, const QByteArray&)));

	connect(mJob, SIGNAL(percent(KIO::Job*, unsigned long)), SLOT(percent(KIO::Job*, unsigned long)));

	if (mTimeout)
		delete mTimeout;
	mTimeout=new QTimer(this);
	mTimeout->start(30000, true);
	connect(mTimeout, SIGNAL(timeout()), SLOT(giveUpWithThisDownloadServerIsRunningNT()));
}

void Downloader::data(KIO::Job *j, const QByteArray &data)
{
	if (!data.size())
	{ // file is done downloading
		jobDone(j);
		delete mTimeout;
		mTimeout=0;
		return;
	}
	localfile->writeBlock(data);
	localfile->flush();
	delete mTimeout;
	mTimeout=0;
}

void Downloader::jobDone(KIO::Job *)
{
	current->notifier->downloadFinished();
	if (mStarted)
		emit dequeued(current->notifier);
	delete current;
	current=0;
	mJob=0;
	getNext();
}

void Downloader::giveUpWithThisDownloadServerIsRunningNT()
{
	delete mTimeout;
	mTimeout=0;
	if (!current) return;
	DownloadItem *old=current->notifier;
	if (!old) return;	
	old->downloadTimeout();
	current=0;
	mJob=0;
	delete old;
	getNext();
}

void Downloader::percent( KIO::Job *, unsigned long percent)
{
	if (current && current->notifier)
		current->notifier->downloaded((int)percent);
}

#include "noatun/downloader.moc"

