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

#include <QLineEdit>
#include <QFileDialog>
#include <QMessageBox>

#include "pulse/CommonDataModel.h"
#include "pulse/PhysiologyEngine.h"
#include "pulse/utils/FileUtils.h"
#include "pulse/engine/SEPatientConfiguration.h"
#include "pulse/patient/SEPatient.h"
#include "pulse/properties/SEScalar0To1.h"
#include "pulse/properties/SEScalarArea.h"
#include "pulse/properties/SEScalarFrequency.h"
#include "pulse/properties/SEScalarLength.h"
#include "pulse/properties/SEScalarMass.h"
#include "pulse/properties/SEScalarMassPerVolume.h"
#include "pulse/properties/SEScalarPower.h"
#include "pulse/properties/SEScalarPressure.h"
#include "pulse/properties/SEScalarTime.h"
#include "pulse/properties/SEScalarVolume.h"

class QPatientEditorWidget::Controls : public Ui::PatientEditorWidget
{
public:
  Controls(QPulse& qp) : Pulse(qp), EnginePatient(qp.GetEngine().GetLogger()){}
  QPulse&                Pulse;

  std::string                               InitialStateLocation;

  QWidget*                                  Name;
  QLabel*                                   NameLabel;
  QSpacerItem*                              NameSpacer;
  QLineEdit*                                NameValue;
  QHBoxLayout*                              NameLayout;

  QWidget*                                  Sex;
  QLabel*                                   SexLabel;
  QSpacerItem*                              SexSpacer;
  QComboBox*                                SexValue;
  QHBoxLayout*                              SexLayout;

  QScalarQuantityWidget<TimeUnit>*          Age;
  QScalarQuantityWidget<MassUnit>*          Weight;
  QScalarQuantityWidget<LengthUnit>*        Height;
  QScalarQuantityWidget<MassPerVolumeUnit>* BodyDensity;
  QScalarWidget*                            BodyFatFraction;
  QScalarQuantityWidget<MassUnit>*          LeanBodyMass;
  QScalarQuantityWidget<AreaUnit>*          SkinSurfaceArea;
  QScalarQuantityWidget<PowerUnit>*         BasalMetabolicRate;

  QScalarQuantityWidget<AreaUnit>*          AlveoliSurfaceArea;
  QScalarWidget*                            RightLungRatio;
  QScalarQuantityWidget<FrequencyUnit>*     RespirationRateBaseline;
  QScalarQuantityWidget<VolumeUnit>*        FunctionalResidualCapacity;
  QScalarQuantityWidget<VolumeUnit>*        TotalLungCapacity;
  QScalarQuantityWidget<VolumeUnit>*        TidalVolumeBaseline;
  QScalarQuantityWidget<VolumeUnit>*        ExpiratoryReserveVolume;
  QScalarQuantityWidget<VolumeUnit>*        InspiratoryCapacity;
  QScalarQuantityWidget<VolumeUnit>*        InspiratoryReserveVolume;
  QScalarQuantityWidget<VolumeUnit>*        VitalCapacity;
  QScalarQuantityWidget<VolumeUnit>*        ResidualVolume;

  QScalarQuantityWidget<FrequencyUnit>*     HeartRateBaseline;
  QScalarQuantityWidget<VolumeUnit>*        BloodVolumeBaseline;
  QScalarQuantityWidget<PressureUnit>*      SystolicArterialPressureBaseline;
  QScalarQuantityWidget<PressureUnit>*      DiastolicArterialPressureBaseline;
  QScalarQuantityWidget<PressureUnit>*      MeanArterialPressureBaseline;

  QScalarQuantityWidget<FrequencyUnit>*     HeartRateMaximum;
  QScalarQuantityWidget<FrequencyUnit>*     HeartRateMinimum;

  SEPatient                                 EnginePatient;
};

QPatientEditorWidget::QPatientEditorWidget(QPulse& qp, QWidget *parent, Qt::WindowFlags flags) : QDockWidget(parent,flags)
{
  m_Controls = new Controls(qp);
  m_Controls->setupUi(this);

  m_Controls->NameLayout = new QHBoxLayout();
  m_Controls->NameLayout->setSpacing(6);
  m_Controls->NameLayout->setContentsMargins(-1, 3, -1, 3);
  QSizePolicy NsizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  NsizePolicy.setHorizontalStretch(0);
  NsizePolicy.setVerticalStretch(0);
  m_Controls->NameLabel = new QLabel("Name", this);
  NsizePolicy.setHeightForWidth(m_Controls->NameLabel->sizePolicy().hasHeightForWidth());
  m_Controls->NameLabel->setSizePolicy(NsizePolicy);
  m_Controls->NameLayout->addWidget(m_Controls->NameLabel);
  m_Controls->NameSpacer = new QSpacerItem(40, 30, QSizePolicy::Expanding, QSizePolicy::Maximum);
  m_Controls->NameLayout->addItem(m_Controls->NameSpacer);
  m_Controls->NameValue = new QLineEdit(this);
  m_Controls->NameValue->setMinimumSize(QSize(148, 0));
  m_Controls->NameValue->setMaximumSize(QSize(148, 16777215));
  m_Controls->NameLayout->addWidget(m_Controls->NameValue);
  m_Controls->Name = new QWidget(this);
  m_Controls->Name->setLayout(m_Controls->NameLayout);
  m_Controls->Properties->layout()->addWidget(m_Controls->Name);

  m_Controls->SexLayout = new QHBoxLayout();
  m_Controls->SexLayout->setSpacing(6);
  m_Controls->SexLayout->setContentsMargins(-1, 3, -1, 3);
  QSizePolicy SsizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  SsizePolicy.setHorizontalStretch(0);
  SsizePolicy.setVerticalStretch(0);
  m_Controls->SexLabel = new QLabel("Sex", this);
  SsizePolicy.setHeightForWidth(m_Controls->SexLabel->sizePolicy().hasHeightForWidth());
  m_Controls->SexLabel->setSizePolicy(SsizePolicy);
  m_Controls->SexLayout->addWidget(m_Controls->SexLabel);
  m_Controls->SexSpacer = new QSpacerItem(40, 30, QSizePolicy::Expanding, QSizePolicy::Maximum);
  m_Controls->SexLayout->addItem(m_Controls->SexSpacer);
  m_Controls->SexValue = new QComboBox(this); 
  m_Controls->SexValue->addItem("Male");
  m_Controls->SexValue->addItem("Female");
  m_Controls->SexValue->setMinimumSize(QSize(70, 0));
  m_Controls->SexValue->setMaximumSize(QSize(70, 16777215));
  m_Controls->SexLayout->addWidget(m_Controls->SexValue);
  m_Controls->Sex = new QWidget(this);
  m_Controls->Sex->setLayout(m_Controls->SexLayout);
  m_Controls->Properties->layout()->addWidget(m_Controls->Sex);

  m_Controls->Age = new QScalarQuantityWidget<TimeUnit>("Age", 18, 65, 1, TimeUnit::yr, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->Age);
  m_Controls->Weight = new QScalarQuantityWidget<MassUnit>("Weight", 90, 300, 1, MassUnit::lb, ScalarOptionWidget::Check, this);
  m_Controls->Weight->AddUnit(MassUnit::kg);
  m_Controls->Properties->layout()->addWidget(m_Controls->Weight);
  m_Controls->Height = new QScalarQuantityWidget<LengthUnit>("Height", 48, 96, 0.1, LengthUnit::in, ScalarOptionWidget::Check, this);
  m_Controls->Height->AddUnit(LengthUnit::ft);
  m_Controls->Height->AddUnit(LengthUnit::m);
  m_Controls->Properties->layout()->addWidget(m_Controls->Height);
  m_Controls->BodyDensity = new QScalarQuantityWidget<MassPerVolumeUnit>("Body Density", 0, 1000, 1, MassPerVolumeUnit::kg_Per_L, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->BodyDensity);
  m_Controls->BodyFatFraction = new QScalarWidget("Body Fat Fraction", 0, 1, 0.1, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->BodyFatFraction);
  m_Controls->LeanBodyMass = new QScalarQuantityWidget<MassUnit>("Lean Body Mass", 0, 1000, 1, MassUnit::lb, ScalarOptionWidget::Check, this);
  m_Controls->LeanBodyMass->AddUnit(MassUnit::kg);
  m_Controls->Properties->layout()->addWidget(m_Controls->LeanBodyMass);
  m_Controls->SkinSurfaceArea = new QScalarQuantityWidget<AreaUnit>("Skin Surface Area", 0, 4, 0.1, AreaUnit::m2, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->SkinSurfaceArea);
  m_Controls->BasalMetabolicRate = new QScalarQuantityWidget<PowerUnit>("Basal Metabolic Rate", 0, 3000, 1, PowerUnit::kcal_Per_day, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->BasalMetabolicRate);

  m_Controls->AlveoliSurfaceArea = new QScalarQuantityWidget<AreaUnit>("Alveoli Surface Area", 0, 100, 0.1, AreaUnit::m2, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->AlveoliSurfaceArea);
  m_Controls->RightLungRatio = new QScalarWidget("Right Lung Ratio", 0, 1, 0.1, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->RightLungRatio);
  m_Controls->RespirationRateBaseline = new QScalarQuantityWidget<FrequencyUnit>("Respiration Rate Baseline", 0, 30, 1, FrequencyUnit::Per_min, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->RespirationRateBaseline);
  m_Controls->FunctionalResidualCapacity = new QScalarQuantityWidget<VolumeUnit>("Functional Residual Capacity", 0, 4, 0.1, VolumeUnit::L, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->FunctionalResidualCapacity);
  m_Controls->TotalLungCapacity = new QScalarQuantityWidget<VolumeUnit>("Total Lung Capacity", 0, 10, 0.1, VolumeUnit::L, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->TotalLungCapacity);
  m_Controls->TidalVolumeBaseline = new QScalarQuantityWidget<VolumeUnit>("Tidal Volume Baseline", 0, 1, 0.1, VolumeUnit::L, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->TidalVolumeBaseline);
  m_Controls->ExpiratoryReserveVolume = new QScalarQuantityWidget<VolumeUnit>("Expiratory Reserve Volume", 0, 2, 0.1, VolumeUnit::L, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->ExpiratoryReserveVolume);
  m_Controls->InspiratoryCapacity = new QScalarQuantityWidget<VolumeUnit>("Inspiratory Capacity", 0, 8, 0.1, VolumeUnit::L, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->InspiratoryCapacity);
  m_Controls->InspiratoryReserveVolume = new QScalarQuantityWidget<VolumeUnit>("Inspiratory Reserve Volume", 0, 8, 0.1, VolumeUnit::L, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->InspiratoryReserveVolume);
  m_Controls->VitalCapacity = new QScalarQuantityWidget<VolumeUnit>("Vital Capacity", 0, 10, 0.1, VolumeUnit::L, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->VitalCapacity);
  m_Controls->ResidualVolume = new QScalarQuantityWidget<VolumeUnit>("Residual Volume", 0, 3, 0.1, VolumeUnit::L, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->ResidualVolume);

  m_Controls->HeartRateBaseline = new QScalarQuantityWidget<FrequencyUnit>("Heart Rate Baseline", 0, 250, 1, FrequencyUnit::Per_min, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->HeartRateBaseline);
  m_Controls->BloodVolumeBaseline = new QScalarQuantityWidget<VolumeUnit>("Blood Volume Baseline", 0, 8000, 1, VolumeUnit::mL, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->BloodVolumeBaseline);
  m_Controls->SystolicArterialPressureBaseline = new QScalarQuantityWidget<PressureUnit>("Systolic Pressure Baseline", 0, 200, 1, PressureUnit::mmHg, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->SystolicArterialPressureBaseline);
  m_Controls->DiastolicArterialPressureBaseline = new QScalarQuantityWidget<PressureUnit>("Diastolic Pressure Baseline", 0, 120, 1, PressureUnit::mmHg, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->DiastolicArterialPressureBaseline);
  m_Controls->MeanArterialPressureBaseline = new QScalarQuantityWidget<PressureUnit>("Mean Arterial Pressure Baseline", 0, 160, 1, PressureUnit::mmHg, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->MeanArterialPressureBaseline);

  m_Controls->HeartRateMaximum = new QScalarQuantityWidget<FrequencyUnit>("Heart Rate Maximum", 0, 250, 1, FrequencyUnit::Per_min, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->HeartRateMaximum);
  m_Controls->HeartRateMinimum = new QScalarQuantityWidget<FrequencyUnit>("Heart Rate Minimum", 0, 100, 1, FrequencyUnit::Per_min, ScalarOptionWidget::Check, this);
  m_Controls->Properties->layout()->addWidget(m_Controls->HeartRateMinimum);

  QSpacerItem *spacer = new QSpacerItem(40, 1000, QSizePolicy::Expanding, QSizePolicy::Expanding);
  m_Controls->Properties->layout()->addItem(spacer);

  connect(m_Controls->ShowAdvancedProperties, SIGNAL(clicked()), this, SLOT(ShowAdvancedProperties()));
  connect(m_Controls->SaveState, SIGNAL(clicked()), this, SLOT(SetInitialStateFilename()));
  connect(m_Controls->LoadState, SIGNAL(clicked()), parentWidget(), SLOT(LoadState()));
  connect(m_Controls->ClearPatient, SIGNAL(clicked()), parentWidget(), SLOT(ClearPatient()));
  connect(m_Controls->LoadPatientFile,  SIGNAL(clicked()), this, SLOT(LoadPatientFile()));
  connect(m_Controls->SavePatientFile,  SIGNAL(clicked()), this, SLOT(SavePatientFile()));
  Clear();
  ShowAdvancedProperties();

}

QPatientEditorWidget::~QPatientEditorWidget()
{
  delete m_Controls;
}


void QPatientEditorWidget::UpdateUI()
{

}

void QPatientEditorWidget::Clear()
{
  m_Controls->InitialStateLocation = "";
  m_Controls->StateFilename->setText("");
  ResetControls();
  EnableSetupControls(true);
  m_Controls->Pulse.SetEngineStateFilename("");
  m_Controls->Pulse.SetPatientFilename("");
}


void QPatientEditorWidget::ClearPatient()
{
  EnableSetupControls(true);
  EnableInput(true);
  Clear();
}

bool QPatientEditorWidget::ValidPatient()
{
  return !m_Controls->NameValue->text().isEmpty();
}

void QPatientEditorWidget::ResetControls()
{

  m_Controls->NameValue->setText("");
  m_Controls->NameValue->setEnabled(true);


  m_Controls->Age->Reset();
  m_Controls->Weight->Reset();
  m_Controls->Height->Reset();
  m_Controls->BodyDensity->Reset();
  m_Controls->BodyFatFraction->Reset();
  m_Controls->LeanBodyMass->Reset();
  m_Controls->SkinSurfaceArea->Reset();
  m_Controls->BasalMetabolicRate->Reset();

  m_Controls->AlveoliSurfaceArea->Reset();
  m_Controls->RightLungRatio->Reset();
  m_Controls->RespirationRateBaseline->Reset();
  m_Controls->FunctionalResidualCapacity->Reset();
  m_Controls->TotalLungCapacity->Reset();
  m_Controls->TidalVolumeBaseline->Reset();
  m_Controls->ExpiratoryReserveVolume->Reset();
  m_Controls->InspiratoryCapacity->Reset();
  m_Controls->InspiratoryReserveVolume->Reset();
  m_Controls->VitalCapacity->Reset();
  m_Controls->ResidualVolume->Reset();

  m_Controls->HeartRateBaseline->Reset();
  m_Controls->BloodVolumeBaseline->Reset();
  m_Controls->SystolicArterialPressureBaseline->Reset();
  m_Controls->DiastolicArterialPressureBaseline->Reset();
  m_Controls->MeanArterialPressureBaseline->Reset();

  m_Controls->HeartRateMaximum->Reset();
  m_Controls->HeartRateMinimum->Reset();
}

void QPatientEditorWidget::ShowAdvancedProperties()
{
  if (m_Controls->ShowAdvancedProperties->isChecked())
  {
    m_Controls->BodyDensity->show();
    m_Controls->LeanBodyMass->show();
    m_Controls->SkinSurfaceArea->show();
    m_Controls->BasalMetabolicRate->show();

    m_Controls->AlveoliSurfaceArea->show();
    m_Controls->RightLungRatio->show();

    m_Controls->BloodVolumeBaseline->show();
    m_Controls->MeanArterialPressureBaseline->show();

    m_Controls->FunctionalResidualCapacity->show();
    m_Controls->TotalLungCapacity->show();
    m_Controls->TidalVolumeBaseline->show();
    m_Controls->ExpiratoryReserveVolume->show();
    m_Controls->InspiratoryCapacity->show();
    m_Controls->InspiratoryReserveVolume->show();
    m_Controls->VitalCapacity->show();
    m_Controls->ResidualVolume->show();

    m_Controls->HeartRateMaximum->show();
    m_Controls->HeartRateMinimum->show();
  }
  else
  {
    m_Controls->BodyDensity->hide();
    m_Controls->LeanBodyMass->hide();
    m_Controls->SkinSurfaceArea->hide();
    m_Controls->BasalMetabolicRate->hide();

    m_Controls->AlveoliSurfaceArea->hide();
    m_Controls->RightLungRatio->hide();

    m_Controls->BloodVolumeBaseline->hide();
    m_Controls->MeanArterialPressureBaseline->hide();

    m_Controls->FunctionalResidualCapacity->hide();
    m_Controls->TotalLungCapacity->hide();
    m_Controls->TidalVolumeBaseline->hide();
    m_Controls->ExpiratoryReserveVolume->hide();
    m_Controls->InspiratoryCapacity->hide();
    m_Controls->InspiratoryReserveVolume->hide();
    m_Controls->VitalCapacity->hide();
    m_Controls->ResidualVolume->hide();

    m_Controls->HeartRateMaximum->hide();
    m_Controls->HeartRateMinimum->hide();
  }
}

void QPatientEditorWidget::SetStateFilename(QString& fileName)
{
  QStringList pieces = fileName.split("/");
  m_Controls->StateFilename->setText("Loaded State : " + pieces.value(pieces.length() - 1));
  m_Controls->SaveState->hide();
  m_Controls->SaveState->setEnabled(false);
}

void QPatientEditorWidget::SetInitialStateFilename()
{
  if (m_Controls->SaveState->isChecked())
  {
    QString fileName = QFileDialog::getSaveFileName(this, "Save state file", "./states", "JSON (*.json);;Protobuf Binary (*.pbb)");
    if (fileName.isEmpty())
    {
      m_Controls->InitialStateLocation = "";
      m_Controls->SaveState->setChecked(false);
    }
    else
    {
      m_Controls->InitialStateLocation = fileName.toStdString();
      m_Controls->Pulse.GetLogBox().append("Will save stable patient state as : " + fileName);
    }
  }
  else
  {
    m_Controls->InitialStateLocation = "";
    m_Controls->Pulse.GetLogBox().append("No longer saving stable state");
  }
  
}

void QPatientEditorWidget::EnableInput(bool b)
{
  EnableConverter(!b);

  m_Controls->NameLabel->setEnabled(b);
  m_Controls->NameValue->setEnabled(b);
  m_Controls->SexLabel->setEnabled(b);
  m_Controls->SexValue->setEnabled(b);

  m_Controls->Age->EnableInput(b);
  m_Controls->Weight->EnableInput(b);
  m_Controls->Height->EnableInput(b);
  m_Controls->BodyDensity->EnableInput(b);
  m_Controls->BodyFatFraction->EnableInput(b);
  m_Controls->LeanBodyMass->EnableInput(b);
  m_Controls->SkinSurfaceArea->EnableInput(b);
  m_Controls->BasalMetabolicRate->EnableInput(b);

  m_Controls->AlveoliSurfaceArea->EnableInput(b);
  m_Controls->RightLungRatio->EnableInput(b);
  m_Controls->RespirationRateBaseline->EnableInput(b);
  m_Controls->FunctionalResidualCapacity->EnableInput(b);
  m_Controls->TotalLungCapacity->EnableInput(b);
  m_Controls->TidalVolumeBaseline->EnableInput(b);
  m_Controls->ExpiratoryReserveVolume->EnableInput(b);
  m_Controls->InspiratoryCapacity->EnableInput(b);
  m_Controls->InspiratoryReserveVolume->EnableInput(b);
  m_Controls->VitalCapacity->EnableInput(b);
  m_Controls->ResidualVolume->EnableInput(b);

  m_Controls->HeartRateBaseline->EnableInput(b);
  m_Controls->BloodVolumeBaseline->EnableInput(b);
  m_Controls->SystolicArterialPressureBaseline->EnableInput(b);
  m_Controls->DiastolicArterialPressureBaseline->EnableInput(b);
  m_Controls->MeanArterialPressureBaseline->EnableInput(b);

  m_Controls->HeartRateMaximum->EnableInput(b);
  m_Controls->HeartRateMinimum->EnableInput(b);
}

void QPatientEditorWidget::EnableSetupControls(bool b)
{
  m_Controls->LoadState->setEnabled(b);
  m_Controls->ClearPatient->setEnabled(b);
  m_Controls->LoadPatientFile->setEnabled(b);
  m_Controls->SavePatientFile->setEnabled(b);
  m_Controls->SaveState->setEnabled(b);
  if (b)
  {
    m_Controls->LoadState->show();
    m_Controls->ClearPatient->show();
    m_Controls->LoadPatientFile->show();
    m_Controls->SavePatientFile->show();
    m_Controls->SaveState->show();
  }
  else
  {
    m_Controls->LoadState->hide();
    m_Controls->ClearPatient->hide();
    m_Controls->LoadPatientFile->hide();
    m_Controls->SavePatientFile->hide();
    m_Controls->SaveState->hide();
  }
}

void QPatientEditorWidget::EnableConverter(bool b)
{
  m_Controls->Age->EnableConverter(b);
  m_Controls->Weight->EnableConverter(b);
  m_Controls->Height->EnableConverter(b);
  m_Controls->BodyDensity->EnableConverter(b);
  m_Controls->LeanBodyMass->EnableConverter(b);
  m_Controls->SkinSurfaceArea->EnableConverter(b);
  m_Controls->BasalMetabolicRate->EnableConverter(b);

  m_Controls->AlveoliSurfaceArea->EnableConverter(b);
  m_Controls->RespirationRateBaseline->EnableConverter(b);
  m_Controls->FunctionalResidualCapacity->EnableConverter(b);
  m_Controls->TotalLungCapacity->EnableConverter(b);
  m_Controls->TidalVolumeBaseline->EnableConverter(b);
  m_Controls->ExpiratoryReserveVolume->EnableConverter(b);
  m_Controls->InspiratoryCapacity->EnableConverter(b);
  m_Controls->InspiratoryReserveVolume->EnableConverter(b);
  m_Controls->VitalCapacity->EnableConverter(b);
  m_Controls->ResidualVolume->EnableConverter(b);

  m_Controls->HeartRateBaseline->EnableConverter(b);
  m_Controls->BloodVolumeBaseline->EnableConverter(b);
  m_Controls->SystolicArterialPressureBaseline->EnableConverter(b);
  m_Controls->DiastolicArterialPressureBaseline->EnableConverter(b);
  m_Controls->MeanArterialPressureBaseline->EnableConverter(b);

  m_Controls->HeartRateMaximum->EnableConverter(b);
  m_Controls->HeartRateMinimum->EnableConverter(b);
}

void QPatientEditorWidget::LoadPatientFile()
{
  QString filename = QFileDialog::getOpenFileName(this,
    "Open Patient", "./patients", "JSON (*.json);;Protobuf Binary (*.pbb)");
  if (filename.isEmpty())
    return;

  // Let's try to make the separate file relative to the working directory
  std::string cwd = GetCurrentWorkingDirectory();
  std::replace(cwd.begin(), cwd.end(), '\\', '/');
  QStringList pieces = filename.split(QString::fromStdString(cwd));
  if (pieces.size() > 1)
    filename = "." + pieces[1];
  std::string s = filename.toStdString();

  if (!m_Controls->Pulse.GetPatientConfiguration().GetPatient().SerializeFromFile(s))
  {
    QMessageBox msgBox(this);
    msgBox.setWindowTitle("Error!");
    QString err = "Unable to load patient file : " + filename;
    msgBox.setText(err);
    msgBox.exec();
    return;
  }
  m_Controls->Pulse.SetPatientFilename(s);
  PatientToControls(m_Controls->Pulse.GetPatientConfiguration().GetPatient());
}


void QPatientEditorWidget::SavePatientFile()
{
  QString filename = QFileDialog::getSaveFileName(this, "Save Patient", "./patients", "JSON (*.json);;Protobuf Binary (*.pbb)");
  if (filename.isEmpty())
    return;

  // Let's try to make the separate file relative to the working directory
  std::string cwd = GetCurrentWorkingDirectory();
  std::replace(cwd.begin(), cwd.end(), '\\', '/');
  QStringList pieces = filename.split(QString::fromStdString(cwd));
  if (pieces.size() > 1)
    filename = "." + pieces[1];

  if (m_Controls->NameValue->text().isEmpty())
  {
    QMessageBox msgBox(this);
    msgBox.setWindowTitle("Error!");
    msgBox.setText("Patient must have a name");
    msgBox.exec();
    return;
  }
  std::string s = filename.toStdString();
  SEPatient patient(m_Controls->EnginePatient.GetLogger());
  ControlsToPatient(patient);
  patient.SerializeToFile(s);
  m_Controls->Pulse.SetPatientFilename(s);
}

void QPatientEditorWidget::PatientToControls(SEPatient const& p)
{
  ResetControls();

  // Removing const to easily get SEScalar objects
  SEPatient& patient = const_cast<SEPatient&>(p);

  if (patient.HasName())
    m_Controls->NameValue->setText(QString::fromStdString(patient.GetName()));
   m_Controls->SexValue->setCurrentIndex(patient.GetSex() == ePatient_Sex::Male ? 0 : 1);
   if (patient.HasAge())
   {
     m_Controls->Age->EnableInput(true);
     m_Controls->Age->SetValue(patient.GetAge());
   }
  if (patient.HasWeight())
  {
    m_Controls->Weight->EnableInput(true);
    m_Controls->Weight->SetValue(patient.GetWeight());
  }
  if (patient.HasHeight())
  {
    m_Controls->Height->EnableInput(true);
    m_Controls->Height->SetValue(patient.GetHeight());
  }
  if (patient.HasBodyDensity())
  {
    m_Controls->BodyDensity->EnableInput(true);
    m_Controls->BodyDensity->SetValue(patient.GetBodyDensity());
  }
  if (patient.HasBodyFatFraction())
  {
    m_Controls->BodyFatFraction->EnableInput(true);
    m_Controls->BodyFatFraction->SetValue(patient.GetBodyFatFraction());
  }
  if (patient.HasLeanBodyMass())
  {
    m_Controls->LeanBodyMass->EnableInput(true);
    m_Controls->LeanBodyMass->SetValue(patient.GetLeanBodyMass());
  }
  if (patient.HasSkinSurfaceArea())
  {
    m_Controls->SkinSurfaceArea->EnableInput(true);
    m_Controls->SkinSurfaceArea->SetValue(patient.GetSkinSurfaceArea());
  }
  if (patient.HasBasalMetabolicRate())
  {
    m_Controls->BasalMetabolicRate->EnableInput(true);
    m_Controls->BasalMetabolicRate->SetValue(patient.GetBasalMetabolicRate());
  }

  if (patient.HasAlveoliSurfaceArea())
  {
    m_Controls->AlveoliSurfaceArea->EnableInput(true);
    m_Controls->AlveoliSurfaceArea->SetValue(patient.GetAlveoliSurfaceArea());
  }
  if (patient.HasRightLungRatio())
  {
    m_Controls->RightLungRatio->EnableInput(true);
    m_Controls->RightLungRatio->SetValue(patient.GetRightLungRatio());
  }
  if (patient.HasRespirationRateBaseline())
  {
    m_Controls->RespirationRateBaseline->EnableInput(true);
    m_Controls->RespirationRateBaseline->SetValue(patient.GetRespirationRateBaseline());
  }
  if (patient.HasFunctionalResidualCapacity())
  {
    m_Controls->FunctionalResidualCapacity->EnableInput(true);
    m_Controls->FunctionalResidualCapacity->SetValue(patient.GetFunctionalResidualCapacity());
  }
  if (patient.HasTotalLungCapacity())
  {
    m_Controls->TotalLungCapacity->EnableInput(true);
    m_Controls->TotalLungCapacity->SetValue(patient.GetTotalLungCapacity());
  }
  if (patient.HasTidalVolumeBaseline())
  {
    m_Controls->TidalVolumeBaseline->EnableInput(true);
    m_Controls->TidalVolumeBaseline->SetValue(patient.GetTidalVolumeBaseline());
  }
  if (patient.HasExpiratoryReserveVolume())
  {
    m_Controls->ExpiratoryReserveVolume->EnableInput(true);
    m_Controls->ExpiratoryReserveVolume->SetValue(patient.GetExpiratoryReserveVolume());
  }
  if (patient.HasInspiratoryCapacity())
  {
    m_Controls->InspiratoryCapacity->EnableInput(true);
    m_Controls->InspiratoryCapacity->SetValue(patient.GetInspiratoryCapacity());
  }
  if (patient.HasInspiratoryReserveVolume())
  {
    m_Controls->InspiratoryReserveVolume->EnableInput(true);
    m_Controls->InspiratoryReserveVolume->SetValue(patient.GetInspiratoryReserveVolume());
  }
  if (patient.HasVitalCapacity())
  {
    m_Controls->VitalCapacity->EnableInput(true);
    m_Controls->VitalCapacity->SetValue(patient.GetVitalCapacity());
  }
  if (patient.HasResidualVolume())
  {
    m_Controls->ResidualVolume->EnableInput(true);
    m_Controls->ResidualVolume->SetValue(patient.GetResidualVolume());
  }

  if (patient.HasBloodVolumeBaseline())
  {
    m_Controls->BloodVolumeBaseline->EnableInput(true);
    m_Controls->BloodVolumeBaseline->SetValue(patient.GetBloodVolumeBaseline());
  }
  if (patient.HasDiastolicArterialPressureBaseline())
  {
    m_Controls->DiastolicArterialPressureBaseline->EnableInput(true);
    m_Controls->DiastolicArterialPressureBaseline->SetValue(patient.GetDiastolicArterialPressureBaseline());
  }
  if (patient.HasSystolicArterialPressureBaseline())
  {
    m_Controls->SystolicArterialPressureBaseline->EnableInput(true);
    m_Controls->SystolicArterialPressureBaseline->SetValue(patient.GetSystolicArterialPressureBaseline());
  }
  if (patient.HasHeartRateBaseline())
  {
    m_Controls->HeartRateBaseline->EnableInput(true);
    m_Controls->HeartRateBaseline->SetValue(patient.GetHeartRateBaseline());
  }
  if (patient.HasMeanArterialPressureBaseline())
  {
    m_Controls->MeanArterialPressureBaseline->EnableInput(true);
    m_Controls->MeanArterialPressureBaseline->SetValue(patient.GetMeanArterialPressureBaseline());
  }

  if (patient.HasHeartRateMaximum())
  {
    m_Controls->HeartRateMaximum->EnableInput(true);
    m_Controls->HeartRateMaximum->SetValue(patient.GetHeartRateMaximum());
  }
  if (patient.HasHeartRateMinimum())
  {
    m_Controls->HeartRateMinimum->EnableInput(true);
    m_Controls->HeartRateMinimum->SetValue(patient.GetHeartRateMinimum());
  }
}

void QPatientEditorWidget::ControlsToPatient(SEPatient& patient)
{
  patient.Clear();
  patient.SetName(m_Controls->NameValue->text().toStdString());
  patient.SetSex(m_Controls->SexValue->currentIndex() == 0 ? ePatient_Sex::Male : ePatient_Sex::Female);
  if (m_Controls->Age->IsChecked())
    m_Controls->Age->GetValue(patient.GetAge());
  if (m_Controls->Weight->IsChecked())
    m_Controls->Weight->GetValue(patient.GetWeight());
  if (m_Controls->Height->IsChecked())
    m_Controls->Height->GetValue(patient.GetHeight());
  if (m_Controls->BodyDensity->IsChecked())
    m_Controls->BodyDensity->GetValue(patient.GetBodyDensity());
  if (m_Controls->BodyFatFraction->IsChecked())
    m_Controls->BodyFatFraction->GetValue(patient.GetBodyFatFraction());
  if (m_Controls->LeanBodyMass->IsChecked())
    m_Controls->LeanBodyMass->GetValue(patient.GetLeanBodyMass());
  if (m_Controls->SkinSurfaceArea->IsChecked())
    m_Controls->SkinSurfaceArea->GetValue(patient.GetSkinSurfaceArea());
  if (m_Controls->BasalMetabolicRate->IsChecked())
    m_Controls->BasalMetabolicRate->GetValue(patient.GetBasalMetabolicRate());

  if (m_Controls->AlveoliSurfaceArea->IsChecked())
    m_Controls->AlveoliSurfaceArea->GetValue(patient.GetAlveoliSurfaceArea());
  if (m_Controls->RightLungRatio->IsChecked())
    m_Controls->RightLungRatio->GetValue(patient.GetRightLungRatio());
  if (m_Controls->RespirationRateBaseline->IsChecked())
    m_Controls->RespirationRateBaseline->GetValue(patient.GetRespirationRateBaseline());
  if (m_Controls->FunctionalResidualCapacity->IsChecked())
    m_Controls->FunctionalResidualCapacity->GetValue(patient.GetFunctionalResidualCapacity());
  if (m_Controls->TotalLungCapacity->IsChecked())
    m_Controls->TotalLungCapacity->GetValue(patient.GetTotalLungCapacity());
  if (m_Controls->TidalVolumeBaseline->IsChecked())
    m_Controls->TidalVolumeBaseline->GetValue(patient.GetTidalVolumeBaseline());
  if (m_Controls->ExpiratoryReserveVolume->IsChecked())
    m_Controls->ExpiratoryReserveVolume->GetValue(patient.GetExpiratoryReserveVolume());
  if (m_Controls->InspiratoryCapacity->IsChecked())
    m_Controls->InspiratoryCapacity->GetValue(patient.GetInspiratoryCapacity());
  if (m_Controls->InspiratoryReserveVolume->IsChecked())
    m_Controls->InspiratoryReserveVolume->GetValue(patient.GetInspiratoryReserveVolume());
  if (m_Controls->VitalCapacity->IsChecked())
    m_Controls->VitalCapacity->GetValue(patient.GetVitalCapacity());
  if (m_Controls->ResidualVolume->IsChecked())
    m_Controls->ResidualVolume->GetValue(patient.GetResidualVolume());

  if (m_Controls->BloodVolumeBaseline->IsChecked())
    m_Controls->BloodVolumeBaseline->GetValue(patient.GetBloodVolumeBaseline());
  if (m_Controls->DiastolicArterialPressureBaseline->IsChecked())
    m_Controls->DiastolicArterialPressureBaseline->GetValue(patient.GetDiastolicArterialPressureBaseline());
  if (m_Controls->SystolicArterialPressureBaseline->IsChecked())
    m_Controls->SystolicArterialPressureBaseline->GetValue(patient.GetSystolicArterialPressureBaseline());
  if (m_Controls->HeartRateBaseline->IsChecked())
    m_Controls->HeartRateBaseline->GetValue(patient.GetHeartRateBaseline());
  if (m_Controls->MeanArterialPressureBaseline->IsChecked())
    m_Controls->MeanArterialPressureBaseline->GetValue(patient.GetMeanArterialPressureBaseline());

  if (m_Controls->HeartRateMaximum->IsChecked())
    m_Controls->HeartRateMaximum->GetValue(patient.GetHeartRateMaximum());
  if (m_Controls->HeartRateMinimum->IsChecked())
    m_Controls->HeartRateMinimum->GetValue(patient.GetHeartRateMinimum());
}

void QPatientEditorWidget::AtSteadyState(PhysiologyEngine& pulse)
{
  if (m_Controls->SaveState->isChecked())
    pulse.SerializeToFile(m_Controls->InitialStateLocation);
  // Sync the GUI Patient object with what Pulse Calculated
  m_Controls->EnginePatient.Copy(pulse.GetPatient());
}
void QPatientEditorWidget::AtSteadyStateUpdateUI()
{
  PatientToControls(m_Controls->EnginePatient);
  EnableInput(false);
  EnableConverter(true);
}
