/***************************** LICENSE START ***********************************

 Copyright 2016 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include "MvQFileDialog.h"

#include <QtGlobal>
#include <MvQFileInfo.h>
#include <QDir>
#include <QFileSystemModel>
#include <QSettings>
#include <QUrl>

#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
#include <QStandardPaths>
#else
#include <QDesktopServices>
#endif
#ifdef METVIEW
#include "MvApplication.h"
#endif

#include "MvMiscellaneous.h"
#include "MvQPixmapCache.h"
#include "MvQMethods.h"
#include "MvLog.h"
#include "MvQStreamOper.h"

//===========================
// MvQFileIconProvider
//===========================

MvQFileIconProvider::MvQFileIconProvider()
{
    if (char* iconHome = getenv("METVIEW_DIR_SHARE")) {
        path_ = QString(iconHome);
        path_.append("/icons/");
    }

    pixCache_ = new MvQPixmapCache(QPixmap());

    char* mv = getenv("METVIEW_USER_DIRECTORY");
    if (mv)
        mvHome_ = QString(mv);
}

QIcon MvQFileIconProvider::icon(const QFileInfo& info) const
{
#ifdef METVIEW
    if (info.isDir() && !path_.isEmpty()) {
        QString pixName = "FOLDER";

        if (!mvHome_.isEmpty() && info.filePath() == mvHome_) {
            pixName = "HOME";
        }

        QPixmap pix = pixCache_->pixmap(pixName);
        if (pix.isNull()) {
            pix = QPixmap(path_ + pixName + ".svg");
            if (!pix.isNull())
                pixCache_->add(pixName, pix);
        }

        return QIcon(pix);
    }
#endif
    return QFileIconProvider::icon(info);
}

//===========================
// MvQFileDialogFilterModel
//===========================

MvQFileDialogFilterModel::MvQFileDialogFilterModel(QObject* parent) :
    QSortFilterProxyModel(parent)
{
}

bool MvQFileDialogFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
{
    QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
    auto* fsModel = qobject_cast<QFileSystemModel*>(sourceModel());

    if (!fsModel)
        return false;

    QString fileName = fsModel->fileName(index);

    if (fsModel->isDir(index)) {
        if (fileName.endsWith("#") == false)
            return true;
        else
            return false;
    }

    if (fileName.startsWith(".") == false &&
        fileName.startsWith("..") == false) {
        return true;
    }

    return false;
}

bool MvQFileDialogFilterModel::lessThan(const QModelIndex& left, const QModelIndex& right) const
{
    auto* fsModel = qobject_cast<QFileSystemModel*>(sourceModel());

    if (!fsModel)
        return false;

    if (fsModel->isDir(right)) {
        if (!fsModel->isDir(left))
            return false;
    }
    else {
        if (fsModel->isDir(left))
            return true;
    }

    return QSortFilterProxyModel::lessThan(left, right);
}

//===========================
// MvQFileDialog
//===========================

MvQFileDialog::MvQFileDialog(QString startDir, QString title, QWidget* parent) :
    QFileDialog(parent)
{
    setWindowTitle(title);

    setOptions(QFileDialog::DontUseNativeDialog);

    // url sidebar
    MvQFileDialog::updateSidebar(this, startDir);

    // Filter model
    auto* proxy = new MvQFileDialogFilterModel(this);
    setProxyModel(proxy);

    // Dir
    MvQFileDialog::initTargetDir(this, startDir);

#ifdef METVIEW
    // Icons
    auto* iconProvider = new MvQFileIconProvider;
    setIconProvider(iconProvider);
#endif

    readSettings();
}

MvQFileDialog::~MvQFileDialog()
{
    writeSettings();
}

void MvQFileDialog::updateSidebar(QFileDialog* dg, QString startDir)
{
    Q_ASSERT(dg);

    QList<QUrl> urlLst;

    urlLst << QUrl::fromLocalFile(QDir::rootPath());
    Q_FOREACH (QString s, QStandardPaths::standardLocations(QStandardPaths::HomeLocation)) {
        urlLst << QUrl::fromLocalFile(s);
    }

#ifdef METVIEW
    if (char* mvDir = getenv("METVIEW_USER_DIRECTORY")) {
        urlLst << QUrl::fromLocalFile(QString(mvDir));
    }
#endif
    if (char* scratchDir = getenv("SCRATCH")) {
        urlLst << QUrl::fromLocalFile(QString(scratchDir));
    }


    auto startUrl = QUrl::fromLocalFile(startDir);
    auto prevFile = MvQFileDialog::readLastGlobalSavedFile();
    QFileInfo fInfo(prevFile);
    auto prevUrl = QUrl::fromLocalFile((fInfo.isDir() ? prevFile : fInfo.absoluteDir().path()));

    if (!urlLst.contains(startUrl)) {
        urlLst << startUrl;
    }

    if (!urlLst.contains(prevUrl)) {
        urlLst << prevUrl;
    }

    dg->setSidebarUrls(urlLst);
}

void MvQFileDialog::readSettings()
{
    QSettings settings(MVQ_QSETTINGS_DEFAULT_ARGS, "MV-FileDialog");

    settings.beginGroup("main");
    if (settings.contains("size")) {
        resize(settings.value("size").toSize());
    }
    else {
        resize(QSize(500, 360));
    }

    settings.endGroup();
}

void MvQFileDialog::writeSettings()
{
    MvQFileDialog::writeLastGlobalSavedFile(this);
    QSettings settings(MVQ_QSETTINGS_DEFAULT_ARGS, "MV-FileDialog");
    settings.clear();
    settings.beginGroup("main");
    settings.setValue("size", size());
    settings.endGroup();
}


bool MvQFileDialog::useTargetDirFromConfig()
{
#ifdef METVIEW
    return MvApplication::saveAsFolderTarget() == MvApplication::PreviousFolderTarget;
#endif
    return false;
}

void MvQFileDialog::initTargetFile(QFileDialog* dg, QString startDir)
{
    Q_ASSERT(dg);
    QString lastFile;
    if (MvQFileDialog::useTargetDirFromConfig()) {
        lastFile = MvQFileDialog::readLastGlobalSavedFile();
    }
    //    MvLog().info() << MV_FN_INFO << "lastFile=" << lastFile;
    if (!lastFile.isEmpty()) {
        QFileInfo fInfo(lastFile);
        if (fInfo.isDir()) {
            dg->setDirectory(lastFile);
        }
        else {
            dg->selectFile(lastFile);
        }
    }
    else {
        QString rDir;
#ifdef METVIEW
        rDir = QString::fromStdString(metview::metviewRootDir());
#endif
        //        MvLog().info() << "  dir=" << ((!startDir.isEmpty())?startDir:rDir);
        dg->setDirectory((!startDir.isEmpty()) ? startDir : rDir);
    }
}

void MvQFileDialog::initTargetDir(QFileDialog* dg, QString startDir)
{
    Q_ASSERT(dg);
    QString lastFile;
    if (MvQFileDialog::useTargetDirFromConfig()) {
        lastFile = MvQFileDialog::readLastGlobalSavedFile();
    }
    if (!lastFile.isEmpty()) {
        QFileInfo fInfo(lastFile);
        dg->setDirectory((fInfo.isDir() ? lastFile : fInfo.absoluteDir().path()));
    }
    else {
        QString rDir;
#ifdef METVIEW
        rDir = QString::fromStdString(metview::metviewRootDir());
#endif
        dg->setDirectory((!startDir.isEmpty()) ? startDir : rDir);
    }
}

QString MvQFileDialog::readLastGlobalSavedFile()
{
    QSettings settings(MVQ_QSETTINGS_DEFAULT_ARGS, "MV-lastSavedFileInDialog");
    auto f = settings.value("fileName").toString();
    //    MvLog().info() << MV_FN_INFO << "fileName=" << f;
    return f;
}

void MvQFileDialog::writeLastGlobalSavedFile(QFileDialog* dg)
{
    Q_ASSERT(dg);
    QStringList lst = dg->selectedFiles();
    //    MvLog().info() << MV_FN_INFO << "fileName=" << lst;
    if (lst.size() > 0 && !lst[0].isEmpty()) {
        QSettings settings(MVQ_QSETTINGS_DEFAULT_ARGS, "MV-lastSavedFileInDialog");
        settings.clear();
        settings.setValue("fileName", lst[0]);
    }
}
