#include "mapview.h"
#include "osm_downloader_p.h"
#include "osm_tile_cache_p.h"


OSMDownloader::OSMDownloader(MapView * p): QThread() {
	qRegisterMetaType<OSM::TileIndex>();
	nam      = new QNetworkAccessManager();
	parent   = p;
	provider = "http://tile.openstreetmap.org";
	start();
}


OSMDownloader::~OSMDownloader() {
	requestInterruption();
	cond.wakeAll();
	wait();
	delete nam;
}


bool OSMDownloader::queueTile(OSM::TileIndex index, bool force) {
	// auto hash = tile.hash();
	bool ret = false;
	cond_mutex.lock();
	if ((!queue.contains(index) && !in_progress.contains(index.hash())) || force) {
		queue.enqueue(index);
		cond.wakeOne();
		ret = true;
	}
	cond_mutex.unlock();
	return ret;
}


void OSMDownloader::queueTiles(QList<OSM::TileIndex> indeces) {
	cond_mutex.lock();
	queue << indeces;
	cond.wakeOne();
	cond_mutex.unlock();
}


void OSMDownloader::clearQueue() {
	cond_mutex.lock();
	queue.clear();
	cond_mutex.unlock();
}


void OSMDownloader::requestTile(OSM::TileIndex index) {
	QNetworkRequest req(provider + QString("/%1/%2/%3.png").arg(index.z).arg(index.x).arg(index.y));
	req.setHeader(QNetworkRequest::UserAgentHeader, "Qt/5");
	auto * r = nam->get(req);
	if (!r) return;
	connect(r, &QNetworkReply::finished, this, [this, r, index]() {
		r->deleteLater();
		if (r->error() != QNetworkReply::NoError) {
			qDebug() << "Error:" << r->error();
		} else {
			QByteArray data = r->readAll();
			if (!data.isEmpty()) {
				QPixmap tim;
				tim.loadFromData(data, "png");
				if (!tim.isNull()) parent->cache->tileDownloaded(index, tim);
			}
		}
		cond_mutex.lock();
		in_progress.remove(index.hash());
		cond_mutex.unlock();
		emit tileDone();
	});
}


void OSMDownloader::run() {
	while (!isInterruptionRequested()) {
		cond_mutex.lock();
		if (queue.isEmpty())
			cond.wait(&cond_mutex);
		else {
			auto t = queue.dequeue();
			in_progress.insert(t.hash());
			QMetaObject::invokeMethod(
				parent,
				[this, t]() { requestTile(t); },
				Qt::QueuedConnection);
		}
		cond_mutex.unlock();
	}
}
