/**
 * \file pappsomspp/widget/precisionwidget/precisionwidget.cpp
 * \date 5/1/2018
 * \author Olivier Langella
 * \brief edit presicion in ppm or dalton
 */


/*******************************************************************************
 * Copyright (c) 2018 Olivier Langella <Olivier.Langella@u-psud.fr>.
 *
 * This file is part of the PAPPSOms++ library.
 *
 *     PAPPSOms++ 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 3 of the License, or
 *     (at your option) any later version.
 *
 *     PAPPSOms++ 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 PAPPSOms++.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Contributors:
 *     Olivier Langella <Olivier.Langella@u-psud.fr> - initial API and
 *implementation
 ******************************************************************************/

#include "pappsomspp/core/exception/exceptionnotpossible.h"
#include "precisionwidget.h"
#include <QHBoxLayout>
#include <QDebug>


namespace pappso
{

PrecisionWidget::PrecisionWidget(QWidget *parent) : QWidget(parent)
{
  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__
  //<< "PrecisionWidget::PrecisionWidget begin";
  setLayout(new QHBoxLayout(this));

  this->layout()->setContentsMargins(0, 0, 0, 0);

  // Each precision type has its own double spin box.
  mp_daltonValueSpinBox = new QDoubleSpinBox();
  this->layout()->addWidget(mp_daltonValueSpinBox);

  mp_ppmValueSpinBox = new QDoubleSpinBox();
  this->layout()->addWidget(mp_ppmValueSpinBox);

  mp_resValueSpinBox = new QDoubleSpinBox();
  this->layout()->addWidget(mp_resValueSpinBox);

  mp_unitComboBox = new QComboBox();
  this->layout()->addWidget(mp_unitComboBox);

  mp_unitComboBox->addItem("dalton", QString("dalton"));
  mp_unitComboBox->addItem("ppm", QString("ppm"));
  mp_unitComboBox->addItem("res", QString("res"));

  mp_precisionDalton = PrecisionFactory::getDaltonInstance(0.02);
  mp_precisionPpm    = PrecisionFactory::getPpmInstance(10);
  mp_precisionRes    = PrecisionFactory::getResInstance(20000);

  mp_daltonValueSpinBox->setDecimals(6);
  mp_daltonValueSpinBox->setSingleStep(0.01);
  mp_daltonValueSpinBox->setRange(0, 30);

  mp_ppmValueSpinBox->setDecimals(4);
  mp_ppmValueSpinBox->setSingleStep(10);
  mp_ppmValueSpinBox->setRange(0.0001, 300);

  mp_resValueSpinBox->setDecimals(0);
  mp_resValueSpinBox->setSingleStep(1000);
  mp_resValueSpinBox->setRange(1, 2000000);

  // By default set precision to be of the Dalton type.
  setPrecision(mp_precisionDalton);

  connect(mp_unitComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setCurrentIndex(int)));

  connect(
    mp_daltonValueSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setDaltonValueChanged(double)));

  connect(mp_ppmValueSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setPpmValueChanged(double)));

  connect(mp_resValueSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setResValueChanged(double)));

  m_oldIndex = -1;
  // qDebug() << "PrecisionWidget::PrecisionWidget end";
}

PrecisionWidget::~PrecisionWidget()
{
}

void
PrecisionWidget::setCurrentIndex(int index)
{
  // qDebug() << "PrecisionWidget::setCurrentIndex index=" << index;

  if(m_oldIndex != index)
    {
      m_oldIndex = index;

      if(mp_unitComboBox->itemData(index) == "dalton")
        {
          mp_daltonValueSpinBox->setValue(mp_precisionDalton->getNominal());
          mp_daltonValueSpinBox->setVisible(true);

          mp_ppmValueSpinBox->setVisible(false);
          mp_resValueSpinBox->setVisible(false);

          emit precisionChanged(mp_precisionDalton);
        }
      else if(mp_unitComboBox->itemData(index) == "ppm")
        {
          mp_ppmValueSpinBox->setValue(mp_precisionPpm->getNominal());
          mp_ppmValueSpinBox->setVisible(true);

          mp_daltonValueSpinBox->setVisible(false);
          mp_resValueSpinBox->setVisible(false);

          emit precisionChanged(mp_precisionPpm);
        }
      else if(mp_unitComboBox->itemData(index) == "res")
        {
          mp_resValueSpinBox->setValue(mp_precisionRes->getNominal());
          mp_resValueSpinBox->setVisible(true);

          mp_daltonValueSpinBox->setVisible(false);
          mp_ppmValueSpinBox->setVisible(false);

          emit precisionChanged(mp_precisionRes);
        }
      else
        {
          throw ExceptionNotPossible(
            "precisionwidget.cpp @ setCurrentIndex(int index) -- ERROR "
            "programming error.");
        }
    }
}


void
PrecisionWidget::setDaltonValueChanged(double value)
{
  // qDebug() << "dalton PrecisionWidget::setValueChanged value=" << value;

  PrecisionPtr precision = PrecisionFactory::getDaltonInstance(value);
  if(mp_precisionDalton != precision)
    {
      mp_precisionDalton = precision;
      emit precisionChanged(mp_precisionDalton);
    }
}


void
PrecisionWidget::setPpmValueChanged(double value)
{
  // qDebug() << "ppm PrecisionWidget::setValueChanged value=" << value;

  PrecisionPtr precision = PrecisionFactory::getPpmInstance(value);
  if(mp_precisionPpm != precision)
    {
      mp_precisionPpm = precision;
      emit precisionChanged(mp_precisionPpm);
    }
}


void
PrecisionWidget::setResValueChanged(double value)
{
  // qDebug() << "res PrecisionWidget::setValueChanged value=" << value;

  PrecisionPtr precision = PrecisionFactory::getResInstance(value);
  if(mp_precisionRes != precision)
    {
      mp_precisionRes = precision;
      emit precisionChanged(mp_precisionRes);
    }
}


const PrecisionPtr &
PrecisionWidget::getPrecision() const
{
  if(mp_unitComboBox->itemData(mp_unitComboBox->currentIndex()) == "dalton")
    {
      return mp_precisionDalton;
    }
  else if(mp_unitComboBox->itemData(mp_unitComboBox->currentIndex()) == "ppm")
    {
      return mp_precisionPpm;
    }
  else if(mp_unitComboBox->itemData(mp_unitComboBox->currentIndex()) == "res")
    {
      return mp_precisionRes;
    }
  else
    {
      throw ExceptionNotPossible("precisionwidget.cpp @ getPrecision()-- ERROR programming error.");
    }
}


void
PrecisionWidget::setPrecision(PrecisionPtr precision)
{

  if(precision->unit() == Enums::PrecisionUnit::dalton)
    {
      mp_precisionDalton = precision;
      mp_unitComboBox->setCurrentIndex(mp_unitComboBox->findData(QString("dalton")));

      mp_daltonValueSpinBox->setValue(precision->getNominal());
      mp_daltonValueSpinBox->setVisible(true);

      mp_ppmValueSpinBox->setVisible(false);
      mp_resValueSpinBox->setVisible(false);
    }
  else if(precision->unit() == Enums::PrecisionUnit::ppm)
    {
      mp_precisionPpm = precision;
      mp_unitComboBox->setCurrentIndex(mp_unitComboBox->findData(QString("ppm")));

      mp_ppmValueSpinBox->setValue(precision->getNominal());
      mp_ppmValueSpinBox->setVisible(true);

      mp_daltonValueSpinBox->setVisible(false);
      mp_resValueSpinBox->setVisible(false);
    }
  else if(precision->unit() == Enums::PrecisionUnit::res)
    {
      mp_precisionRes = precision;
      mp_unitComboBox->setCurrentIndex(mp_unitComboBox->findData(QString("res")));

      mp_resValueSpinBox->setValue(precision->getNominal());
      mp_resValueSpinBox->setVisible(true);

      mp_daltonValueSpinBox->setVisible(false);
      mp_ppmValueSpinBox->setVisible(false);
    }
  else
    {
      throw ExceptionNotPossible(
        "precisionwidget.cpp @ setPrecision(PrecisionPtr precision)-- ERROR "
        "programming error.");
    }
}


} // namespace pappso
