//
//    DopplerDialog.cpp: Doppler effect dialog
//    Copyright (C) 2020 Gonzalo José Carracedo Carballal
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU Lesser General Public License as
//    published by the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
//
//    You should have received a copy of the GNU Lesser General Public
//    License along with this program.  If not, see
//    <http://www.gnu.org/licenses/>
//
#include "DopplerDialog.h"
#include "ui_DopplerDialog.h"
#include <SuWidgetsHelpers.h>
#include <QFileDialog>
#include <QMessageBox>
#include <cmath>
#include <fstream>
#include <iomanip>

using namespace SigDigger;

DopplerDialog::DopplerDialog(QWidget *parent) :
  QDialog(parent),
  ui(new Ui::DopplerDialog)
{
  ui->setupUi(this);
  this->setWindowFlags(
        this->windowFlags() | Qt::Window | Qt::WindowMaximizeButtonHint);

  this->connectAll();
}

void
DopplerDialog::connectAll(void)
{
  connect(
        this->ui->saveButton,
        SIGNAL(clicked(void)),
        this,
        SLOT(onSave(void)));

  connect(
        this->ui->zoomResetButton,
        SIGNAL(clicked(void)),
        this,
        SLOT(onZoomReset(void)));
}

bool
DopplerDialog::exportToMatlab(QString const &path)
{
  std::ofstream of(path.toStdString().c_str(), std::ofstream::binary);
  const SUCOMPLEX *data = this->data.data();
  int length = static_cast<int>(this->data.size());

  if (!of.is_open())
    return false;

  of << "%\n";
  of << "% Velocity dispersion diagram generated by SigDigger\n";
  of << "% Units are m/s (meters per second)\n";
  of << "%\n\n";

  of << std::setprecision(std::numeric_limits<float>::digits10);

  of << "f0 = " << this->f0 << ";\n";
  of << "vDom = " << this->vDom << ";\n";
  of << "sigmaV = " << this->sigmaV << ";\n";
  of << "deltaV = " << 1 / this->fs << ";\n";
  of << "v = [ ";

  for (int i = 0; i <= length; ++i)
    of << SU_C_REAL(data[i]) << ", ";

  of << "];\n";

  return true;
}


void
DopplerDialog::setDominantVelocity(qreal vel)
{
  this->vDom = vel;

  this->ui->fDomLabel->setText(
        SuWidgetsHelpers::formatQuantityFromDelta(
          vel,
          this->sigmaV > 0 ? this->sigmaV : 5,
          "m/s"));

}
void
DopplerDialog::setSigmaV(qreal vel)
{
  this->sigmaV = vel;

  this->ui->sigmaFLabel->setText(
        SuWidgetsHelpers::formatQuantity(vel, 3, "m/s"));
}

void
DopplerDialog::setCenterFreq(qreal freq)
{
  this->f0 = freq;

  this->ui->fcLabel->setText(
        SuWidgetsHelpers::formatQuantity(freq, 6, "Hz"));
}

void
DopplerDialog::setMax(qreal max)
{
  this->max = max;

  this->ui->waveform->zoomVertical(
        static_cast<qreal>(0.),
        this->max);
}

void
DopplerDialog::setVelocityStep(qreal deltaV)
{
  this->fs = 1 / deltaV;

  this->ui->waveform->setSampleRate(this->fs);
}

void
DopplerDialog::setColorConfig(ColorConfig const &cfg)
{
  this->ui->waveform->setForegroundColor(cfg.spectrumForeground);
  this->ui->waveform->setBackgroundColor(cfg.spectrumBackground);
  this->ui->waveform->setTextColor(cfg.spectrumText);
  this->ui->waveform->setAxesColor(cfg.spectrumAxes);
}

void
DopplerDialog::zoomReset(void)
{
  this->ui->waveform->zoomVertical(
        static_cast<qreal>(0.),
        this->max);

  this->ui->waveform->zoomHorizontalReset();
  this->ui->waveform->invalidate();
}

void
DopplerDialog::showEvent(QShowEvent *)
{
  this->zoomReset();
}

void
DopplerDialog::giveSpectrum(std::vector<SUCOMPLEX> &&data)
{
  this->data = std::move(data);
  this->ui->waveform->setData(&this->data);
  this->ui->waveform->setRealComponent(true);
  this->ui->waveform->setOriginX(-static_cast<qint64>(this->data.size()) / 2.);
  this->ui->waveform->setSampleRate(this->fs);
}

DopplerDialog::~DopplerDialog()
{
  delete ui;
}

////////////////////////////////// Slots ///////////////////////////////////////
void
DopplerDialog::onSave(void)
{
  bool done = false;

  do {
    QFileDialog dialog(this);
    QStringList filters;

    dialog.setFileMode(QFileDialog::FileMode::AnyFile);
    dialog.setAcceptMode(QFileDialog::AcceptSave);
    dialog.setWindowTitle(QString("Save capture"));

    filters << "MATLAB/Octave file (*.m)";

    dialog.setNameFilters(filters);

    if (dialog.exec()) {
      QString path = dialog.selectedFiles().first();
      QString filter = dialog.selectedNameFilter();
      bool result;

      path = SuWidgetsHelpers::ensureExtension(path, "m");
      result = this->exportToMatlab(path);

      if (!result) {
        QMessageBox::warning(
              this,
              "Cannot open file",
              "Cannote save file in the specified location. Please choose "
              "a different location and try again.",
              QMessageBox::Ok);
      } else {
        done = true;
      }
    } else {
      done = true;
    }
  } while (!done);
}

void
DopplerDialog::onZoomReset(void)
{
  this->zoomReset();
}
