#include "settingsdialog.h"
#include <QFormLayout>
#include <QDialogButtonBox>
#include <QLabel>
#include <QSettings>
#include <QApplication>
#include <QProcess>
#include <QCoreApplication>
#include <QFileInfo>
#include <QMessageBox>
#include <QDir>
#include <QPushButton>
#include <QLineEdit>
#include <QColorDialog>
#include "rawimage.h"

extern int DEFAULT_WIDTH;
extern double SATURATION;
extern int FILTERING;
extern bool BESTFIT;
extern QMap<QString, QColor> headerHighlight;

class EvenNumber : public QSpinBox
{
public:
    explicit EvenNumber(QWidget *parent) : QSpinBox(parent){}
protected:
    QValidator::State validate(QString &text, int &) const
    {
        bool ok;
        int val = text.toInt(&ok);
        if(ok && (val & 1) == 0)return QValidator::Acceptable;
        if(ok)return QValidator::Intermediate;
        return QValidator::Invalid;
    }
    void fixup(QString &input) const
    {
        bool ok;
        int val = input.toInt(&ok);
        val -= val & 1;
        input = QString::number(val);
    }
};

SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent)
{
    QFormLayout *layout = new QFormLayout(this);
    setWindowTitle(tr("Settings"));

    QSettings settings;

    m_preloadImages = new QSpinBox(this);
    m_preloadImages->setRange(0, 32);
    m_preloadImages->setValue(settings.value("settings/preloadimagecount", DEFAULT_WIDTH).toInt());
    m_preloadImages->setToolTip(tr("How many images are preloaded before and after current image."));

    m_thumSize = new EvenNumber(this);
    m_thumSize->setRange(64, 512);
    m_thumSize->setSingleStep(2);
    m_thumSize->setValue(settings.value("settings/thumnailsize", THUMB_SIZE).toInt());
    m_thumSize->setToolTip(tr("Thumbnail size in pixels"));

    m_saturation = new QDoubleSpinBox(this);
    m_saturation->setMinimum(0);
    m_saturation->setMaximum(100);
    m_saturation->setSuffix(" %");
    m_saturation->setValue(settings.value("settings/saturation", SATURATION * 100.0).toDouble());
    m_saturation->setToolTip(tr("Set threshold value that is considered saturated when showing statistics.\nFor RAW files you may set 22%"));

    m_slideShowTime = new QDoubleSpinBox(this);
    m_slideShowTime->setMinimum(0.01);
    m_slideShowTime->setMaximum(10);
    m_slideShowTime->setSuffix(" s");
    m_slideShowTime->setValue(settings.value("settings/slideshowtime", 1.0).toDouble());
    m_slideShowTime->setSingleStep(0.1);

    m_useNativeDialog = new QCheckBox(tr("Don't use native file dialog"), this);
    m_useNativeDialog->setChecked(QApplication::testAttribute(Qt::AA_DontUseNativeDialogs));

    m_filtering = new QComboBox(this);
    m_filtering->addItems({tr("Nearest"), tr("Linear"), tr("Cubic")});
    m_filtering->setCurrentIndex(FILTERING);

    m_qualityThumbnail = new QCheckBox(tr("Smooth thumbnails"), this);
    m_qualityThumbnail->setChecked(QUALITY_RESIZE);
    m_qualityThumbnail->setToolTip(tr("Use box filter when downsampling thumbnails instead of nearest. Slightly slower."));

    m_bestFit = new QCheckBox(tr("Best Fit on image load"));
    m_bestFit->setToolTip(tr("Set Best Fit zoom level when opening new image."));
    m_bestFit->setChecked(BESTFIT);

    m_headerHighlight = new QListWidget(this);
    m_headerHighlight->setToolTip(tr("List of FITS keywords that will be highlighted in Image info"));
    for(auto i = headerHighlight.begin(); i != headerHighlight.end(); i++)
    {
        QListWidgetItem *item = new QListWidgetItem(m_headerHighlight);
        item->setText(i.key());
        item->setBackground(i.value());
    }
    m_keyword = new QLineEdit(this);
    m_keyword->setPlaceholderText(tr("FITS keyword"));
    QPushButton *color = new QPushButton(this);
    QPixmap pix(16, 16);
    pix.fill(m_color);
    color->setIcon(pix);
    connect(color, &QPushButton::clicked, [this, color](){
        QColor rgb = QColorDialog::getColor(m_color, this);
        if(rgb.isValid())
        {
            QPixmap pix(16, 16);
            pix.fill(rgb);
            color->setIcon(pix);
            m_color = rgb;
        }
    });

    QPushButton *add = new QPushButton(tr("Add keyword highlight"), this);
    connect(add, &QPushButton::clicked, [this](){
        auto list = m_headerHighlight->findItems(m_keyword->text(), Qt::MatchFixedString | Qt::MatchCaseSensitive);
        if(list.size())return;
        QListWidgetItem *item = new QListWidgetItem(m_headerHighlight);
        item->setText(m_keyword->text());
        item->setBackground(m_color);
    });
    QPushButton *remove = new QPushButton(tr("Remove keyword highlight"), this);
    connect(remove, &QPushButton::clicked, [this](){
        auto list = m_headerHighlight->selectedItems();
        for(auto item : list)
            delete item;
    });

    m_lang = new QComboBox(this);
    m_lang->addItems({"English", "Français", "Slovenčina", "Português"});
    QString lang;
    switch(QLocale().language())
    {
    default:
    case QLocale::English: lang = "en"; break;
    case QLocale::French: lang = "fr"; break;
    case QLocale::Slovak: lang = "sk"; break;
    case QLocale::Portuguese: lang = "pt_BR"; break;
    }

    lang = settings.value("settings/lang", lang).toString();
    if(lang == "en")m_lang->setCurrentIndex(0);
    else if(lang == "fr")m_lang->setCurrentIndex(1);
    else if(lang == "sk")m_lang->setCurrentIndex(2);
    else if(lang == "pt_BR")m_lang->setCurrentIndex(3);

    m_checkUpdate = new QCheckBox(tr("Check for new version"), this);
    m_checkUpdate->setToolTip(tr("Check for new version every week"));
    m_checkUpdate->setChecked(settings.value("settings/checkupdate", true).toBool());

    layout->addRow(tr("Image preload count"), m_preloadImages);
    layout->addRow(tr("Thumbnails size"), m_thumSize);
    layout->addRow(tr("Saturation"), m_saturation);
    layout->addRow(tr("Slideshow interval"), m_slideShowTime);
    layout->addRow(tr("Image interpolation"), m_filtering);
    layout->addRow(tr("Language"), m_lang);
    layout->addRow(m_qualityThumbnail);
    layout->addRow(m_useNativeDialog);
    layout->addRow(m_bestFit);
    layout->addRow(m_checkUpdate);
    layout->addRow(new QLabel(tr("FITS header highlight"), this));
    layout->addRow(m_headerHighlight);
    layout->addRow(m_keyword, color);
    layout->addRow(add, remove);

#ifdef Q_OS_WIN64
    QPushButton *installThumbnailer = new QPushButton(tr("Install"), this);
    installThumbnailer->setToolTip(tr("This will install thumnail generation for FITS and XISF files in File Explorer"));
    connect(installThumbnailer, &QPushButton::clicked, this, &SettingsDialog::installThumbnailer);
    layout->addRow(tr("Install thumbnailer"), installThumbnailer);
#endif
    //layout->addRow(new QLabel(tr("Changes in settings will take effect after program restart.")));

    QDialogButtonBox *buttonBox = new QDialogButtonBox(this);
    buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
    connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
    connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
    connect(this, &QDialog::accepted, this, &SettingsDialog::saveSettings);

    layout->addRow(buttonBox);
}

void SettingsDialog::loadSettings()
{
    QSettings settings;
    THUMB_SIZE = settings.value("settings/thumbnailsize", THUMB_SIZE).toInt();
    THUMB_SIZE_BORDER = THUMB_SIZE + 10;
    THUMB_SIZE_BORDER_Y = THUMB_SIZE + 30;
    DEFAULT_WIDTH = settings.value("settings/preloadimagecount", DEFAULT_WIDTH).toInt();
    SATURATION = settings.value("settings/saturation", 95.0).toDouble() / 100.0;
    FILTERING = settings.value("settings/filtering", FILTERING).toInt();
    QUALITY_RESIZE = settings.value("settings/qualitythumbnail", QUALITY_RESIZE).toBool();
    BESTFIT = settings.value("settings/bestfit", BESTFIT).toBool();
    QStringList keywords = settings.value("settings/headerhighlightkeywords").toStringList();
    QStringList colors = settings.value("settings/headerhighlightcolors").toStringList();
    for(int i = 0; i < std::min(keywords.size(), colors.size()); i++)
        headerHighlight.insert(keywords[i], QColor::fromString(colors[i]));

    QApplication::setAttribute(Qt::AA_DontUseNativeDialogs, settings.value("settings/dontusenativedialogs", false).toBool());
}

bool SettingsDialog::loadThumbsizes()
{
    QSettings settings;
    int OLD_THUMB_SIZE = THUMB_SIZE;
    THUMB_SIZE = settings.value("settings/thumbnailsize", THUMB_SIZE).toInt();
    THUMB_SIZE_BORDER = THUMB_SIZE + 10;
    THUMB_SIZE_BORDER_Y = THUMB_SIZE + 30;
    return OLD_THUMB_SIZE != THUMB_SIZE;
}

void SettingsDialog::installThumbnailer()
{
#ifdef Q_OS_WIN64
    QString path = QCoreApplication::instance()->applicationDirPath() + "/tenmonthumbnailer.dll";
    if(!QFileInfo::exists(path))
    {
        QMessageBox::critical(this, tr("Missing dll"), tr("Can't find ") + path);
        return;
    }

    QProcess regsvr;
    int ret = regsvr.execute("regsvr32.exe", {"/s", path});
    if(ret == 0)
        QMessageBox::information(this, tr("Thumbnail support"), tr("Thumbnail generation support sucessufully installed."));
    else
        QMessageBox::critical(this, tr("Error"), tr("Failed to register thumbnailer. %1").arg(ret));
#endif
}

void SettingsDialog::saveSettings()
{
    QSettings settings;
    settings.setValue("settings/thumbnailsize", m_thumSize->value());
    settings.setValue("settings/preloadimagecount", m_preloadImages->value());
    settings.setValue("settings/dontusenativedialogs", m_useNativeDialog->isChecked());
    settings.setValue("settings/saturation", m_saturation->value());
    settings.setValue("settings/slideshowtime", m_slideShowTime->value());
    settings.setValue("settings/qualitythumbnail", m_qualityThumbnail->isChecked());
    QUALITY_RESIZE = m_qualityThumbnail->isChecked();
    FILTERING = m_filtering->currentIndex();
    BESTFIT = m_bestFit->isChecked();
    settings.setValue("settings/filtering", FILTERING);
    settings.setValue("settings/bestfit", BESTFIT);
    SATURATION = m_saturation->value() / 100.0;
    QApplication::setAttribute(Qt::AA_DontUseNativeDialogs, m_useNativeDialog->isChecked());
    if(DEFAULT_WIDTH != m_preloadImages->value())
        emit preloadChanged(m_preloadImages->value());

    headerHighlight.clear();
    QStringList colors;
    for(int i = 0; i < m_headerHighlight->count(); i++)
    {
        auto item = m_headerHighlight->item(i);
        colors.push_back(item->background().color().name());
        headerHighlight[item->text()] = item->background().color();
    }
    settings.setValue("settings/headerhighlightkeywords", headerHighlight.keys());
    settings.setValue("settings/headerhighlightcolors", colors);
    QString lang;
    int langIdx = m_lang->currentIndex();
    switch(langIdx)
    {
    case 0: lang = "en"; break;
    case 1: lang = "fr"; break;
    case 2: lang = "sk"; break;
    case 3: lang = "pt_BR"; break;
    }
    settings.setValue("settings/lang", lang);
    settings.setValue("settings/checkupdate", m_checkUpdate->isChecked());
}
