/*
 * This file is a part of Luminance HDR package.
 * ----------------------------------------------------------------------
 * Copyright (C) 2006,2007 Giuseppe Rota
 *
 *  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
 * ----------------------------------------------------------------------
 *
 * Original Work
 * @author Giuseppe Rota <grota@users.sourceforge.net>
 *
 * Improvements, bugfixing
 * @author Franco Comida <fcomida@users.sourceforge.net>
 *
 */

#include <QMessageBox>
#include <QDesktopServices>
#include <QFileDialog>
#include <QTextStream>
#include <QDir>
#include <QInputDialog>
#include <QStatusBar>
#include <QProgressBar>
#include <QLineEdit>
#include <QKeyEvent>
#include <QDebug>
#include <QSqlTableModel>
#include <QSqlRecord>
#include <QSqlQuery>
#include <QSqlError>

#include "Common/LuminanceOptions.h"
#include "Common/config.h"
#include "PreviewPanel/PreviewLabel.h"
#include "TonemappingPanel/TonemappingPanel.h"
#include "TonemappingPanel/TMOProgressIndicator.h"
#include "TonemappingPanel/TonemappingSettings.h"
#include "Common/SavedParametersDialog.h"
#include "TonemappingPanel/SavingParametersDialog.h"
#include "TonemappingOperators/pfstmdefaultparams.h"
#include "UI/Gang.h"
#include "ui_TonemappingPanel.h"

#include "contrib/qtwaitingspinner/QtWaitingSpinner.h"

TonemappingPanel::TonemappingPanel(int mainWinNumber, PreviewPanel *panel, QWidget *parent):
    QWidget(parent),
    adding_custom_size(false),
    m_previewPanel(panel),
    m_mainWinNumber(mainWinNumber),
    m_autolevelThreshold(0.985f),
    m_thd(new ThresholdWidget(this)),
    m_Ui(new Ui::TonemappingPanel)
{
    m_Ui->setupUi(this);

    connect(m_thd.data(), SIGNAL(ready()), this, SLOT(thresholdReady()));

    if ( !QIcon::hasThemeIcon("edit-download") )
        m_Ui->saveButton->setIcon(QIcon(":/program-icons/edit-download"));
    if ( !QIcon::hasThemeIcon("cloud-upload") )
        m_Ui->loadButton->setIcon(QIcon(":/program-icons/cloud-upload"));

    currentTmoOperator = mantiuk06; // from Qt Designer

    // mantiuk06
    contrastfactorGang = new Gang(m_Ui->contrastFactorSlider,m_Ui->contrastFactordsb,m_Ui->contrastEqualizCheckBox,NULL,NULL, NULL, 0.01f /*0.001f*/, 1.0f, MANTIUK06_CONTRAST_FACTOR);

    connect(contrastfactorGang, SIGNAL(enableUndo(bool)), m_Ui->undoButton, SLOT(setEnabled(bool)));
    connect(contrastfactorGang, SIGNAL(enableRedo(bool)), m_Ui->redoButton, SLOT(setEnabled(bool)));

    saturationfactorGang = new Gang(m_Ui->saturationFactorSlider, m_Ui->saturationFactordsb, NULL, NULL, NULL, NULL, 0.0f, 2.0f, MANTIUK06_SATURATION_FACTOR);
    detailfactorGang = new Gang(m_Ui->detailFactorSlider, m_Ui->detailFactordsb,NULL,NULL,NULL,NULL, 1.0f, 99.0f, MANTIUK06_DETAIL_FACTOR);

    // mantiuk08
    colorSaturationGang = new Gang(m_Ui->colorSaturationSlider,m_Ui->colorSaturationDSB, NULL, NULL, NULL, NULL, 0.f, 2.f, MANTIUK08_COLOR_SATURATION);

    connect(colorSaturationGang, SIGNAL(enableUndo(bool)), m_Ui->undoButton, SLOT(setEnabled(bool)));
    connect(colorSaturationGang, SIGNAL(enableRedo(bool)), m_Ui->redoButton, SLOT(setEnabled(bool)));

    contrastEnhancementGang = new Gang(m_Ui->contrastEnhancementSlider, m_Ui->contrastEnhancementDSB, NULL, NULL, NULL, NULL, .01f, 10.f, MANTIUK08_CONTRAST_ENHANCEMENT);
    luminanceLevelGang = new Gang(m_Ui->luminanceLevelSlider, m_Ui->luminanceLevelDSB, m_Ui->luminanceLevelCheckBox, NULL, NULL, NULL, 1.f, 100.0f, MANTIUK08_LUMINANCE_LEVEL);

    // fattal02
    alphaGang = new Gang(m_Ui->alphaSlider, m_Ui->alphadsb, NULL,NULL,NULL,NULL, 0.05, 2.f, FATTAL02_ALPHA, true);

    connect(alphaGang, SIGNAL(enableUndo(bool)), m_Ui->undoButton, SLOT(setEnabled(bool)));
    connect(alphaGang, SIGNAL(enableRedo(bool)), m_Ui->redoButton, SLOT(setEnabled(bool)));

    betaGang = new Gang(m_Ui->betaSlider, m_Ui->betadsb, NULL,NULL,NULL,NULL, 0.1f, 2.f, FATTAL02_BETA);
    saturation2Gang = new Gang(m_Ui->saturation2Slider, m_Ui->saturation2dsb, NULL,NULL,NULL,NULL, 0.f, 1.5f, FATTAL02_COLOR);
    noiseGang = new Gang(m_Ui->noiseSlider, m_Ui->noisedsb, NULL,NULL,NULL,NULL, 0, 1.f, FATTAL02_NOISE_REDUX);
    // oldFattalGang = new Gang(NULL,NULL, m_Ui->oldFattalCheckBox);
    fftSolverGang = new Gang(NULL, NULL,m_Ui->fftVersionCheckBox);

    // ferradans11
    rhoGang = new Gang(m_Ui->rhoSlider, m_Ui->rhodsb, NULL,NULL,NULL,NULL, -10.f, 10.f, FERRADANS11_RHO);

    connect(rhoGang, SIGNAL(enableUndo(bool)), m_Ui->undoButton, SLOT(setEnabled(bool)));
    connect(rhoGang, SIGNAL(enableRedo(bool)), m_Ui->redoButton, SLOT(setEnabled(bool)));

    inv_alphaGang = new Gang(m_Ui->inv_alphaSlider, m_Ui->inv_alphadsb, NULL,NULL,NULL,NULL, 0.1f, 10.f, FERRADANS11_INV_ALPHA);

    // ashikhmin02
    contrastGang = new Gang(m_Ui->contrastSlider, m_Ui->contrastdsb,NULL,NULL,NULL,NULL, 0.f, 1.f, 0.5f);

    connect(contrastGang, SIGNAL(enableUndo(bool)), m_Ui->undoButton, SLOT(setEnabled(bool)));
    connect(contrastGang, SIGNAL(enableRedo(bool)), m_Ui->redoButton, SLOT(setEnabled(bool)));

    simpleGang = new Gang(NULL, NULL, m_Ui->simpleCheckBox);
    eq2Gang = new Gang(NULL, NULL,NULL, NULL, m_Ui->eq2RadioButton, m_Ui->eq4RadioButton);

    // drago03
    biasGang = new Gang(m_Ui->biasSlider, m_Ui->biasdsb,NULL,NULL,NULL,NULL, 0.f, 1.f, DRAGO03_BIAS);

    connect(biasGang, SIGNAL(enableUndo(bool)), m_Ui->undoButton, SLOT(setEnabled(bool)));
    connect(biasGang, SIGNAL(enableRedo(bool)), m_Ui->redoButton, SLOT(setEnabled(bool)));

    // durand02
    spatialGang = new Gang(m_Ui->spatialSlider, m_Ui->spatialdsb, NULL, NULL, NULL, NULL, 0.f, 100.f, DURAND02_SPATIAL);

    connect(spatialGang, SIGNAL(enableUndo(bool)), m_Ui->undoButton, SLOT(setEnabled(bool)));
    connect(spatialGang, SIGNAL(enableRedo(bool)), m_Ui->redoButton, SLOT(setEnabled(bool)));

    rangeGang = new Gang(m_Ui->rangeSlider, m_Ui->rangedsb,NULL,NULL,NULL,NULL, 0.01f, 10.f, DURAND02_RANGE);
    baseGang = new Gang(m_Ui->baseSlider, m_Ui->basedsb,NULL,NULL,NULL,NULL, 0.f, 10.f, DURAND02_BASE);

    // pattanaik00
    multiplierGang = new Gang(m_Ui->multiplierSlider, m_Ui->multiplierdsb,NULL,NULL,NULL,NULL, 1e-3,1000.f, PATTANAIK00_MULTIPLIER, true);

    connect(multiplierGang, SIGNAL(enableUndo(bool)), m_Ui->undoButton, SLOT(setEnabled(bool)));
    connect(multiplierGang, SIGNAL(enableRedo(bool)), m_Ui->redoButton, SLOT(setEnabled(bool)));

    coneGang = new Gang(m_Ui->coneSlider, m_Ui->conedsb,NULL,NULL,NULL,NULL, 0.f, 1.f, PATTANAIK00_CONE);
    rodGang = new Gang(m_Ui->rodSlider, m_Ui->roddsb,NULL,NULL,NULL,NULL, 0.f, 1.f, PATTANAIK00_ROD);
    autoYGang = new Gang(NULL,NULL, m_Ui->autoYcheckbox);
    pattalocalGang = new Gang(NULL,NULL, m_Ui->pattalocal);

    // reinhard02
    keyGang = new Gang(m_Ui->keySlider, m_Ui->keydsb,NULL,NULL,NULL,NULL, 0.f, 1.f, 0.18f);

    connect(keyGang, SIGNAL(enableUndo(bool)), m_Ui->undoButton, SLOT(setEnabled(bool)));
    connect(keyGang, SIGNAL(enableRedo(bool)), m_Ui->redoButton, SLOT(setEnabled(bool)));

    phiGang = new Gang(m_Ui->phiSlider, m_Ui->phidsb, NULL,NULL,NULL,NULL, 0.f, 100.f, REINHARD02_PHI);
    range2Gang = new Gang(m_Ui->range2Slider, m_Ui->range2dsb,NULL,NULL,NULL,NULL, 1.f, 32.f, REINHARD02_RANGE);
    lowerGang = new Gang(m_Ui->lowerSlider, m_Ui->lowerdsb,NULL,NULL,NULL,NULL, 1.f, 100.f, REINHARD02_LOWER);
    upperGang = new Gang(m_Ui->upperSlider, m_Ui->upperdsb,NULL,NULL,NULL,NULL, 1.f, 100.f, REINHARD02_UPPER);
    usescalesGang = new Gang(NULL,NULL, m_Ui->usescalescheckbox);

    // reinhard05
    brightnessGang = new Gang(m_Ui->brightnessSlider, m_Ui->brightnessdsb,NULL,NULL,NULL,NULL, -20.f, 20.f, REINHARD05_BRIGHTNESS);

    connect(brightnessGang, SIGNAL(enableUndo(bool)), m_Ui->undoButton, SLOT(setEnabled(bool)));
    connect(brightnessGang, SIGNAL(enableRedo(bool)), m_Ui->redoButton, SLOT(setEnabled(bool)));

    chromaticGang = new Gang(m_Ui->chromaticAdaptSlider, m_Ui->chromaticAdaptdsb,NULL,NULL,NULL,NULL, 0.f, 1.f, REINHARD05_CHROMATIC_ADAPTATION);
    lightGang = new Gang(m_Ui->lightAdaptSlider, m_Ui->lightAdaptdsb,NULL,NULL,NULL,NULL, 0.f, 1.f, REINHARD05_LIGHT_ADAPTATION);

    // pregamma
    pregammaGang = new Gang(m_Ui->pregammaSlider, m_Ui->pregammadsb,NULL,NULL,NULL,NULL, 0, 5, 1);

    //--
    connect(m_Ui->stackedWidget_operators, SIGNAL(currentChanged(int)), this, SLOT(updateCurrentTmoOperator(int)));

    connect(m_Ui->loadButton, SIGNAL(clicked()), this, SLOT(loadParameters()));
    connect(m_Ui->saveButton, SIGNAL(clicked()), this, SLOT(saveParameters()));

    connect(m_Ui->autoLevelsCheckBox, SIGNAL(toggled(bool)), this, SLOT(autoLevels(bool)));

    m_spinner = new QtWaitingSpinner(this);

    m_spinner->setRoundness(70.0);
    m_spinner->setMinimumTrailOpacity(15.0);
    m_spinner->setTrailFadePercentage(70.0);
    m_spinner->setNumberOfLines(12);
    m_spinner->setLineLength(5);
    m_spinner->setLineWidth(2);
    m_spinner->setInnerRadius(5);
    m_spinner->setRevolutionsPerSecond(1);

    m_spinner->start();

    m_Ui->frameSpinner->addWidget(m_spinner);
    m_spinner->setVisible(false);

    createDatabase();
}

void TonemappingPanel::setExportQueueSize(int size)
{
    m_spinner->setVisible(size > 0);
    m_Ui->lblQueueSize->setText(QString(tr("Queue size: %1")).arg(size));
}


TonemappingPanel::~TonemappingPanel()
{
    qDebug() << "TonemappingPanel::~TonemappingPanel()";

    delete contrastfactorGang;
    delete saturationfactorGang;
    delete detailfactorGang;
    delete contrastGang;
    delete colorSaturationGang;
    delete contrastEnhancementGang;
    delete luminanceLevelGang;
    delete simpleGang;
    delete eq2Gang;
    delete biasGang;
    delete spatialGang;
    delete rangeGang;
    delete baseGang;
    delete alphaGang;
    delete betaGang;
    delete rhoGang;
    delete inv_alphaGang;
    delete saturation2Gang;
    delete noiseGang;
    delete multiplierGang;
    delete coneGang;
    delete rodGang;
    delete autoYGang;
    delete pattalocalGang;
    delete keyGang;
    delete phiGang;
    delete range2Gang;
    delete lowerGang;
    delete upperGang;
    delete usescalesGang;
    delete brightnessGang;
    delete chromaticGang;
    delete lightGang;
    delete pregammaGang;
    delete m_spinner;

    qDeleteAll(toneMappingOptionsToDelete);

    if (m_mainWinNumber == 0) {
        QSqlDatabase db = QSqlDatabase::database();
        db.close();
    }
}

void TonemappingPanel::changeEvent(QEvent *event)
{
    if (event->type() == QEvent::LanguageChange)
         m_Ui->retranslateUi(this);
    QWidget::changeEvent(event);
}

void TonemappingPanel::createDatabase()
{
    LuminanceOptions options;

    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(options.getDatabaseFileName());
    db.setHostName("localhost");
    bool ok = db.open();
    if (!ok)
    {
        QMessageBox::warning(this,tr("TM Database Problem"),
                                  tr("The database used for saving TM parameters cannot be opened.\n"
                                    "Error: %1").arg(db.lastError().databaseText()),
                                  QMessageBox::Ok,QMessageBox::NoButton);
        return;
    }
    QSqlQuery query;
    // Mantiuk 06
    bool res = query.exec(" CREATE TABLE IF NOT EXISTS mantiuk06 (contrastEqualization boolean NOT NULL, contrastFactor real, saturationFactor real, detailFactor real, pregamma real, comment varchar(150));");
    if (res == false)
        qDebug() << query.lastError();
    // Mantiuk 08
    res = query.exec(" CREATE TABLE IF NOT EXISTS mantiuk08 (colorSaturation real, contrastEnhancement real, luminanceLevel real, manualLuminanceLevel boolean NOT NULL, pregamma real, comment varchar(150));");
    if (res == false)
        qDebug() << query.lastError();
    // Ashikhmin
    res = query.exec(" CREATE TABLE IF NOT EXISTS ashikhmin (simple boolean NOT NULL, eq2 boolean NOT NULL, lct real, pregamma real, comment varchar(150));");
    if (res == false)
        qDebug() << query.lastError();
    // Drago
    res = query.exec(" CREATE TABLE IF NOT EXISTS drago (bias real, pregamma real, comment varchar(150));");
    if (res == false)
        qDebug() << query.lastError();
    // Durand
    res = query.exec(" CREATE TABLE IF NOT EXISTS durand (spatial real, range real, base real, pregamma real, comment varchar(150));");
    if (res == false)
        qDebug() << query.lastError();
    // Fattal
    res = query.exec(" CREATE TABLE IF NOT EXISTS fattal (alpha real, beta real, colorSaturation real, noiseReduction real, oldFattal boolean NOT NULL, pregamma real, comment varchar(150));");
    if (res == false)
        qDebug() << query.lastError();
    // Fattal
    res = query.exec(" CREATE TABLE IF NOT EXISTS ferradans (rho real, inv_alpha real, pregamma real, comment varchar(150));");
    if (res == false)
        qDebug() << query.lastError();
    // Pattanaik
    res = query.exec(" CREATE TABLE IF NOT EXISTS pattanaik (autolum boolean NOT NULL, local boolean NOT NULL, cone real, rod real, multiplier real, pregamma real, comment varchar(150));");
    if (res == false)
        qDebug() << query.lastError();
    // Reinhard02
    res = query.exec(" CREATE TABLE IF NOT EXISTS reinhard02 (scales boolean NOT NULL, key real, phi real, range int, lower int, upper int, pregamma real, comment varchar(150));");
    if (res == false)
        qDebug() << query.lastError();
    // Reinhard05
    res = query.exec(" CREATE TABLE IF NOT EXISTS reinhard05 (brightness real, chromaticAdaptation real, lightAdaptation real, pregamma real, comment varchar(150));");
    if (res == false)
        qDebug() << query.lastError();
    // Hdr creation custom config parameters
    res = query.exec("CREATE TABLE IF NOT EXISTS parameters (weight integer, response integer, model integer, filename varchar(150));");
    if (res == false)
        qDebug() << query.lastError();
}

void TonemappingPanel::setSizes(int width, int height)
{
    sizes.resize(0);
    for(int x = 256; x <= width; x *= 2) {
        if( x >= width )
            break;
        sizes.push_front(x);
        if( 3*(x/2) >= width )
            break;
        sizes.push_front(3*(x/2));
    }
    sizes.push_front(width);
    heightToWidthRatio = ( (float)height )/( (float) width);
    fillCustomSizeComboBox();
    m_Ui->sizeComboBox->setCurrentIndex(m_Ui->sizeComboBox->count() - 1);
}

void TonemappingPanel::on_defaultButton_clicked()
{
    switch (currentTmoOperator)
    {
    case ashikhmin:
        contrastGang->setDefault();
        m_Ui->simpleCheckBox->setChecked(false);
        m_Ui->eq2RadioButton->setChecked(true);
        break;
    case drago:
        biasGang->setDefault();
        break;
    case durand:
        spatialGang->setDefault();
        rangeGang->setDefault();
        baseGang->setDefault();
        break;
    case fattal:
        alphaGang->setDefault();
        betaGang->setDefault();
        saturation2Gang->setDefault();
        noiseGang->setDefault();
        fftSolverGang->setDefault();
        m_Ui->fftVersionCheckBox->setChecked(true);
        break;
    case ferradans:
        rhoGang->setDefault();
        inv_alphaGang->setDefault();
        break;
    case mai: //no options
        break;
    case mantiuk06:
        contrastfactorGang->setDefault();
        saturationfactorGang->setDefault();
        detailfactorGang->setDefault();
        m_Ui->contrastEqualizCheckBox->setChecked(false);
        break;
    case mantiuk08:
        colorSaturationGang->setDefault();
        contrastEnhancementGang->setDefault();
        luminanceLevelGang->setDefault();
        m_Ui->luminanceLevelCheckBox->setChecked(false);
        break;
    case pattanaik:
        multiplierGang->setDefault();
        coneGang->setDefault();
        rodGang->setDefault();
        m_Ui->pattalocal->setChecked(false);
        m_Ui->autoYcheckbox->setChecked(true);
        break;
    case reinhard02:
        keyGang->setDefault();
        phiGang->setDefault();
        range2Gang->setDefault();
        lowerGang->setDefault();
        upperGang->setDefault();
        m_Ui->usescalescheckbox->setChecked(false);
        break;
    case reinhard05:
        brightnessGang->setDefault();
        chromaticGang->setDefault();
        lightGang->setDefault();
        break;
    }
}

// TODO : if you change the position of the operator inside the TMOperator enum
// you will screw up this function!!!
void TonemappingPanel::updateCurrentTmoOperator(int idx)
{
    currentTmoOperator = TMOperator(idx);
    updateUndoState();
}

void TonemappingPanel::updateUndoState()
{
    switch (currentTmoOperator)
    {
    case ashikhmin:
        contrastGang->updateUndoState();
        break;
    case drago:
        biasGang->updateUndoState();
        break;
    case durand:
        spatialGang->updateUndoState();
        break;
    case fattal:
        alphaGang->updateUndoState();
        break;
    case ferradans:
        rhoGang->updateUndoState();
        break;
    case mai: //no options
        break;
    case mantiuk06:
        contrastfactorGang->updateUndoState();
        break;
    case mantiuk08:
        colorSaturationGang->updateUndoState();
        break;
    case pattanaik:
        multiplierGang->updateUndoState();
        break;
    case reinhard02:
        keyGang->updateUndoState();
        break;
    case reinhard05:
        brightnessGang->updateUndoState();
        break;
    }
}

void TonemappingPanel::on_pregammadefault_clicked()
{
    pregammaGang->setDefault();
}

void TonemappingPanel::on_applyButton_clicked()
{
    fillToneMappingOptions(false);
    setupUndo();

    emit startTonemapping(toneMappingOptions);
}

void TonemappingPanel::on_queueButton_clicked()
{
    fillToneMappingOptions(true);
    //setupUndo();

    emit startExport(toneMappingOptions);
}

void TonemappingPanel::fillToneMappingOptions(bool exportMode)
{
    toneMappingOptions = new TonemappingOptions;
    if (!exportMode)
    {
        toneMappingOptionsToDelete.push_back(toneMappingOptions);
    }
    if (!exportMode && sizes.size())
    {
        toneMappingOptions->origxsize = sizes[0];
        toneMappingOptions->xsize = sizes[m_Ui->sizeComboBox->currentIndex()];
    } else {
        toneMappingOptions->origxsize = 0;
        toneMappingOptions->xsize = 0;
    }
    toneMappingOptions->pregamma = pregammaGang->v();
    // toneMappingOptions->tonemapSelection = checkBoxSelection->isChecked();
    // toneMappingOptions->tonemapOriginal = checkBoxOriginal->isChecked();
    switch (currentTmoOperator) {
    case ashikhmin:
        toneMappingOptions->tmoperator = ashikhmin;
        toneMappingOptions->operator_options.ashikhminoptions.simple=simpleGang->isCheckBox1Checked();
        toneMappingOptions->operator_options.ashikhminoptions.eq2=eq2Gang->isRadioButton1Checked();
        toneMappingOptions->operator_options.ashikhminoptions.lct=contrastGang->v();
        break;
    case drago:
        toneMappingOptions->tmoperator = drago;
        toneMappingOptions->operator_options.dragooptions.bias=biasGang->v();
        break;
    case durand:
        toneMappingOptions->tmoperator = durand;
        toneMappingOptions->operator_options.durandoptions.spatial=spatialGang->v();
        toneMappingOptions->operator_options.durandoptions.range=rangeGang->v();
        toneMappingOptions->operator_options.durandoptions.base=baseGang->v();
        break;
    case fattal:
        toneMappingOptions->tmoperator = fattal;
        toneMappingOptions->operator_options.fattaloptions.alpha=alphaGang->v();
        toneMappingOptions->operator_options.fattaloptions.beta=betaGang->v();
        toneMappingOptions->operator_options.fattaloptions.color=saturation2Gang->v();
        toneMappingOptions->operator_options.fattaloptions.noiseredux=noiseGang->v();
//        toneMappingOptions->operator_options.fattaloptions.newfattal=!oldFattalGang->isCheckBox1Checked();
        toneMappingOptions->operator_options.fattaloptions.fftsolver=fftSolverGang->isCheckBox1Checked();
        break;
    case ferradans:
        toneMappingOptions->tmoperator = ferradans;
        toneMappingOptions->operator_options.ferradansoptions.rho=rhoGang->v();
        toneMappingOptions->operator_options.ferradansoptions.inv_alpha=inv_alphaGang->v();
        break;
    case mai:
        toneMappingOptions->tmoperator = mai;
        break;
    case mantiuk06:
        toneMappingOptions->tmoperator = mantiuk06;
        toneMappingOptions->operator_options.mantiuk06options.contrastfactor=contrastfactorGang->v();
        toneMappingOptions->operator_options.mantiuk06options.saturationfactor=saturationfactorGang->v();
        toneMappingOptions->operator_options.mantiuk06options.detailfactor=detailfactorGang->v();
        toneMappingOptions->operator_options.mantiuk06options.contrastequalization=contrastfactorGang->isCheckBox1Checked();
        break;
    case mantiuk08:
        toneMappingOptions->tmoperator = mantiuk08;
        toneMappingOptions->operator_options.mantiuk08options.colorsaturation=colorSaturationGang->v();
        toneMappingOptions->operator_options.mantiuk08options.contrastenhancement=contrastEnhancementGang->v();
        toneMappingOptions->operator_options.mantiuk08options.luminancelevel=luminanceLevelGang->v();
        toneMappingOptions->operator_options.mantiuk08options.setluminance=luminanceLevelGang->isCheckBox1Checked();
        break;
    case pattanaik:
        toneMappingOptions->tmoperator = pattanaik;
        toneMappingOptions->operator_options.pattanaikoptions.autolum=autoYGang->isCheckBox1Checked();
        toneMappingOptions->operator_options.pattanaikoptions.local=pattalocalGang->isCheckBox1Checked();
        toneMappingOptions->operator_options.pattanaikoptions.cone=coneGang->v();
        toneMappingOptions->operator_options.pattanaikoptions.rod=rodGang->v();
        toneMappingOptions->operator_options.pattanaikoptions.multiplier=multiplierGang->v();
        break;
    case reinhard02:
        toneMappingOptions->tmoperator = reinhard02;
        toneMappingOptions->operator_options.reinhard02options.scales=usescalesGang->isCheckBox1Checked();
        toneMappingOptions->operator_options.reinhard02options.key=keyGang->v();
        toneMappingOptions->operator_options.reinhard02options.phi=phiGang->v();
        toneMappingOptions->operator_options.reinhard02options.range=(int)range2Gang->v();
        toneMappingOptions->operator_options.reinhard02options.lower=(int)lowerGang->v();
        toneMappingOptions->operator_options.reinhard02options.upper=(int)upperGang->v();
        break;
    case reinhard05:
        toneMappingOptions->tmoperator = reinhard05;
        toneMappingOptions->operator_options.reinhard05options.brightness=brightnessGang->v();
        toneMappingOptions->operator_options.reinhard05options.chromaticAdaptation=chromaticGang->v();
        toneMappingOptions->operator_options.reinhard05options.lightAdaptation=lightGang->v();
        break;
    }
}

void TonemappingPanel::setupUndo()
{
    switch (currentTmoOperator)
    {
    case ashikhmin:
        simpleGang->setupUndo();
        eq2Gang->setupUndo();
        contrastGang->setupUndo();
        break;
    case drago:
        biasGang->setupUndo();
        break;
    case durand:
        spatialGang->setupUndo();
        rangeGang->setupUndo();
        baseGang->setupUndo();
        break;
    case fattal:
        alphaGang->setupUndo();
        betaGang->setupUndo();
        saturation2Gang->setupUndo();
        noiseGang->setupUndo();
//        oldFattalGang->setupUndo();
        fftSolverGang->setupUndo();
        break;
    case ferradans:
        rhoGang->setupUndo();
        inv_alphaGang->setupUndo();
        break;
    case mai: //no options
        break;
    case mantiuk06:
        contrastfactorGang->setupUndo();
        saturationfactorGang->setupUndo();
        detailfactorGang->setupUndo();
        break;
    case mantiuk08:
        colorSaturationGang->setupUndo();
        contrastEnhancementGang->setupUndo();
        luminanceLevelGang->setupUndo();
        break;
    case pattanaik:
        autoYGang->setupUndo();
        pattalocalGang->setupUndo();
        coneGang->setupUndo();
        rodGang->setupUndo();
        multiplierGang->setupUndo();
        break;
    case reinhard02:
        usescalesGang->setupUndo();
        keyGang->setupUndo();
        phiGang->setupUndo();
        range2Gang->setupUndo();
        lowerGang->setupUndo();
        upperGang->setupUndo();
        break;
    case reinhard05:
        brightnessGang->setupUndo();
        chromaticGang->setupUndo();
        lightGang->setupUndo();
        break;
    }
}

void TonemappingPanel::on_undoButton_clicked()
{
    onUndoRedo(true);
}

void TonemappingPanel::on_redoButton_clicked()
{
    onUndoRedo(false);
}

void TonemappingPanel::onUndoRedo(bool undo)
{
    typedef void (Gang::*REDO_UNDO) ();
    REDO_UNDO redoUndo = undo ? &Gang::undo : &Gang::redo;
    switch (currentTmoOperator)
    {
    case ashikhmin:
        (simpleGang->*redoUndo)();
        (eq2Gang->*redoUndo)();
        (contrastGang->*redoUndo)();
        break;
    case drago:
        (biasGang->*redoUndo)();
        break;
    case durand:
        (spatialGang->*redoUndo)();
        (rangeGang->*redoUndo)();
        (baseGang->*redoUndo)();
        break;
    case fattal:
        (alphaGang->*redoUndo)();
        (betaGang->*redoUndo)();
        (saturation2Gang->*redoUndo)();
        (noiseGang->*redoUndo)();
//      (oldFattalGang->*redoUndo)();
        (fftSolverGang->*redoUndo)();
        break;
    case ferradans:
        (rhoGang->*redoUndo)();
        (inv_alphaGang->*redoUndo)();
        break;
    case mai:
        break;
    case mantiuk06:
        (contrastfactorGang->*redoUndo)();
        (saturationfactorGang->*redoUndo)();
        (detailfactorGang->*redoUndo)();
        break;
    case mantiuk08:
        (colorSaturationGang->*redoUndo)();
        (contrastEnhancementGang->*redoUndo)();
        (luminanceLevelGang->*redoUndo)();
        break;
    case pattanaik:
        (autoYGang->*redoUndo)();
        (pattalocalGang->*redoUndo)();
        (coneGang->*redoUndo)();
        (rodGang->*redoUndo)();
        (multiplierGang->*redoUndo)();
        break;
    case reinhard02:
        (usescalesGang->*redoUndo)();
        (keyGang->*redoUndo)();
        (phiGang->*redoUndo)();
        (range2Gang->*redoUndo)();
        (lowerGang->*redoUndo)();
        (upperGang->*redoUndo)();
        break;
    case reinhard05:
        (brightnessGang->*redoUndo)();
        (chromaticGang->*redoUndo)();
        (lightGang->*redoUndo)();
        break;
    }
}

void TonemappingPanel::on_lblOpenQueue_linkActivated(const QString& link)
{
    LuminanceOptions options;
    QDesktopServices::openUrl(QUrl::fromLocalFile(options.getExportDir()));
}


void TonemappingPanel::on_loadsettingsbutton_clicked()
{
    LuminanceOptions lum_options;

    QString opened = QFileDialog::getOpenFileName(this,
                                                  tr("Load a tonemapping settings text file..."),
                                                  lum_options.getDefaultPathTmoSettings(),
                                                  tr("LuminanceHDR tonemapping settings text file (*.txt)") );
    if ( !opened.isEmpty() )
    {
        QFileInfo qfi(opened);
        if (!qfi.isReadable())
        {
            QMessageBox::critical(this,tr("Aborting..."),
                                  tr("File is not readable (check existence, permissions,...)"),
                                  QMessageBox::Ok,QMessageBox::NoButton);
            return;
        }
        lum_options.setDefaultPathTmoSettings( qfi.path() );

        //update filename internal field, used by parsing function fromTxt2Gui()
        tmoSettingsFilename = opened;
        //call parsing function
        fromTxt2Gui();
    }
}

void TonemappingPanel::on_savesettingsbutton_clicked()
{
    LuminanceOptions lum_options;

    QString fname = QFileDialog::getSaveFileName(this,
                                                 tr("Save tonemapping settings text file to..."),
                                                 lum_options.getDefaultPathTmoSettings(),
                                                 tr("LuminanceHDR tonemapping settings text file (*.txt)"));
    if( ! fname.isEmpty() )
    {
        QFileInfo qfi(fname);
        if (qfi.suffix().toUpper() != "TXT")
        {
            fname+=".txt";
        }

        lum_options.setDefaultPathTmoSettings( qfi.path() );

        //write txt file
        fromGui2Txt(fname);
    }
}

void TonemappingPanel::fromGui2Txt(QString destination)
{
    QFile file(destination);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        QMessageBox::critical(this,tr("Aborting..."),tr("File is not writable (check permissions, path...)"),
                              QMessageBox::Ok,QMessageBox::NoButton);
        return;
    }
    QTextStream out(&file);
    out << "# LuminanceHDR Tonemapping Setting file." << endl;
    out << "# Editing this file by hand is risky, worst case scenario is Luminance crashing." << endl;
    out << "# Please edit this file by hand only if you know what you're doing, in any case never change the left hand side text (i.e. the part before the ``='')." << endl;
    out << "TMOSETTINGSVERSION=" << TMOSETTINGSVERSION << endl;
    out << "XSIZE=" << sizes[m_Ui->sizeComboBox->currentIndex()] << endl;

    QWidget *current_page = m_Ui->stackedWidget_operators->currentWidget();
    if (current_page == m_Ui->page_mantiuk06)
    {
        out << "TMO=" << "Mantiuk06" << endl;
        out << "CONTRASTFACTOR=" << contrastfactorGang->v() << endl;
        out << "SATURATIONFACTOR=" << saturationfactorGang->v() << endl;
        out << "DETAILFACTOR=" << detailfactorGang->v() << endl;
        out << "CONTRASTEQUALIZATION=" << (m_Ui->contrastEqualizCheckBox->isChecked() ? "YES" : "NO") << endl;
    }
    else if (current_page == m_Ui->page_mantiuk08)
    {
        out << "TMO=" << "Mantiuk08" << endl;
        out << "COLORSATURATION=" << colorSaturationGang->v() << endl;
        out << "CONTRASTENHANCEMENT=" << contrastEnhancementGang->v() << endl;
        out << "LUMINANCELEVEL=" << luminanceLevelGang->v() << endl;
        out << "SETLUMINANCE=" << (m_Ui->luminanceLevelCheckBox->isChecked() ? "YES" : "NO") << endl;
    }
    else if (current_page == m_Ui->page_fattal)
    {
        out << "TMO=" << "Fattal02" << endl;
        out << "ALPHA=" << alphaGang->v() << endl;
        out << "BETA=" << betaGang->v() << endl;
        out << "COLOR=" << saturation2Gang->v() << endl;
        out << "NOISE=" << noiseGang->v() << endl;
        out << "OLDFATTAL=" << (m_Ui->fftVersionCheckBox->isChecked() ? "NO" : "YES") << endl;
    }
    else if (current_page == m_Ui->page_ferradans)
    {
        out << "TMO=" << "Ferradans11" << endl;
        out << "RHO=" << rhoGang->v() << endl;
        out << "INV_ALPHA=" << inv_alphaGang->v() << endl;
    }
    else if (current_page == m_Ui->page_mai)
    {
        out << "TMO=" << "Mai11" << endl;
    }
    else if (current_page == m_Ui->page_ashikhmin)
    {
        out << "TMO=" << "Ashikhmin02" << endl;
        out << "SIMPLE=" << (m_Ui->simpleCheckBox->isChecked() ? "YES" : "NO") << endl;
        out << "EQUATION=" << (m_Ui->eq2RadioButton->isChecked() ? "2" : "4") << endl;
        out << "CONTRAST=" << contrastGang->v() << endl;
    }
    else if (current_page == m_Ui->page_durand)
    {
        out << "TMO=" << "Durand02" << endl;
        out << "SPATIAL=" << spatialGang->v() << endl;
        out << "RANGE=" << rangeGang->v() << endl;
        out << "BASE=" << baseGang->v() << endl;
    }
    else if (current_page == m_Ui->page_drago)
    {
        out << "TMO=" << "Drago03" << endl;
        out << "BIAS=" << biasGang->v() << endl;
    }
    else if (current_page == m_Ui->page_pattanaik)
    {
        out << "TMO=" << "Pattanaik00" << endl;
        out << "MULTIPLIER=" << multiplierGang->v() << endl;
        out << "LOCAL=" << (m_Ui->pattalocal->isChecked() ? "YES" : "NO") << endl;
        out << "AUTOLUMINANCE=" << (m_Ui->autoYcheckbox->isChecked() ? "YES" : "NO") << endl;
        out << "CONE=" << coneGang->v() << endl;
        out << "ROD=" << rodGang->v() << endl;
    }
    else if (current_page == m_Ui->page_reinhard02)
    {
        out << "TMO=" << "Reinhard02" << endl;
        out << "KEY=" << keyGang->v() << endl;
        out << "PHI=" << phiGang->v() << endl;
        out << "SCALES=" << (m_Ui->usescalescheckbox->isChecked() ? "YES" : "NO") << endl;
        out << "RANGE=" << range2Gang->v() << endl;
        out << "LOWER=" << lowerGang->v() << endl;
        out << "UPPER=" << upperGang->v() << endl;
    }
    else if (current_page == m_Ui->page_reinhard05)
    {
        out << "TMO=" << "Reinhard05" << endl;
        out << "BRIGHTNESS=" << brightnessGang->v() << endl;
        out << "CHROMATICADAPTATION=" << chromaticGang->v() << endl;
        out << "LIGHTADAPTATION=" << lightGang->v() << endl;
    }
    out << "PREGAMMA=" << pregammaGang->v() << endl;
    file.close();
}

void TonemappingPanel::fromTxt2Gui()
{
    QFile file(tmoSettingsFilename);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text) || file.size()==0)
    {
        QMessageBox::critical(this,tr("Aborting..."),tr("File is not readable (check permissions, path...)"),
                              QMessageBox::Ok,QMessageBox::NoButton);
        return;
    }
    QTextStream in(&file);
    QString field,value;

    while (!in.atEnd())
    {
        QString line = in.readLine();
        //skip comments
        if (line.startsWith('#'))
            continue;

        QString tmo; // Hack, same parameter "RANGE" in durand and reinhard02

        field=line.section('=',0,0); //get the field
        value=line.section('=',1,1); //get the value
        if (field == "TMOSETTINGSVERSION")
        {
            if (value != TMOSETTINGSVERSION)
            {
                QMessageBox::critical(this,tr("Aborting..."),tr("Error: The tone mapping settings file format has changed. This (old) file cannot be used with this version of LuminanceHDR. Create a new one."),
                                      QMessageBox::Ok,QMessageBox::NoButton);
                return;
            }
        }
        else if (field == "XSIZE")
        {
            int idx;
            for (idx = 0; idx < m_Ui->sizeComboBox->count(); idx++)
            {
                    if (sizes[idx] == value.toInt())
                        break;
            }
            if (idx == m_Ui->sizeComboBox->count()) // Custom XSIZE
            {
                sizes.push_back(value.toInt());
                fillCustomSizeComboBox();
                m_Ui->sizeComboBox->setCurrentIndex(m_Ui->sizeComboBox->count() - 1);
            }
            else
                m_Ui->sizeComboBox->setCurrentIndex(idx);
        }
        //else if ( field == "QUALITY" å)
        //{
        //    m_Ui->qualityHS->setValue(value.toInt());
        //    m_Ui->qualitySB->setValue(value.toInt());
        //}
        else if (field == "TMO")
        {
            if (value == "Ashikhmin02") {
                m_Ui->stackedWidget_operators->setCurrentWidget(m_Ui->page_ashikhmin);
                tmo = "Ashikhmin02";
            } else if (value == "Mantiuk06") {
                m_Ui->stackedWidget_operators->setCurrentWidget(m_Ui->page_mantiuk06);
                tmo = "Mantiuk06";
            } else if (value == "Mantiuk08") {
                m_Ui->stackedWidget_operators->setCurrentWidget(m_Ui->page_mantiuk08);
                tmo = "Mantiuk08";
            } else if (value == "Drago03") {
                m_Ui->stackedWidget_operators->setCurrentWidget(m_Ui->page_drago);
                tmo = "Drago03";
            } else if (value == "Durand02") {
                m_Ui->stackedWidget_operators->setCurrentWidget(m_Ui->page_durand);
                tmo = "Durand02";
            } else if (value == "Fattal02") {
                m_Ui->stackedWidget_operators->setCurrentWidget(m_Ui->page_fattal);
                tmo = "Fattal02";
            } else if (value == "Ferradans11") {
                m_Ui->stackedWidget_operators->setCurrentWidget(m_Ui->page_ferradans);
                tmo = "Ferradans11";
            } else if (value == "Mai11") {
                m_Ui->stackedWidget_operators->setCurrentWidget(m_Ui->page_mai);
                tmo = "Mai11";
            } else if (value == "Pattanaik00") {
                m_Ui->stackedWidget_operators->setCurrentWidget(m_Ui->page_pattanaik);
                tmo = "Pattanaik00";
            } else if (value == "Reinhard02") {
                m_Ui->stackedWidget_operators->setCurrentWidget(m_Ui->page_reinhard02);
                tmo = "Reinhard02";
            } else if (value == "Reinhard05") {
                m_Ui->stackedWidget_operators->setCurrentWidget(m_Ui->page_reinhard05);
                tmo = "Reinhard05";
            }
        } else if (field == "CONTRASTFACTOR") {
            m_Ui->contrastFactorSlider->setValue(contrastfactorGang->v2p(value.toFloat()));
        } else if (field == "SATURATIONFACTOR") {
            m_Ui->saturationFactorSlider->setValue(saturationfactorGang->v2p(value.toFloat()));
        } else if (field == "DETAILFACTOR") {
            m_Ui->detailFactorSlider->setValue(detailfactorGang->v2p(value.toFloat()));
        } else if (field == "CONTRASTEQUALIZATION") {
            m_Ui->contrastEqualizCheckBox->setChecked((value == "YES"));
        } else if (field == "COLORSATURATION") {
            m_Ui->contrastFactorSlider->setValue(colorSaturationGang->v2p(value.toFloat()));
        } else if (field == "CONTRASTENHANCEMENT") {
            m_Ui->saturationFactorSlider->setValue(contrastEnhancementGang->v2p(value.toFloat()));
        } else if (field == "LUMINANCELEVEL") {
            m_Ui->detailFactorSlider->setValue(luminanceLevelGang->v2p(value.toFloat()));
        } else if (field == "SIMPLE") {
            m_Ui->simpleCheckBox->setChecked((value == "YES"));
        } else if (field == "EQUATION") {
            m_Ui->eq2RadioButton->setChecked((value=="2"));
            m_Ui->eq4RadioButton->setChecked((value=="4"));
        } else if (field == "CONTRAST") {
            m_Ui->contrastSlider->setValue(contrastGang->v2p(value.toFloat()));
        } else if (field == "BIAS") {
            m_Ui->biasSlider->setValue(biasGang->v2p(value.toFloat()));
        } else if (field == "SPATIAL") {
            m_Ui->spatialSlider->setValue(spatialGang->v2p(value.toFloat()));
        } else if (field == "RANGE") {
            if (tmo == "Durand02")
                m_Ui->rangeSlider->setValue(rangeGang->v2p(value.toFloat()));
            else
                m_Ui->range2Slider->setValue(range2Gang->v2p(value.toFloat()));
        } else if (field == "BASE") {
            m_Ui->baseSlider->setValue(baseGang->v2p(value.toFloat()));
        } else if (field == "ALPHA") {
            m_Ui->alphaSlider->setValue(alphaGang->v2p(value.toFloat()));
        } else if (field == "BETA") {
            m_Ui->betaSlider->setValue(betaGang->v2p(value.toFloat()));
        } else if (field == "COLOR") {
            m_Ui->saturation2Slider->setValue(saturation2Gang->v2p(value.toFloat()));
        } else if (field == "NOISE") {
            m_Ui->noiseSlider->setValue(noiseGang->v2p(value.toFloat()));
        } else if (field == "OLDFATTAL") {
            m_Ui->fftVersionCheckBox->setChecked(value != "YES");
        } else if (field == "RHO") {
            m_Ui->rhoSlider->setValue(rhoGang->v2p(value.toFloat()));
        } else if (field == "INV_ALPHA") {
            m_Ui->inv_alphaSlider->setValue(inv_alphaGang->v2p(value.toFloat()));
        } else if (field == "MULTIPLIER") {
            m_Ui->multiplierSlider->setValue(multiplierGang->v2p(value.toFloat()));
        } else if (field == "LOCAL") {
            (value == "YES") ? m_Ui->pattalocal->setChecked(value == "YES") : m_Ui->pattalocal->setChecked(value=="NO");
        } else if (field == "AUTOLUMINANCE") {
            (value == "YES") ? m_Ui->autoYcheckbox->setChecked(value == "YES") : m_Ui->autoYcheckbox->setChecked(value=="NO");
        } else if (field == "CONE") {
            m_Ui->coneSlider->setValue(coneGang->v2p(value.toFloat()));
        } else if (field == "ROD") {
            m_Ui->rodSlider->setValue(rodGang->v2p(value.toFloat()));
        } else if (field == "KEY") {
            m_Ui->keySlider->setValue(keyGang->v2p(value.toFloat()));
        } else if (field == "PHI") {
            m_Ui->phiSlider->setValue(phiGang->v2p(value.toFloat()));
        } else if (field == "SCALES") {
            (value == "YES") ? m_Ui->usescalescheckbox->setChecked(value == "YES") : m_Ui->usescalescheckbox->setChecked(value=="NO");
        } else if (field == "LOWER") {
            m_Ui->lowerSlider->setValue(lowerGang->v2p(value.toFloat()));
        } else if (field == "UPPER") {
            m_Ui->upperSlider->setValue(upperGang->v2p(value.toFloat()));
        } else if (field == "BRIGHTNESS") {
            m_Ui->brightnessSlider->setValue(brightnessGang->v2p(value.toFloat()));
        } else if (field == "CHROMATICADAPTATION") {
            m_Ui->chromaticAdaptSlider->setValue(chromaticGang->v2p(value.toFloat()));
        } else if (field == "LIGHTADAPTATION") {
            m_Ui->lightAdaptSlider->setValue(lightGang->v2p(value.toFloat()));
        } else if (field == "PREGAMMA") {
            m_Ui->pregammaSlider->setValue(pregammaGang->v2p(value.toFloat()));
        }
    }
}

void TonemappingPanel::on_addCustomSizeButton_clicked()
{
    bool ok;
    int i = QInputDialog::getInt(this,
                                     tr("Custom LDR size"),
                                     tr("Enter the width of the new size:"), 0 , 0, 2147483647, 1, &ok);
    if (ok && i > 0)
    {
        sizes.push_back(i);
        fillCustomSizeComboBox();
        m_Ui->sizeComboBox->setCurrentIndex(m_Ui->sizeComboBox->count() - 1);
    }
}

void TonemappingPanel::fillCustomSizeComboBox()
{
    m_Ui->sizeComboBox->clear();
    for (int i = 0; i < sizes.size(); i++)
    {
        m_Ui->sizeComboBox->addItem( QString("%1x%2").arg(sizes[i]).arg( (int)(heightToWidthRatio*sizes[i]) ));
    }
}

void TonemappingPanel::setEnabled(bool b)
{
    if (b)
    {
        updateUndoState();
    }
    else
    {
        m_Ui->undoButton->setEnabled(false);
        m_Ui->redoButton->setEnabled(false);
    }
    m_Ui->tonemapGroupBox->setEnabled(b);
    m_Ui->groupSaveLoadTMOsetting->setEnabled(b);
    m_Ui->groupBoxExport->setEnabled(b);
    m_Ui->pregammaGroup->setEnabled(b);

    m_Ui->applyButton->setEnabled(b);
    m_Ui->queueButton->setEnabled(b);
    m_Ui->lblOpenQueue->setVisible(b);
    m_Ui->replaceLdrCheckBox->setEnabled(b);
    m_Ui->autoLevelsCheckBox->setEnabled(b);
    m_Ui->toolButtonThreshold->setEnabled(b);
/*
    // Operator select
    m_Ui->cmbOperators->setEnabled(b);
    m_Ui->stackedWidget_operators->setEnabled(b);

    // Load/Store/Reset
    m_Ui->loadsettingsbutton->setEnabled(b);
    m_Ui->savesettingsbutton->setEnabled(b);
    m_Ui->defaultButton->setEnabled(b);
    // Size
    m_Ui->sizeComboBox->setEnabled(b);
    m_Ui->addCustomSizeButton->setEnabled(b);

    // Gamma
    m_Ui->pregammadefault->setEnabled(b);
    m_Ui->pregammaSlider->setEnabled(b);
    m_Ui->pregammadsb->setEnabled(b);

    // Tonemap
    m_Ui->applyButton->setEnabled(b);
    m_Ui->queueButton->setEnabled(b);
    m_Ui->lblOpenQueue->setVisible(b);

    // DB
    m_Ui->loadButton->setEnabled(b);
    m_Ui->saveButton->setEnabled(b);

    //m_Ui->qualityHS->setEnabled(b);
    //m_Ui->qualitySB->setEnabled(b);

    m_Ui->replaceLdrCheckBox->setEnabled(b);
    m_Ui->autoLevelsCheckBox->setEnabled(b);

    // Labels
    m_Ui->lblOperators->setEnabled(b);
    m_Ui->groupSaveLoadTMOsetting->setEnabled(b);
    m_Ui->label->setEnabled(b);
    m_Ui->pregammaLabel->setEnabled(b);
    m_Ui->pregammaGroup->setEnabled(b);
*/
}

void TonemappingPanel::updatedHDR(pfs::Frame* f)
{
    setSizes(f->getWidth(), f->getHeight());
    m_currentFrame = f;
}

/*
 * This function should set the entire status.
 * Currently I'm only interested in changing the TM operator
 */
void TonemappingPanel::updateTonemappingParams(TonemappingOptions *opts)
{
    qDebug() << "TonemappingPanel::updateTonemappingParams(TonemappingOptions *opts)";
//    currentTmoOperator = opts->tmoperator;
//    updateUndoState();
    m_Ui->cmbOperators->setCurrentIndex(opts->tmoperator);
}

void TonemappingPanel::saveParameters()
{
    SavingParameters dialog;
    if (dialog.exec())
    {
        // Ashikhmin
        float lct;
        bool simple,
                eq2;
        // Drago
        float bias;
        // Durand
        float spatial,
                range,
                base;
        // Fattal
        float alpha,
                beta,
                colorSat,
                noiseReduction;
        bool oldFattal;
        // Ferradans
        float rho,
                inv_alpha;
        // Mantiuk 06
        float contrastFactor,
                saturationFactor,
                detailFactor;
        bool contrastEqualization;
        // Mantiuk 08
        float colorSaturation,
                contrastEnhancement,
                luminanceLevel;
        bool manualLuminanceLevel;
        // Pattanaik
        float multiplier,
                rod,
                cone;
        bool autolum,
                local;
        // Reinhard 02
        bool scales;
        float key,
                phi;
        int irange,
            lower,
            upper;
        // Reinhard 05
        float brightness,
                chromaticAdaptation,
                lightAdaptation;

        QString comment = dialog.getComment();

        switch (currentTmoOperator) {
            case ashikhmin:
                simple = simpleGang->isCheckBox1Checked();
                eq2 = eq2Gang->isRadioButton1Checked();
                lct = contrastGang->v();
                execAshikhminQuery(simple, eq2, lct, comment);
            break;
            case drago:
                bias = biasGang->v();
                execDragoQuery(bias, comment);
            break;
            case durand:
                spatial = spatialGang->v();
                range = rangeGang->v();
                base = baseGang->v();
                execDurandQuery(spatial, range, base, comment);
            break;
            case fattal:
                alpha = alphaGang->v();
                beta = betaGang->v();
                colorSat = saturation2Gang->v();
                noiseReduction = noiseGang->v();
                oldFattal = !fftSolverGang->isCheckBox1Checked();
                execFattalQuery(alpha, beta, colorSat, noiseReduction, oldFattal, comment);
            break;
            case ferradans:
                rho = rhoGang->v();
                inv_alpha = inv_alphaGang->v();
                execFerradansQuery(rho, inv_alpha, comment);
            break;
            case mai: //no options
            break;
            case mantiuk06:
                contrastFactor = contrastfactorGang->v();
                saturationFactor = saturationfactorGang->v();
                detailFactor = detailfactorGang->v();
                contrastEqualization = contrastfactorGang->isCheckBox1Checked();
                execMantiuk06Query(contrastEqualization, contrastFactor, saturationFactor, detailFactor, comment);
            break;
            case mantiuk08:
                colorSaturation = colorSaturationGang->v();
                contrastEnhancement = contrastEnhancementGang->v();
                luminanceLevel = luminanceLevelGang->v();
                manualLuminanceLevel = luminanceLevelGang->isCheckBox1Checked();
                execMantiuk08Query(colorSaturation, contrastEnhancement, luminanceLevel, manualLuminanceLevel, comment);
            break;
            case pattanaik:
                autolum=autoYGang->isCheckBox1Checked();
                local=pattalocalGang->isCheckBox1Checked();
                cone=coneGang->v();
                rod=rodGang->v();
                multiplier=multiplierGang->v();
                execPattanaikQuery(autolum, local, cone, rod, multiplier, comment);
            break;
            case reinhard02:
                scales = usescalesGang->isCheckBox1Checked();
                key = keyGang->v();
                phi = phiGang->v();
                irange = (int) range2Gang->v();
                lower = (int) lowerGang->v();
                upper = (int) upperGang->v();
                execReinhard02Query(scales, key, phi, irange, lower, upper, comment);
            break;
            case reinhard05:
                brightness = brightnessGang->v();
                chromaticAdaptation = chromaticGang->v();
                lightAdaptation = lightGang->v();
                execReinhard05Query(brightness, chromaticAdaptation, lightAdaptation, comment);
            break;
        }
    }
}

void TonemappingPanel::loadParameters()
{
    TonemappingSettings dialog(this, m_currentFrame);

    if (dialog.exec())
    {
        LuminanceOptions *luminance_options = new LuminanceOptions;
        setRealtimePreviews(false);
        TonemappingOptions *tmopts = dialog.getTonemappingOptions();
        // Ashikhmin
        bool simple,
                eq2;
        float lct;
        // Drago
        float bias;
        // Durand
        float spatial,
                range,
                base;
        // Fattal
        float alpha,
                beta,
                colorSat,
                noiseReduction;
        bool fftsolver;
        // Ferradans
        float rho,
                inv_alpha;
        // Mantiuk 06
        bool contrastEqualization;
        float contrastFactor;
        float saturationFactor;
        float detailFactor;
        // Mantiuk 08
        float colorSaturation,
                contrastEnhancement,
                luminanceLevel;
        bool manualLuminanceLevel;
        // Pattanaik
        float multiplier,
                rod,
                cone;
        bool autolum,
                local;
        // Reinhard 02
        bool scales;
        float key,
                phi;
        int irange,
            lower,
            upper;
        // Reinhard 05
        float brightness,
                chromaticAdaptation,
                lightAdaptation;
        // Pre-gamma
        float pregamma;

        switch (tmopts->tmoperator) {
            case ashikhmin:
                m_Ui->stackedWidget_operators->setCurrentIndex(ashikhmin);
                simple = tmopts->operator_options.ashikhminoptions.simple;
                eq2 = tmopts->operator_options.ashikhminoptions.eq2;
                lct = tmopts->operator_options.ashikhminoptions.lct;
                pregamma = tmopts->pregamma;
                m_Ui->simpleCheckBox->setChecked(simple);
                if (eq2)
                    m_Ui->eq2RadioButton->setChecked(true);
                else
                    m_Ui->eq4RadioButton->setChecked(true);
                m_Ui->contrastSlider->setValue(lct);
                m_Ui->contrastdsb->setValue(lct);
                m_Ui->pregammaSlider->setValue(pregamma);
                m_Ui->pregammadsb->setValue(pregamma);
            break;
            case drago:
                m_Ui->stackedWidget_operators->setCurrentIndex(drago);
                bias = tmopts->operator_options.dragooptions.bias;
                pregamma = tmopts->pregamma;
                m_Ui->biasSlider->setValue(bias);
                m_Ui->biasdsb->setValue(bias);
                m_Ui->pregammaSlider->setValue(pregamma);
                m_Ui->pregammadsb->setValue(pregamma);
            break;
            case durand:
                m_Ui->stackedWidget_operators->setCurrentIndex(durand);
                spatial = tmopts->operator_options.durandoptions.spatial;
                range = tmopts->operator_options.durandoptions.range;
                base = tmopts->operator_options.durandoptions.base;
                pregamma = tmopts->pregamma;
                m_Ui->spatialSlider->setValue(spatial);
                m_Ui->spatialdsb->setValue(spatial);
                m_Ui->rangeSlider->setValue(range);
                m_Ui->rangedsb->setValue(range);
                m_Ui->baseSlider->setValue(base);
                m_Ui->basedsb->setValue(base);
                m_Ui->pregammaSlider->setValue(pregamma);
                m_Ui->pregammadsb->setValue(pregamma);
            break;
            case fattal:
                m_Ui->stackedWidget_operators->setCurrentIndex(fattal);
                alpha = tmopts->operator_options.fattaloptions.alpha;
                beta = tmopts->operator_options.fattaloptions.beta;
                colorSat = tmopts->operator_options.fattaloptions.color;
                noiseReduction = tmopts->operator_options.fattaloptions.noiseredux;
                fftsolver = tmopts->operator_options.fattaloptions.fftsolver;
                pregamma = tmopts->pregamma;
                m_Ui->alphaSlider->setValue(alpha);
                m_Ui->alphadsb->setValue(alpha);
                m_Ui->betaSlider->setValue(beta);
                m_Ui->betadsb->setValue(beta);
                m_Ui->saturation2Slider->setValue(colorSat);
                m_Ui->saturation2dsb->setValue(colorSat);
                m_Ui->noiseSlider->setValue(noiseReduction);
                m_Ui->noisedsb->setValue(noiseReduction);
                m_Ui->fftVersionCheckBox->setChecked(fftsolver);
                m_Ui->pregammaSlider->setValue(pregamma);
                m_Ui->pregammadsb->setValue(pregamma);
            break;
            case ferradans:
                m_Ui->stackedWidget_operators->setCurrentIndex(ferradans);
                rho = tmopts->operator_options.ferradansoptions.rho;
                inv_alpha = tmopts->operator_options.ferradansoptions.inv_alpha;
                pregamma = tmopts->pregamma;
                m_Ui->rhoSlider->setValue(rho);
                m_Ui->rhodsb->setValue(rho);
                m_Ui->inv_alphaSlider->setValue(inv_alpha);
                m_Ui->inv_alphadsb->setValue(inv_alpha);
                m_Ui->pregammaSlider->setValue(pregamma);
                m_Ui->pregammadsb->setValue(pregamma);
            break;
            case mai:
                m_Ui->stackedWidget_operators->setCurrentIndex(mai);
                pregamma = tmopts->pregamma;
            break;
            case mantiuk06:
                m_Ui->stackedWidget_operators->setCurrentIndex(mantiuk06);
                contrastEqualization = tmopts->operator_options.mantiuk06options.contrastequalization;
                contrastFactor = tmopts->operator_options.mantiuk06options.contrastfactor;
                saturationFactor = tmopts->operator_options.mantiuk06options.saturationfactor;
                detailFactor = tmopts->operator_options.mantiuk06options.detailfactor;
                pregamma = tmopts->pregamma;
                m_Ui->contrastEqualizCheckBox->setChecked(contrastEqualization);
                m_Ui->contrastFactorSlider->setValue(contrastFactor);
                m_Ui->contrastFactordsb->setValue(contrastFactor);
                m_Ui->saturationFactorSlider->setValue(saturationFactor);
                m_Ui->saturationFactordsb->setValue(saturationFactor);
                m_Ui->detailFactorSlider->setValue(detailFactor);
                m_Ui->detailFactordsb->setValue(detailFactor);
                m_Ui->pregammaSlider->setValue(pregamma);
                m_Ui->pregammadsb->setValue(pregamma);
            break;
            case mantiuk08:
                m_Ui->stackedWidget_operators->setCurrentIndex(mantiuk08);
                colorSaturation = tmopts->operator_options.mantiuk08options.colorsaturation;
                contrastEnhancement = tmopts->operator_options.mantiuk08options.contrastenhancement;
                luminanceLevel = tmopts->operator_options.mantiuk08options.luminancelevel;
                manualLuminanceLevel = tmopts->operator_options.mantiuk08options.setluminance;
                pregamma = tmopts->pregamma;
                m_Ui->colorSaturationSlider->setValue(colorSaturation);
                m_Ui->colorSaturationDSB->setValue(colorSaturation);
                m_Ui->contrastEnhancementSlider->setValue(contrastEnhancement);
                m_Ui->contrastEnhancementDSB->setValue(contrastEnhancement);
                m_Ui->luminanceLevelSlider->setValue(luminanceLevel);
                m_Ui->luminanceLevelDSB->setValue(luminanceLevel);
                m_Ui->luminanceLevelCheckBox->setChecked(manualLuminanceLevel);
                m_Ui->pregammaSlider->setValue(pregamma);
                m_Ui->pregammadsb->setValue(pregamma);
            break;
            case pattanaik:
                m_Ui->stackedWidget_operators->setCurrentIndex(pattanaik);
                multiplier = tmopts->operator_options.pattanaikoptions.multiplier;
                rod = tmopts->operator_options.pattanaikoptions.rod;
                cone = tmopts->operator_options.pattanaikoptions.cone;
                autolum = tmopts->operator_options.pattanaikoptions.autolum;
                local = tmopts->operator_options.pattanaikoptions.local;
                pregamma = tmopts->pregamma;
                m_Ui->multiplierSlider->setValue(multiplier);
                m_Ui->multiplierdsb->setValue(multiplier);
                m_Ui->coneSlider->setValue(cone);
                m_Ui->conedsb->setValue(cone);
                m_Ui->rodSlider->setValue(rod);
                m_Ui->roddsb->setValue(rod);
                m_Ui->pattalocal->setChecked(local);
                m_Ui->autoYcheckbox->setChecked(autolum);
                m_Ui->pregammaSlider->setValue(pregamma);
                m_Ui->pregammadsb->setValue(pregamma);
            break;
            case reinhard02:
                m_Ui->stackedWidget_operators->setCurrentIndex(reinhard02);
                scales = tmopts->operator_options.reinhard02options.scales;
                key = tmopts->operator_options.reinhard02options.key;
                phi = tmopts->operator_options.reinhard02options.phi;
                irange = tmopts->operator_options.reinhard02options.range;
                lower = tmopts->operator_options.reinhard02options.lower;
                upper = tmopts->operator_options.reinhard02options.upper;
                pregamma = tmopts->pregamma;
                m_Ui->usescalescheckbox->setChecked(scales);
                m_Ui->keySlider->setValue(key);
                m_Ui->keydsb->setValue(key);
                m_Ui->phiSlider->setValue(phi);
                m_Ui->phidsb->setValue(phi);
                m_Ui->range2Slider->setValue(irange);
                m_Ui->range2dsb->setValue(irange);
                m_Ui->lowerSlider->setValue(lower);
                m_Ui->lowerdsb->setValue(lower);
                m_Ui->upperSlider->setValue(upper);
                m_Ui->upperdsb->setValue(upper);
                m_Ui->pregammaSlider->setValue(pregamma);
                m_Ui->pregammadsb->setValue(pregamma);
            break;
            case reinhard05:
                m_Ui->stackedWidget_operators->setCurrentIndex(reinhard05);
                brightness = tmopts->operator_options.reinhard05options.brightness;
                chromaticAdaptation = tmopts->operator_options.reinhard05options.chromaticAdaptation;
                lightAdaptation = tmopts->operator_options.reinhard05options.lightAdaptation;
                pregamma = tmopts->pregamma;
                m_Ui->brightnessSlider->setValue(brightness);
                m_Ui->brightnessdsb->setValue(brightness);
                m_Ui->chromaticAdaptSlider->setValue(chromaticAdaptation);
                m_Ui->chromaticAdaptdsb->setValue(chromaticAdaptation);
                m_Ui->lightAdaptSlider->setValue(lightAdaptation);
                m_Ui->lightAdaptdsb->setValue(lightAdaptation);
                m_Ui->pregammaSlider->setValue(pregamma);
                m_Ui->pregammadsb->setValue(pregamma);
            break;
        }
        if (dialog.wantsTonemap()) {
            TonemappingOptions *t = new TonemappingOptions(*tmopts);
            toneMappingOptionsToDelete.push_back(t);
            t->origxsize = sizes[0];
            t->xsize = sizes[0];
            emit startTonemapping(t);
        }
        setRealtimePreviews(luminance_options->isRealtimePreviewsActive());
        delete luminance_options;
    }
}

void TonemappingPanel::execMantiuk06Query(bool contrastEqualization, float contrastFactor, float saturationFactor,
    float detailFactor, QString comment)
{
    qDebug() << "TonemappingPanel::execMantiuk06Query";
    QSqlDatabase db = QSqlDatabase::database();
    QSqlQuery query(db);
    float pregamma = m_Ui->pregammadsb->value();
    query.prepare("INSERT INTO mantiuk06 (contrastEqualization, contrastFactor, saturationFactor, detailFactor, pregamma, comment) "
                "VALUES (:contrastEqualization, :contrastFactor, :saturationFactor, :detailFactor, :pregamma, :comment)");
    query.bindValue(":contrastEqualization", contrastEqualization);
    query.bindValue(":contrastFactor", contrastFactor);
    query.bindValue(":saturationFactor", saturationFactor);
    query.bindValue(":detailFactor", detailFactor);
    query.bindValue(":pregamma", pregamma);
    query.bindValue(":comment", comment);
    bool res = query.exec();
    if (res == false)
        qDebug() << query.lastError();
}

void TonemappingPanel::execMantiuk08Query(float colorSaturation, float contrastEnhancement, float luminanceLevel,
    bool manualLuminanceLevel, QString comment)
{
    qDebug() << "TonemappingPanel::execMantiuk08Query";
    QSqlDatabase db = QSqlDatabase::database();
    QSqlQuery query(db);
    float pregamma = m_Ui->pregammadsb->value();
    query.prepare("INSERT INTO mantiuk08 (colorSaturation, contrastEnhancement, luminanceLevel, manualLuminanceLevel, pregamma, comment) "
                "VALUES (:colorSaturation, :contrastEnhancement, :luminanceLevel, :manualLuminanceLevel, :pregamma, :comment)");
    query.bindValue(":colorSaturation", colorSaturation);
    query.bindValue(":contrastEnhancement", contrastEnhancement);
    query.bindValue(":luminanceLevel", luminanceLevel);
    query.bindValue(":manualLuminanceLevel", manualLuminanceLevel);
    query.bindValue(":pregamma", pregamma);
    query.bindValue(":comment", comment);
    bool res = query.exec();
    if (res == false)
        qDebug() << query.lastError();
}

void TonemappingPanel::execAshikhminQuery(bool simple, bool eq2, float lct, QString comment)
{
    qDebug() << "TonemappingPanel::execAshikhminQuery";
    QSqlDatabase db = QSqlDatabase::database();
    QSqlQuery query(db);
    float pregamma = m_Ui->pregammadsb->value();
    query.prepare("INSERT INTO ashikhmin (simple, eq2, lct, pregamma, comment) "
                "VALUES (:simple, :eq2, :lct, :pregamma, :comment)");
    query.bindValue(":simple", simple);
    query.bindValue(":eq2", eq2);
    query.bindValue(":lct", lct);
    query.bindValue(":pregamma", pregamma);
    query.bindValue(":comment", comment);
    bool res = query.exec();
    if (res == false)
        qDebug() << query.lastError();
}

void TonemappingPanel::execDragoQuery(float bias, QString comment)
{
    qDebug() << "TonemappingPanel::execDragoQuery";
    QSqlDatabase db = QSqlDatabase::database();
    QSqlQuery query(db);
    float pregamma = m_Ui->pregammadsb->value();
    query.prepare("INSERT INTO drago (bias, pregamma, comment) "
                "VALUES (:bias, :pregamma, :comment)");
    query.bindValue(":bias", bias);
    query.bindValue(":pregamma", pregamma);
    query.bindValue(":comment", comment);
    bool res = query.exec();
    if (res == false)
        qDebug() << query.lastError();
}

void TonemappingPanel::execDurandQuery(float spatial, float range, float base, QString comment)
{
    qDebug() << "TonemappingPanel::execDurandQuery";
    QSqlDatabase db = QSqlDatabase::database();
    QSqlQuery query(db);
    float pregamma = m_Ui->pregammadsb->value();
    query.prepare("INSERT INTO durand (spatial, range, base, pregamma, comment) "
                "VALUES (:spatial, :range, :base, :pregamma, :comment)");
    query.bindValue(":spatial", spatial);
    query.bindValue(":base", base);
    query.bindValue(":range", range);
    query.bindValue(":pregamma", pregamma);
    query.bindValue(":comment", comment);
    bool res = query.exec();
    if (res == false)
        qDebug() << query.lastError();
}

void TonemappingPanel::execFattalQuery(float alpha, float beta, float colorSaturation, float noiseReduction, bool oldFattal, QString comment)
{
    qDebug() << "TonemappingPanel::execFattalQuery";
    QSqlDatabase db = QSqlDatabase::database();
    QSqlQuery query(db);
    float pregamma = m_Ui->pregammadsb->value();
    query.prepare("INSERT INTO fattal (alpha, beta, colorSaturation, noiseReduction, oldFattal, pregamma, comment) "
                "VALUES (:alpha, :beta, :colorSaturation, :noiseReduction, :oldFattal, :pregamma, :comment)");
    query.bindValue(":alpha", alpha);
    query.bindValue(":beta", beta);
    query.bindValue(":colorSaturation", colorSaturation);
    query.bindValue(":noiseReduction", noiseReduction);
    query.bindValue(":oldFattal", oldFattal);
    query.bindValue(":pregamma", pregamma);
    query.bindValue(":comment", comment);
    bool res = query.exec();
    if (res == false)
        qDebug() << query.lastError();
}

void TonemappingPanel::execFerradansQuery(float rho, float inv_alpha, QString comment)
{
    qDebug() << "TonemappingPanel::execFerradansQuery";
    QSqlDatabase db = QSqlDatabase::database();
    QSqlQuery query(db);
    float pregamma = m_Ui->pregammadsb->value();
    query.prepare("INSERT INTO ferradans (rho, inv_alpha, pregamma, comment) "
                "VALUES (:rho, :inv_alpha, :pregamma, :comment)");
    query.bindValue(":rho", rho);
    query.bindValue(":inv_alpha", inv_alpha);
    query.bindValue(":pregamma", pregamma);
    query.bindValue(":comment", comment);
    bool res = query.exec();
    if (res == false)
        qDebug() << query.lastError();
}
void TonemappingPanel::execPattanaikQuery(bool autolum, bool local, float cone, float rod, float multiplier, QString comment)
{
    qDebug() << "TonemappingPanel::execPattanaikQuery";
    QSqlDatabase db = QSqlDatabase::database();
    QSqlQuery query(db);
    float pregamma = m_Ui->pregammadsb->value();
    query.prepare("INSERT INTO pattanaik (autolum, local, cone, rod, multiplier, pregamma, comment) "
                "VALUES (:autolum, :local, :cone, :rod, :multiplier, :pregamma, :comment)");
    query.bindValue(":autolum", autolum);
    query.bindValue(":local", local);
    query.bindValue(":cone", cone);
    query.bindValue(":rod", rod);
    query.bindValue(":multiplier", multiplier);
    query.bindValue(":pregamma", pregamma);
    query.bindValue(":comment", comment);
    bool res = query.exec();
    if (res == false)
        qDebug() << query.lastError();
}

void TonemappingPanel::execReinhard02Query(bool scales, float key, float phi, int range, int lower, int upper, QString comment)
{
    qDebug() << "TonemappingPanel::execReinhard02Query";
    QSqlDatabase db = QSqlDatabase::database();
    QSqlQuery query(db);
    float pregamma = m_Ui->pregammadsb->value();
    query.prepare("INSERT INTO reinhard02 (scales, key, phi, range, lower, upper, pregamma, comment) "
                "VALUES (:scales, :key, :phi, :range, :lower, :upper, :pregamma, :comment)");
    query.bindValue(":scales", scales);
    query.bindValue(":key", key);
    query.bindValue(":phi", phi);
    query.bindValue(":range", range);
    query.bindValue(":lower", lower);
    query.bindValue(":upper", upper);
    query.bindValue(":pregamma", pregamma);
    query.bindValue(":comment", comment);
    bool res = query.exec();
    if (res == false)
        qDebug() << query.lastError();
}

void TonemappingPanel::execReinhard05Query(float brightness, float chromaticAdaptation, float lightAdaptation, QString comment)
{
    qDebug() << "TonemappingPanel::execReinhard05Query";
    QSqlDatabase db = QSqlDatabase::database();
    QSqlQuery query(db);
    float pregamma = m_Ui->pregammadsb->value();
    query.prepare("INSERT INTO reinhard05 (brightness, chromaticAdaptation, lightAdaptation, pregamma, comment) "
                "VALUES (:brightness, :chromaticAdaptation, :lightAdaptation, :pregamma, :comment)");
    query.bindValue(":brightness", brightness);
    query.bindValue(":chromaticAdaptation", chromaticAdaptation);
    query.bindValue(":lightAdaptation", lightAdaptation);
    query.bindValue(":pregamma", pregamma);
    query.bindValue(":comment", comment);
    bool res = query.exec();
    if (res == false)
        qDebug() << query.lastError();
}

bool TonemappingPanel::replaceLdr()
{
    return m_Ui->replaceLdrCheckBox->isChecked();
}

bool TonemappingPanel::doAutoLevels()
{
    return m_Ui->autoLevelsCheckBox->isChecked();
}

float TonemappingPanel::getAutoLevelsThreshold()
{
    return m_autolevelThreshold;
}

void TonemappingPanel::updatePreviews(double v)
{
    int index = m_Ui->stackedWidget_operators->currentIndex();
    TonemappingOptions *tmopts = new TonemappingOptions(*toneMappingOptions); // make a copy
    fillToneMappingOptions(false);
    QObject* eventSender(sender());
    // Mantiuk06
    if (eventSender == m_Ui->contrastFactordsb)
        tmopts->operator_options.mantiuk06options.contrastfactor = v;
    else if(eventSender == m_Ui->saturationFactordsb)
        tmopts->operator_options.mantiuk06options.saturationfactor = v;
    else if(eventSender == m_Ui->detailFactordsb)
        tmopts->operator_options.mantiuk06options.detailfactor = v;
    // Mantiuk08
    else if(eventSender == m_Ui->colorSaturationDSB)
        tmopts->operator_options.mantiuk08options.colorsaturation = v;
    else if(eventSender == m_Ui->contrastEnhancementDSB)
        tmopts->operator_options.mantiuk08options.contrastenhancement = v;
    else if(eventSender == m_Ui->luminanceLevelDSB)
        tmopts->operator_options.mantiuk08options.luminancelevel = v;
    // Fattal
    else if(eventSender == m_Ui->alphadsb)
        tmopts->operator_options.fattaloptions.alpha = v;
    else if(eventSender == m_Ui->betadsb)
        tmopts->operator_options.fattaloptions.beta = v;
    else if(eventSender == m_Ui->saturation2dsb)
        tmopts->operator_options.fattaloptions.color = v;
    else if(eventSender == m_Ui->noisedsb)
        tmopts->operator_options.fattaloptions.noiseredux = v;
    // Ferradans
    else if(eventSender == m_Ui->rhodsb)
        tmopts->operator_options.ferradansoptions.rho = v;
    else if(eventSender == m_Ui->inv_alphadsb)
        tmopts->operator_options.ferradansoptions.inv_alpha = v;
    // Drago
    else if(eventSender == m_Ui->biasdsb)
        tmopts->operator_options.dragooptions.bias = v;
    // Durand
    else if(eventSender == m_Ui->basedsb)
        tmopts->operator_options.durandoptions.base = v;
    else if(eventSender == m_Ui->spatialdsb)
        tmopts->operator_options.durandoptions.spatial = v;
    else if(eventSender == m_Ui->rangedsb)
        tmopts->operator_options.durandoptions.range = v;
    // Reinhard02
    else if(eventSender == m_Ui->keydsb)
        tmopts->operator_options.reinhard02options.key = v;
    else if(eventSender == m_Ui->phidsb)
        tmopts->operator_options.reinhard02options.phi = v;
    else if(eventSender == m_Ui->range2dsb)
        tmopts->operator_options.reinhard02options.range = (int)v;
    else if(eventSender == m_Ui->lowerdsb)
        tmopts->operator_options.reinhard02options.lower = (int)v;
    else if(eventSender == m_Ui->upperdsb)
        tmopts->operator_options.reinhard02options.upper = (int)v;
    // Reinhard05
    else if(eventSender == m_Ui->brightnessdsb)
        tmopts->operator_options.reinhard05options.brightness = v;
    else if(eventSender == m_Ui->chromaticAdaptdsb)
        tmopts->operator_options.reinhard05options.chromaticAdaptation = v;
    else if(eventSender == m_Ui->lightAdaptdsb)
        tmopts->operator_options.reinhard05options.lightAdaptation = v;
    // Ashikhmin
    else if(eventSender == m_Ui->contrastdsb)
        tmopts->operator_options.ashikhminoptions.lct = v;
    // Pattanaik
    else if(eventSender == m_Ui->multiplierdsb)
        tmopts->operator_options.pattanaikoptions.multiplier = v;
    else if(eventSender == m_Ui->conedsb)
        tmopts->operator_options.pattanaikoptions.cone = v;
    else if(eventSender == m_Ui->roddsb)
        tmopts->operator_options.pattanaikoptions.rod = v;
    //else if(eventSender == m_Ui->pregammadsb)
    //    tmopts->pregamma = v;

    if (index >= 0)
    {
        if(eventSender == m_Ui->pregammadsb)
        {
            int maxIndex = m_Ui->stackedWidget_operators->count();
            for (int i = 0; i < maxIndex; i++)
            {
                updateCurrentTmoOperator(i);
                fillToneMappingOptions(false);
                TonemappingOptions *tmopts = new TonemappingOptions(*toneMappingOptions); // make a copy
                tmopts->pregamma = v;
                m_previewPanel->getLabel(i)->setTonemappingOptions(tmopts);
                m_previewPanel->updatePreviews(m_currentFrame, i);
            }
            updateCurrentTmoOperator(index);
        }
        else
        {
            m_previewPanel->getLabel(index)->setTonemappingOptions(tmopts);
            m_previewPanel->updatePreviews(m_currentFrame, index);
        }
    }
    delete tmopts;
}

void TonemappingPanel::updatePreviewsCB(int state)
{
    int index = m_Ui->stackedWidget_operators->currentIndex();
    TonemappingOptions *tmopts = new TonemappingOptions(*toneMappingOptions); // make a copy
    fillToneMappingOptions(false);
    QObject* eventSender(sender());
    // Mantiuk06
    if (eventSender == m_Ui->contrastEqualizCheckBox)
        tmopts->operator_options.mantiuk06options.contrastequalization = state;
    // Mantiuk08
    else if (eventSender == m_Ui->luminanceLevelCheckBox)
        tmopts->operator_options.mantiuk08options.luminancelevel = state;
    // Fattal
    else if (eventSender == m_Ui->fftVersionCheckBox)
        tmopts->operator_options.fattaloptions.fftsolver = state;
    // Reinhard02
    else if (eventSender == m_Ui->usescalescheckbox)
        tmopts->operator_options.reinhard02options.scales = state;
    // Ashikhmin
    else if (eventSender == m_Ui->simpleCheckBox)
        tmopts->operator_options.ashikhminoptions.simple = state;
    // Pattanaik
    else if (eventSender == m_Ui->pattalocal)
        tmopts->operator_options.pattanaikoptions.local = state;
    else if (eventSender == m_Ui->autoYcheckbox)
        tmopts->operator_options.pattanaikoptions.autolum = state;

    if (index >= 0)
    {
        m_previewPanel->getLabel(index)->setTonemappingOptions(tmopts);
        m_previewPanel->updatePreviews(m_currentFrame, index);
    }
    delete tmopts;
}

void TonemappingPanel::updatePreviewsRB(bool toggled)
{
    int index = m_Ui->stackedWidget_operators->currentIndex();
    TonemappingOptions *tmopts = new TonemappingOptions(*toneMappingOptions); // make a copy
    fillToneMappingOptions(false);

    // Only one sender: Ashikhmin
    tmopts->operator_options.ashikhminoptions.eq2 = toggled;

    if (index >= 0)
    {
        m_previewPanel->getLabel(index)->setTonemappingOptions(tmopts);
        m_previewPanel->updatePreviews(m_currentFrame, index);
    }
    delete tmopts;
}

void TonemappingPanel::setRealtimePreviews(bool toggled)
{
    if (toggled) {
        fillToneMappingOptions(false);

        //Mantiuk06
        connect(m_Ui->contrastFactordsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->saturationFactordsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->detailFactordsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->contrastEqualizCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updatePreviewsCB(int)));

        //Mantiuk08
        connect(m_Ui->colorSaturationDSB, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->contrastEnhancementDSB, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->luminanceLevelDSB, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->luminanceLevelCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updatePreviewsCB(int)));

        //Fattal
        connect(m_Ui->alphadsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->betadsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->saturation2dsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->noisedsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->fftVersionCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updatePreviewsCB(int)));

        //Ferradans
        connect(m_Ui->rhodsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->inv_alphadsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));

        //Drago
        connect(m_Ui->biasdsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));

        //Durand
        connect(m_Ui->basedsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->spatialdsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->rangedsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));

        //Reinhard02
        connect(m_Ui->keydsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->phidsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->range2dsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->lowerdsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->upperdsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->usescalescheckbox, SIGNAL(stateChanged(int)), this, SLOT(updatePreviewsCB(int)));

        //Reinhard05
        connect(m_Ui->brightnessdsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->chromaticAdaptdsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->lightAdaptdsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));

        //Ashikhmin
        connect(m_Ui->contrastdsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->simpleCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updatePreviewsCB(int)));
        connect(m_Ui->eq2RadioButton, SIGNAL(toggled(bool)), this, SLOT(updatePreviewsRB(bool)));

        //Pattanaik
        connect(m_Ui->multiplierdsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->conedsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->roddsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        connect(m_Ui->pattalocal, SIGNAL(stateChanged(int)), this, SLOT(updatePreviewsCB(int)));
        connect(m_Ui->autoYcheckbox, SIGNAL(stateChanged(int)), this, SLOT(updatePreviewsCB(int)));

        //GLOBAL Pregamma
        connect(m_Ui->pregammadsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
    }
    else {
        disconnect(m_Ui->contrastFactordsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        disconnect(m_Ui->saturationFactordsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        disconnect(m_Ui->detailFactordsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));

        disconnect(m_Ui->colorSaturationDSB, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        disconnect(m_Ui->contrastEnhancementDSB, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        disconnect(m_Ui->luminanceLevelDSB, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));

        disconnect(m_Ui->alphadsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        disconnect(m_Ui->betadsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        disconnect(m_Ui->saturation2dsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        disconnect(m_Ui->noisedsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));

        disconnect(m_Ui->rhodsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        disconnect(m_Ui->inv_alphadsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));

        disconnect(m_Ui->biasdsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));

        disconnect(m_Ui->basedsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        disconnect(m_Ui->spatialdsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        disconnect(m_Ui->rangedsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));

        disconnect(m_Ui->keydsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        disconnect(m_Ui->phidsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        disconnect(m_Ui->range2dsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        disconnect(m_Ui->lowerdsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        disconnect(m_Ui->upperdsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));


        disconnect(m_Ui->brightnessdsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        disconnect(m_Ui->chromaticAdaptdsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        disconnect(m_Ui->lightAdaptdsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));

        disconnect(m_Ui->contrastdsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));

        disconnect(m_Ui->multiplierdsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        disconnect(m_Ui->conedsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));
        disconnect(m_Ui->roddsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));

        disconnect(m_Ui->pregammadsb, SIGNAL(valueChanged(double)), this, SLOT(updatePreviews(double)));

        disconnect(m_Ui->contrastEqualizCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updatePreviewsCB(int)));

        disconnect(m_Ui->luminanceLevelCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updatePreviewsCB(int)));

        disconnect(m_Ui->fftVersionCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updatePreviewsCB(int)));

        disconnect(m_Ui->usescalescheckbox, SIGNAL(stateChanged(int)), this, SLOT(updatePreviewsCB(int)));

        disconnect(m_Ui->simpleCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updatePreviewsCB(int)));

        disconnect(m_Ui->pattalocal, SIGNAL(stateChanged(int)), this, SLOT(updatePreviewsCB(int)));
        disconnect(m_Ui->autoYcheckbox, SIGNAL(stateChanged(int)), this, SLOT(updatePreviewsCB(int)));

        disconnect(m_Ui->eq2RadioButton, SIGNAL(toggled(bool)), this, SLOT(updatePreviewsRB(bool)));
    }
}

void TonemappingPanel::on_pattalocal_toggled(bool b)
{
    bool autoY = m_Ui->autoYcheckbox->isChecked();

    m_Ui->label_cone->setDisabled(b || autoY);
    m_Ui->coneSlider->setDisabled(b || autoY);
    m_Ui->conedsb->setDisabled(b || autoY);
    m_Ui->label_rod->setDisabled(b || autoY);
    m_Ui->rodSlider->setDisabled(b || autoY);
    m_Ui->roddsb->setDisabled(b || autoY);
}

void TonemappingPanel::autoLevels(bool b)
{
    emit autoLevels(b, m_autolevelThreshold);
}

void TonemappingPanel::on_toolButtonThreshold_clicked()
{
    QPoint pos = mapToGlobal(m_Ui->toolButtonThreshold->pos());
    m_thd->move(pos.x() - 40, pos.y() - 20);
    m_thd->show();
}

void TonemappingPanel::thresholdReady()
{
    m_autolevelThreshold = m_thd->threshold();
    m_thd->hide();
    emit autoLevels(doAutoLevels(), m_autolevelThreshold);
}
// ------------------------- // END FILE
