/***************************************************************************
 *   Copyright (C) 2007 by Kai Winter   *
 *   kaiwinter@gmx.de   *
 *                                                                         *
 *   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.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "imagemanager.h"
#include "Preferences/MerkaartorPreferences.h"
#include "IMapAdapter.h"

#include <QDateTime>
#include <QCryptographicHash>

ImageManager* ImageManager::m_ImageManagerInstance = 0;

ImageManager::ImageManager(QObject* parent)
    :QObject(parent), emptyPixmap(QPixmap(1,1)), net(new MapNetwork(this))
{
    emptyPixmap.fill(Qt::transparent);

#ifndef _MOBILE
    m_dataCache.setMaxCost(20000000); // 20mb
#else
    m_dataCache.setMaxCost(2000000); // 2mb
#endif
}

ImageManager::~ImageManager()
{
    net->abortLoading();
    delete net;
}

QByteArray ImageManager::getData(IMapAdapter* anAdapter, QString url)
{
    QString host = anAdapter->getHost();
    QString strHash = QString("%1%2").arg(anAdapter->getName()).arg(url);
    QString hash = QString(strHash.toAscii().toBase64());
    if (hash.size() > 255) {
        QCryptographicHash crypt(QCryptographicHash::Md5);
        crypt.addData(hash.toLatin1());
        hash = QString(crypt.result().toHex());
    }

    QByteArray ba;
    if (m_dataCache.contains(hash)) {
        ba = *m_dataCache.object(hash);
        return ba;
    }

    // currently loading?
    if (!net->isLoading(hash))
    {
        // load from net, add empty image
        net->load(hash, host, url);
        emit(dataRequested());
        return ba;
    }
    return ba;
}

QPixmap ImageManager::getPixmap(IMapAdapter* anAdapter, int x, int y, int z)
{
//    QSize ts(anAdapter->getTileSize(), anAdapter->getTileSize());
//    if (emptyPixmap.size() != ts) {
//        emptyPixmap = QPixmap(ts);
//        emptyPixmap.fill(Qt::transparent);
//    }
    QString url = anAdapter->getQuery(x, y, z);
    return getPixmap(anAdapter, url);
}

QPixmap ImageManager::getPixmap(IMapAdapter* anAdapter, QString url)
{
// 	qDebug() << "ImageManager::getImage";

    QString host = anAdapter->getHost();
    QString strHash = QString("%1%2").arg(anAdapter->getName()).arg(url);
    QString hash = QString(strHash.toAscii().toBase64());
    if (hash.size() > 255) {
        QCryptographicHash crypt(QCryptographicHash::Md5);
        crypt.addData(hash.toLatin1());
        hash = QString(crypt.result().toHex());
    }

    /*	QPixmap pm(anAdapter->getTileSize(), anAdapter->getTileSize());
        pm.fill(Qt::black);*/
    //	QPixmap pm(emptyPixmap);
    QPixmap pm;

    // is image in picture cache
    if (m_dataCache.contains(hash)) {
        pm.loadFromData(*m_dataCache.object(hash));
        return pm;
    }

    // disk cache?
    if (anAdapter->isTiled() && useDiskCache(hash + ".png")) {
        if (pm.load(cacheDir.absolutePath() + "/" + hash + ".png")) {
            return pm;
        }
    }

    if (M_PREFS->getOfflineMode())
        return pm;

    // currently loading?
    if (!net->isLoading(hash))
    {
        // load from net, add empty image
        net->load(hash, host, url);
        emit(dataRequested());
        return pm;
    }
    return pm;
}

//QPixmap ImageManager::prefetchImage(const QString& host, const QString& url)
QPixmap ImageManager::prefetchPixmap(IMapAdapter* anAdapter, int x, int y, int z)
{
    QString host = anAdapter->getHost();
    QString url = anAdapter->getQuery(x, y, z);
    QString strHash = QString("%1%2").arg(anAdapter->getName()).arg(url);
    QString hash = QString(strHash.toAscii().toBase64());

    prefetch.append(hash);
    return getPixmap(anAdapter, x, y, z);
}

void ImageManager::receivedData(const QByteArray& ba, const QString& hash)
{
// 	qDebug() << "ImageManager::receivedImage";

    QByteArray* a = new QByteArray(ba);
    m_dataCache.insert(hash, a, a->size());
    if (cacheMaxSize || cachePermanent) {
        QPixmap pixmap;
        pixmap.loadFromData(ba);

        if (!pixmap.isNull()) {
            pixmap.save(cacheDir.absolutePath() + "/" + hash + ".png");
            QFileInfo info(cacheDir.absolutePath() + "/" + hash + ".png");
            cacheInfo.append(info);
            cacheSize += info.size();

            adaptCache();
        }
    }

    if (prefetch.contains(hash))
    {
        prefetch.removeAt(prefetch.indexOf(hash));
    }
    emit(dataReceived());
}

void ImageManager::loadingQueueEmpty()
{
    emit(loadingFinished());
// 	((Layer*)this->parent())->removeZoomImage();
// 	qDebug() << "size of image-map: " << images.size();
// 	qDebug() << "size: " << QPixmapCache::cacheLimit();
}

void ImageManager::abortLoading()
{
    net->abortLoading();
    loadingQueueEmpty();
}

void ImageManager::setCacheDir(const QDir& path)
{
    cacheDir = path;
    cacheSize = 0;
    if (!cacheDir.exists()) {
        cacheDir.mkpath(cacheDir.absolutePath());
    } else {
        cacheInfo = cacheDir.entryInfoList(QDir::Files, QDir::Time | QDir::Reversed);
        for (int i=0; i<cacheInfo.size(); i++) {
            cacheSize += cacheInfo[i].size();
        }
    }
}

QDir ImageManager::getCacheDir()
{
    return cacheDir;
}

void ImageManager::setCacheMaxSize(int max)
{
    cacheMaxSize = max*1024*1024;
}
