/* Distributed under the Apache License, Version 2.0.
See accompanying NOTICE file for details.*/
#include "VitalsMonitorWidget.h"
#include "ui_VitalsMonitor.h"
#include <QLayout>
#include <QGraphicsLayout>

#include "QwtPulsePlot.h"

#include "PulsePhysiologyEngine.h"
#include "substance/SESubstanceManager.h"
#include "compartment/SECompartmentManager.h"
#include "compartment/fluid/SEGasCompartment.h"
#include "system/physiology/SEBloodChemistrySystem.h"
#include "system/physiology/SECardiovascularSystem.h"
#include "system/physiology/SERespiratorySystem.h"
#include "system/physiology/SEEnergySystem.h"
#include "system/equipment/electrocardiogram/SEElectroCardioGram.h"
#include "properties/SEScalarFrequency.h"
#include "properties/SEScalarTime.h"

class QVitalsMonitorWidget::Controls : public Ui::VitalsMonitorWidget
{
public:
  Controls(QTextEdit& log) : LogBox(log) {}
  QTextEdit&                    LogBox;
  double                        HeartRate_bpm;
  double                        ECG_III_mV;
  double                        ArterialPressure_mmHg;
  double                        MeanArterialPressure_mmHg;
  double                        DiastolicPressure_mmHg;
  double                        SystolicPressure_mmHg;
  double                        OxygenSaturation;
  double                        EndTidalCarbonDioxidePressure_mmHg;
  double                        RespirationRate_bpm;
  double                        Temperature_C;
  const SEGasSubstanceQuantity* CarinaCO2=nullptr;
};

QVitalsMonitorWidget::QVitalsMonitorWidget(QTextEdit& log, QWidget *parent, Qt::WindowFlags flags) : QWidget(parent,flags)
{
  m_Controls = new Controls(log);
  m_Controls->setupUi(this);

  m_Controls->ECGDisplayPlot->setMaxPoints(250);
  m_Controls->ECGDisplayPlot->setDataRange(-0.1, 0.9);

  m_Controls->ABPDisplayPlot->setMaxPoints(175);
  m_Controls->ABPDisplayPlot->setDataRange(70, 115);

  m_Controls->etCO2DisplayPlot->setMaxPoints(750);
  m_Controls->etCO2DisplayPlot->setDataRange(0.2, 30);
}

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

void QVitalsMonitorWidget::Reset()
{
  m_Controls->HeartRateValue->setText("0");
  m_Controls->BloodPressureValues->setText("0/0");
  m_Controls->MeanBloodPressureValue->setText("(0)");
  m_Controls->SpO2Value->setText("0");
  m_Controls->etCO2Value->setText("0");
  m_Controls->RespiratoryRateValue->setText("0");
  m_Controls->TempeartureValue->setText("0");

  m_Controls->ECGDisplayPlot->clear();
  m_Controls->ABPDisplayPlot->clear();
  m_Controls->etCO2DisplayPlot->clear();

  m_Controls->CarinaCO2 = nullptr;
}

void QVitalsMonitorWidget::ProcessPhysiology(PhysiologyEngine& pulse)
{// This is called from a thread, you should NOT update UI here
  // This is where we pull data from pulse, and push any actions to it

  m_Controls->HeartRate_bpm = pulse.GetCardiovascularSystem()->GetHeartRate(FrequencyUnit::Per_min);
  m_Controls->ECG_III_mV = pulse.GetElectroCardioGram()->GetLead3ElectricPotential(ElectricPotentialUnit::mV);
  m_Controls->ArterialPressure_mmHg = pulse.GetCardiovascularSystem()->GetArterialPressure(PressureUnit::mmHg);
  m_Controls->MeanArterialPressure_mmHg = pulse.GetCardiovascularSystem()->GetMeanArterialPressure(PressureUnit::mmHg);
  m_Controls->DiastolicPressure_mmHg = pulse.GetCardiovascularSystem()->GetDiastolicArterialPressure(PressureUnit::mmHg);
  m_Controls->SystolicPressure_mmHg = pulse.GetCardiovascularSystem()->GetSystolicArterialPressure(PressureUnit::mmHg);
  m_Controls->OxygenSaturation = pulse.GetBloodChemistrySystem()->GetOxygenSaturation();
  m_Controls->RespirationRate_bpm = pulse.GetRespiratorySystem()->GetRespirationRate(FrequencyUnit::Per_min);
  m_Controls->EndTidalCarbonDioxidePressure_mmHg = pulse.GetRespiratorySystem()->GetEndTidalCarbonDioxidePressure(PressureUnit::mmHg);
  m_Controls->Temperature_C = pulse.GetEnergySystem()->GetCoreTemperature(TemperatureUnit::C);

  if (m_Controls->CarinaCO2 == nullptr)
  {
    const SESubstance* CO2 = pulse.GetSubstanceManager().GetSubstance("CarbonDioxide");
    m_Controls->CarinaCO2 = pulse.GetCompartments().GetGasCompartment(pulse::PulmonaryCompartment::Carina)->GetSubstanceQuantity(*CO2);
  }
  double time_s = pulse.GetSimulationTime(TimeUnit::s);
  m_Controls->ECGDisplayPlot->append(time_s, m_Controls->ECG_III_mV);
  m_Controls->ABPDisplayPlot->append(time_s, m_Controls->ArterialPressure_mmHg);
  m_Controls->etCO2DisplayPlot->append(time_s, m_Controls->CarinaCO2->GetPartialPressure(PressureUnit::mmHg));
}

void QVitalsMonitorWidget::PhysiologyUpdateUI()
{// This is called from a slot, you can update UI here
  // This is where we take the pulse data we pulled and push it to a UI widget
    m_Controls->HeartRateValue->setText(QString::number(int(m_Controls->HeartRate_bpm),'d',0));
    m_Controls->BloodPressureValues->setText(QString::number(int(m_Controls->SystolicPressure_mmHg), 'd', 0)+"/"+QString::number(int(m_Controls->DiastolicPressure_mmHg), 'd', 0));
    m_Controls->MeanBloodPressureValue->setText("("+QString::number(int(m_Controls->MeanArterialPressure_mmHg), 'd', 0)+")");
    m_Controls->SpO2Value->setText(QString::number(int(m_Controls->OxygenSaturation*100), 'd', 0));
    m_Controls->etCO2Value->setText(QString::number(int(m_Controls->EndTidalCarbonDioxidePressure_mmHg), 'd', 0));
    m_Controls->RespiratoryRateValue->setText(QString::number(int(m_Controls->RespirationRate_bpm), 'd', 0));
    m_Controls->TempeartureValue->setText(QString::number(m_Controls->Temperature_C, 'd', 1));
}
