/* Distributed under the Apache License, Version 2.0.
   See accompanying NOTICE file for details.*/

#include "LabeledDialWidget.h"
#include "ui_LabeledDialWidget.h"


#include "cdm/CommonDefs.h"
#include "cdm/properties/SEScalar.h"

struct LabeledDialWidget::Private : public Ui::LabeledDialWidget
{
  double value = 0.0;
  double dialScale = 1.0;
  SEScalar* scalar = nullptr;
};

LabeledDialWidget::LabeledDialWidget(QWidget *parent) :
  QWidget(parent),
  d(new Private())
{
  d->setupUi(this);

  connect(d->dial, &QDial::valueChanged, this, &LabeledDialWidget::spinBoxUpdated);
  connect(d->input, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &LabeledDialWidget::setValue);
}

LabeledDialWidget::~LabeledDialWidget()
{
  delete d;
}

void LabeledDialWidget::setTitle(QString title)
{
  d->title->setText(title);
}

void LabeledDialWidget::setUnit(QString unit)
{
  d->unit->setText(unit);
}

void LabeledDialWidget::setScalar(SEScalar* scalar)
{
    d->scalar = scalar;
    if (d->scalar != nullptr) {
      // Invalidate the number 
      d->value = std::numeric_limits<double>::max();
      setValue(scalar->GetValue());
    }
}

void LabeledDialWidget::setup(QString title, QString unit, double min, double max, double scale /*= 1.0*/, double step /*= 1.0*/, SEScalar* scalar /*= nullptr*/)
{
  d->scalar = nullptr;
  setTitle(title);
  setUnit(unit);
  d->dialScale = scale;
  d->input->setSingleStep(step);
  setMinimumValue(min);
  setMaximumValue(max);
  setScalar(scalar);
};

void LabeledDialWidget::setMinimumValue(double val)
{
  d->minlabel->setText(QString::number(val));
  if (d->value < val)
  {
    setValue(val);
  }
  d->dial->setMinimum(static_cast<int>(val * d->dialScale));
  d->input->setMinimum(val);
}

void LabeledDialWidget::setMaximumValue(double val)
{
  d->maxlabel->setText(QString::number(val));
  if (d->value > val)
  {
    setValue(val);
  }
  d->dial->setMaximum(static_cast<int>(val * d->dialScale));
  d->input->setMaximum(val);
}

void LabeledDialWidget::setValue(double val)
{
  if (val != d->value)
  {
    // Prevent loops by blocking rather than with value comparison due
    // to scaling the dial value
    QSignalBlocker(d->input);
    QSignalBlocker(d->dial);

    d->input->setValue(val);
    d->dial->setValue(static_cast<int>(val * d->dialScale));
    if (d->scalar != nullptr)
    {
        d->scalar->SetValue(val);
    }
    d->value = val;
    emit valueChanged(val);
  }
}

double LabeledDialWidget::getValue() const
{
  return d->value;
}

void LabeledDialWidget::spinBoxUpdated(int val)
{
  setValue(val / d->dialScale);
}

