/* Distributed under the Apache License, Version 2.0.
See accompanying NOTICE file for details.*/
#include "ScalarQuantityWidget.h"

template<typename Unit>
QScalarQuantityWidget<Unit>::QScalarQuantityWidget(const QString& name, double min, double max, double step, const Unit& unit, ScalarOptionWidget optWidget, QWidget *parent, bool seperate_label) : QScalarConvertWidget(parent), m_DefaultUnit(unit)
{
  setAutoFillBackground(true);
  m_Layout = new QHBoxLayout(this);
  m_Layout->setSpacing(6);
  m_Layout->setContentsMargins(-1, 2, -1, 2);

  QSizePolicy sizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding);
  sizePolicy.setHorizontalStretch(0);
  sizePolicy.setVerticalStretch(0);
  m_Check = nullptr;
  m_Radio = nullptr;
  switch (optWidget)
  {
    case ScalarOptionWidget::Check:
    {
      m_Check = new QCheckBox(name, this);
      sizePolicy.setHeightForWidth(m_Check->sizePolicy().hasHeightForWidth());
      m_Check->setSizePolicy(sizePolicy);
      m_Label = nullptr;
      m_Layout->addWidget(m_Check);
      connect(m_Check, SIGNAL(toggled(bool)), this, SLOT(checkProperty(bool)));
      if (seperate_label)
      {
        m_Label = new QLabel(name, this);
        m_Label->setSizePolicy(sizePolicy);
        m_Layout->addWidget(m_Label);
      }
      break;
    }
    case ScalarOptionWidget::Radio:
    {
      m_Radio = new QRadioButton(name, this);
      sizePolicy.setHeightForWidth(m_Radio->sizePolicy().hasHeightForWidth());
      m_Radio->setSizePolicy(sizePolicy);
      m_Label = nullptr;
      m_Layout->addWidget(m_Radio);
      //connect(m_Radio, SIGNAL(toggled(bool)), this, SLOT(checkProperty(bool)));
      if (seperate_label)
      {
        m_Label = new QLabel(name, this);
        m_Label->setSizePolicy(sizePolicy);
        m_Layout->addWidget(m_Label);
      }
      break;
    }
    case ScalarOptionWidget::None:
    {
      m_Label = new QLabel(name, this);
      sizePolicy.setHeightForWidth(m_Label->sizePolicy().hasHeightForWidth());
      m_Label->setSizePolicy(sizePolicy);
      m_Layout->addWidget(m_Label);
      break;
    }
  }
  m_Spacer = new QSpacerItem(40, 30, QSizePolicy::Expanding, QSizePolicy::Minimum);
  m_Layout->addItem(m_Spacer);
  m_Value = new QDoubleSpinBox(this);
  m_Value->setSingleStep(step);
  if (optWidget == ScalarOptionWidget::Check)
    m_Value->setSpecialValueText("nan");
  m_Value->setMinimum(optWidget == ScalarOptionWidget::Check ? min - step : min);
  m_Value->setMaximum(max);
  m_Value->setMinimumSize(QSize(70, 22));
  m_Value->setMaximumSize(QSize(70, 22));
  m_Value->setDecimals(2);
  m_Layout->addWidget(m_Value);

  m_Unit = new QComboBox(this);
  QSizePolicy sizePolicyU(QSizePolicy::Fixed, QSizePolicy::Maximum);
  sizePolicyU.setHorizontalStretch(0);
  sizePolicyU.setVerticalStretch(0);
  sizePolicyU.setHeightForWidth(m_Unit->sizePolicy().hasHeightForWidth());
  m_Unit->setSizePolicy(sizePolicyU);
  m_Unit->setMinimumSize(QSize(70, 0));
  m_Unit->setMaximumSize(QSize(70, 20));
  m_Unit->addItem(QString::fromStdString(unit.GetString()));
  m_Unit->setEnabled(true);
  m_Units.push_back(&unit);
  connect(m_Unit, SIGNAL(currentIndexChanged(int)), this, SLOT(convert()));
  m_Layout->addWidget(m_Unit);
  setLayout(m_Layout);
  m_Min = min;
  m_Max = max;
  m_Step = step;
  reset();
  if (seperate_label)
  {
    if (m_Check != nullptr)
    {
      m_Check->setChecked(true);
      m_Check->hide();
    }
  }
}

template<typename Unit>
void QScalarQuantityWidget<Unit>::reset()
{
  m_Convert = false;
  if (m_Check != nullptr)
    m_Check->setChecked(false);
  if (m_Radio != nullptr)
    m_Radio->setChecked(false);
  enableInput(true, false);
  m_LastUnitIndex = 0;
  m_LastValue = m_Value->minimum();
  m_Unit->setCurrentIndex(m_LastUnitIndex);
  m_Value->setValue(m_LastValue);
}

template<typename Unit>
bool QScalarQuantityWidget<Unit>::isChecked()
{
  if (m_Check != nullptr)
    return m_Check->isChecked();
  if (m_Radio != nullptr)
    return m_Radio->isChecked();
  return true;
}

template<typename Unit>
void QScalarQuantityWidget<Unit>::setDecimals(int prec)
{
  m_Value->setDecimals(prec);
}

template<typename Unit>
void QScalarQuantityWidget<Unit>::addUnit(const Unit& unit)
{
  for (auto u : m_Units)
    if (u->GetString() == unit.GetString())
      return;
  m_Units.push_back(&unit);
  m_Unit->addItem(QString::fromStdString(unit.GetString()));
}

template<typename Unit>
void QScalarQuantityWidget<Unit>::setValue(const SEScalarQuantity<Unit>& s)
{
  if (s.IsValid())
  {
    m_Value->setEnabled(true);
    if (m_Check != nullptr)
      m_Check->setChecked(true);
    // Update the unit first, then the value so we have the right bounds
    m_Unit->setCurrentText(QString::fromStdString(s.GetUnit()->GetString()));
    m_LastUnitIndex = m_Unit->currentIndex();
    updateMinMax();
    m_Value->setValue(s.GetValue(*s.GetUnit()));
    m_LastValue = s.GetValue(*s.GetUnit());
  }
  else
  {
    m_Value->setValue(m_Value->minimum());
    if (m_Check != nullptr)
      m_Check->setChecked(false);
    m_Value->setEnabled(false);
  }
}

template<typename Unit>
void QScalarQuantityWidget<Unit>::getValue(SEScalarQuantity<Unit>& s)
{
  if (m_Check != nullptr && m_Value->value() == m_Value->minimum())
  {
    s.Invalidate();
    return;//Skip it!! not a valid value as per the bounds
  }
  s.SetValue(m_Value->value(),*m_Units[m_Unit->currentIndex()]);
}

template<typename Unit>
void QScalarQuantityWidget<Unit>::enableInput(bool b)
{
  enableInput(b, b);
}
template<typename Unit>
void QScalarQuantityWidget<Unit>::enableInput(bool check, bool value)
{
  if (m_Check != nullptr)
    m_Check->setEnabled(check);
  if (m_Radio != nullptr)
    m_Radio->setChecked(check);
  m_Value->setEnabled(value);
}

template<typename Unit>
void QScalarQuantityWidget<Unit>::fullDisable()
{
  enableInput(false);
  if (m_Check != nullptr)
    m_Check->setDisabled(true);
  if (m_Radio != nullptr)
    m_Radio->setDisabled(true);
}

template<typename Unit>
void QScalarQuantityWidget<Unit>::checkProperty(bool b)
{
  m_Value->setEnabled(b);
  if (!b)
  {
    m_LastValue = m_Value->value();
    m_LastUnitIndex = m_Unit->currentIndex();
    m_Value->setValue(m_Value->minimum());
  }
  else
  {
    m_Value->setValue(m_LastValue);
    m_Unit->setCurrentIndex(m_LastUnitIndex);
  }
}



template<typename Unit>
void QScalarQuantityWidget<Unit>::enableConverter(bool b)
{
  m_Convert = b;
}

template<typename Unit>
void QScalarQuantityWidget<Unit>::convert()
{
  if (!m_Convert)
    return;
  if (m_Unit->currentIndex() < 0)
    return;
  m_LastValue = Convert(m_LastValue, *m_Units[m_LastUnitIndex], *m_Units[m_Unit->currentIndex()]);
  m_LastUnitIndex = m_Unit->currentIndex();
  updateMinMax();
  m_Value->setValue(m_LastValue);
}

template<typename Unit>
void QScalarQuantityWidget<Unit>::updateMinMax()
{
  double min = Convert(m_Min, m_DefaultUnit, *m_Units[m_Unit->currentIndex()]);
  double max = Convert(m_Max, m_DefaultUnit, *m_Units[m_Unit->currentIndex()]);
  m_Value->setMinimum(m_Check != nullptr ? min - m_Step : min);
  m_Value->setMaximum(max);
}