#include "PathsDialog.hxx"
#include "ui_PathsDialog.h"

#include <QSettings>
#include <QFileDialog>
#include <QMessageBox>
#include <QDebug>
#include <QProcess>

#include "CatalogListModel.hxx"
#include "AddCatalogDialog.hxx"
#include "AircraftModel.hxx"
#include "InstallSceneryDialog.hxx"
#include "QtLauncher.hxx"
#include "LocalAircraftCache.hxx"

#include <Main/options.hxx>
#include <Main/globals.hxx>
#include <Network/HTTPClient.hxx>

AddOnsPage::AddOnsPage(QWidget *parent, simgear::pkg::RootRef root) :
    QWidget(parent),
    m_ui(new Ui::AddOnsPage),
    m_packageRoot(root)
{
    m_ui->setupUi(this);
    
    m_catalogsModel = new CatalogListModel(this, m_packageRoot);
    m_ui->catalogsList->setModel(m_catalogsModel);

 // enable drag-drop to re-order the paths
    m_ui->sceneryPathsList->setDragEnabled(true);
    m_ui->sceneryPathsList->setDragDropMode(QAbstractItemView::InternalMove);
    m_ui->sceneryPathsList->setDropIndicatorShown(true);

    m_ui->aircraftPathsList->setDragEnabled(true);
    m_ui->aircraftPathsList->setDragDropMode(QAbstractItemView::InternalMove);
    m_ui->aircraftPathsList->setDropIndicatorShown(true);

    connect(m_ui->addCatalog, &QToolButton::clicked,
            this, &AddOnsPage::onAddCatalog);
    connect(m_ui->addDefaultCatalogButton, &QPushButton::clicked,
            this, &AddOnsPage::onAddDefaultCatalog);
    connect(m_ui->removeCatalog, &QToolButton::clicked,
            this, &AddOnsPage::onRemoveCatalog);
            
    connect(m_ui->addSceneryPath, &QToolButton::clicked,
            this, &AddOnsPage::onAddSceneryPath);
    connect(m_ui->removeSceneryPath, &QToolButton::clicked,
            this, &AddOnsPage::onRemoveSceneryPath);

    connect(m_ui->addAircraftPath, &QToolButton::clicked,
            this, &AddOnsPage::onAddAircraftPath);
    connect(m_ui->removeAircraftPath, &QToolButton::clicked,
            this, &AddOnsPage::onRemoveAircraftPath);

    connect(m_ui->installSceneryButton, &QPushButton::clicked,
            this, &AddOnsPage::onInstallScenery);

    m_ui->sceneryPathsList->setToolTip(
      tr("After changing this list, please restart the launcher to avoid "
         "possibly inconsistent behavior."));
    m_ui->installSceneryButton->setToolTip(
      tr("After installing scenery, you may have to restart the launcher "
         "to avoid inconsistent behavior."));

    QSettings settings;
            
    QStringList sceneryPaths = settings.value("scenery-paths").toStringList();
    m_ui->sceneryPathsList->addItems(sceneryPaths);

    connect(m_ui->sceneryPathsList->model(), &QAbstractItemModel::rowsMoved,
            this, &AddOnsPage::saveSceneryPaths);

    QStringList aircraftPaths = settings.value("aircraft-paths").toStringList();
    m_ui->aircraftPathsList->addItems(aircraftPaths);

    connect(m_ui->aircraftPathsList->model(), &QAbstractItemModel::rowsMoved,
            this, &AddOnsPage::saveAircraftPaths);

    updateUi();
}

AddOnsPage::~AddOnsPage()
{
    delete m_ui;
}

void AddOnsPage::onAddSceneryPath()
{
    QString path = QFileDialog::getExistingDirectory(this, tr("Choose scenery folder"));
    if (!path.isEmpty()) {
        // validation

        SGPath p(path.toStdString());
        bool isValid = false;

        for (const auto& dir: {"Objects", "Terrain", "Buildings", "Roads",
                               "Pylons", "NavData"}) {
            if ((p / dir).exists()) {
                isValid = true;
                break;
            }
        }

        if (!isValid) {
            QMessageBox mb;
            mb.setText(tr("The folder '%1' doesn't appear to contain scenery - add anyway?").arg(path));
            mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
            mb.setDefaultButton(QMessageBox::No);
            mb.setInformativeText(tr("Added scenery should contain at least one of the following "
                "folders: Objects, Terrain, Buildings, Roads, Pylons, NavData."));
            mb.exec();

            if (mb.result() == QMessageBox::No) {
                return;
            }
        }

        m_ui->sceneryPathsList->addItem(path);
        saveSceneryPaths();
    }
}

void AddOnsPage::onRemoveSceneryPath()
{
    if (m_ui->sceneryPathsList->currentItem()) {
        delete m_ui->sceneryPathsList->currentItem();
        saveSceneryPaths();
    }
}

void AddOnsPage::onAddAircraftPath()
{
    QString path = QFileDialog::getExistingDirectory(this, tr("Choose aircraft folder"));
    if (!path.isEmpty()) {
        // the user might add a directory containing an 'Aircraft' subdir. Let's attempt
        // to check for that case and handle it gracefully.
        bool pathOk = false;

        if (LocalAircraftCache::isCandidateAircraftPath(path)) {
            m_ui->aircraftPathsList->addItem(path);
            pathOk = true;
        } else {
            // no aircraft in speciied path, look for Aircraft/ subdir
            QDir d(path);
            if (d.exists("Aircraft")) {
                QString p2 = d.filePath("Aircraft");
                if (LocalAircraftCache::isCandidateAircraftPath(p2)) {
                    m_ui->aircraftPathsList->addItem(p2);
                    pathOk = true;
                }
            }
        }

        if (!pathOk) {
            QMessageBox mb;
            mb.setText(tr("No aircraft found in the folder '%1' - add anyway?").arg(path));
            mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
            mb.setDefaultButton(QMessageBox::No);
            mb.exec();

            if (mb.result() == QMessageBox::Yes) {
                m_ui->aircraftPathsList->addItem(path);
            }
        }

        saveAircraftPaths();
    }
}

void AddOnsPage::onRemoveAircraftPath()
{
    if (m_ui->aircraftPathsList->currentItem()) {
        delete m_ui->aircraftPathsList->currentItem();
        saveAircraftPaths();
    }
}

void AddOnsPage::saveAircraftPaths()
{
    QSettings settings;
    QStringList paths;

    for (int i=0; i<m_ui->aircraftPathsList->count(); ++i) {
        paths.append(m_ui->aircraftPathsList->item(i)->text());
    }

    settings.setValue("aircraft-paths", paths);
    emit aircraftPathsChanged();
}

void AddOnsPage::saveSceneryPaths()
{
    QSettings settings;
    QStringList paths;
    for (int i=0; i<m_ui->sceneryPathsList->count(); ++i) {
        paths.append(m_ui->sceneryPathsList->item(i)->text());
    }

    settings.setValue("scenery-paths", paths);

    emit sceneryPathsChanged();
}

bool AddOnsPage::haveSceneryPath(QString path) const
{
    for (int i=0; i<m_ui->sceneryPathsList->count(); ++i) {
        if (m_ui->sceneryPathsList->item(i)->text() == path) {
            return true;
        }
    }

    return false;
}

void AddOnsPage::onAddCatalog()
{
    QScopedPointer<AddCatalogDialog> dlg(new AddCatalogDialog(this, m_packageRoot));
    dlg->exec();
    if (dlg->result() == QDialog::Accepted) {
        m_catalogsModel->refresh();
    }
}

void AddOnsPage::onAddDefaultCatalog()
{
    addDefaultCatalog(this, false /* not silent */);

    m_catalogsModel->refresh();
    updateUi();
}

void AddOnsPage::addDefaultCatalog(QWidget* pr, bool silent)
{
    // check it's not a duplicate somehow
    FGHTTPClient* http = globals->get_subsystem<FGHTTPClient>();
    if (http->isDefaultCatalogInstalled())
        return;

    QScopedPointer<AddCatalogDialog> dlg(new AddCatalogDialog(pr, globals->packageRoot()));
    QUrl url(QString::fromStdString(http->getDefaultCatalogUrl()));
    if (silent) {
        dlg->setNonInteractiveMode();
    }
    dlg->setUrlAndDownload(url);
    dlg->exec();

}

void AddOnsPage::onRemoveCatalog()
{
    QModelIndex mi = m_ui->catalogsList->currentIndex();
    FGHTTPClient* http = globals->get_subsystem<FGHTTPClient>();

    if (mi.isValid()) {
        QString s = tr("Remove aircraft hangar '%1'? All installed aircraft from this "
                            "hangar will be removed.");
        QString pkgId = mi.data(CatalogIdRole).toString();

        if (pkgId.toStdString() == http->getDefaultCatalogId()) {
            s = tr("Remove the default aircraft hangar? "
                        "This hangar contains all the default aircraft included with FlightGear. "
                        "If you change your mind in the future, click the 'restore' button.");
        } else {
            s = s.arg(mi.data(Qt::DisplayRole).toString());
        }

        QMessageBox mb;
        mb.setText(s);
        mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
        mb.setDefaultButton(QMessageBox::No);
        mb.exec();
        
        if (mb.result() == QMessageBox::Yes) {
            m_packageRoot->removeCatalogById(pkgId.toStdString());
        }
    }

    updateUi();
}

void AddOnsPage::onInstallScenery()
{
    QSettings settings;
    QString downloadDir = settings.value("download-dir").toString();
    InstallSceneryDialog dlg(this, downloadDir);
    if (dlg.exec() == QDialog::Accepted) {
        if (!haveSceneryPath(dlg.sceneryPath())) {
            m_ui->sceneryPathsList->addItem(dlg.sceneryPath());
            saveSceneryPaths();
        }
    }
}

void AddOnsPage::updateUi()
{
    FGHTTPClient* http = globals->get_subsystem<FGHTTPClient>();
    m_ui->addDefaultCatalogButton->setEnabled(!http->isDefaultCatalogInstalled());
}

void AddOnsPage::onDraggedAircraftList()
{
    qWarning() << "did drag aircraft list";
}