/* Distributed under the Apache License, Version 2.0.
See accompanying NOTICE file for details.*/
#include "EnviornmentWidget.h"
#include "ui_Enviornment.h"
#include <QLayout>
#include <QGroupBox>
#include <QFileDialog>
#include <QMessageBox>

#include "EnviornmentWidget.h"
#include "AddPopup.h"

#include "cdm/CommonDataModel.h"
#include "PulsePhysiologyEngine.h"

#include "substance/SESubstance.h"
#include "substance/SESubstanceManager.h"
#include "substance/SESubstanceFraction.h"
#include "substance/SESubstanceConcentration.h"

#include "system/environment/SEEnvironment.h"
#include "system/environment/SEEnvironmentalConditions.h"
#include "system/environment/SEActiveConditioning.h"
#include "system/environment/SEAppliedTemperature.h"
#include "system/environment/actions/SEThermalApplication.h"
#include "system/environment/actions/SEChangeEnvironmentConditions.h"

#include "controls/ScalarWidget.h"
#include "controls/ScalarQuantityWidget.h"

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

class QEnviornmentWidget::Controls : public Ui::EnviornmentWidget
{
public:
  Controls(QTextEdit& log) : LogBox(log) {}
  QTextEdit&                         LogBox;
  std::string type = "Enviornment";
  // Environmental Conditions
  QScalarQuantityWidget<MassPerVolumeUnit>*      AirDensity;
  QScalarQuantityWidget<LengthPerTimeUnit>*      AirVelocity;
  QScalarQuantityWidget<TemperatureUnit>*        AmbientTemperature;
  QScalarQuantityWidget<PressureUnit>*           AtmosphericPressure;
  QScalarQuantityWidget<HeatResistanceAreaUnit>* ClothingResistance;
  QScalarWidget*                                 Emissivity;
  QScalarQuantityWidget<TemperatureUnit>*        MeanRadiantTemperature;
  QScalarWidget*                                 RelativeHumidity;
  QScalarQuantityWidget<TemperatureUnit>*        RespirationAmbientTemperature;

  // Eventually, These should be dynamic based on a list of substances
  SESubstance*                                   O2;
  SESubstance*                                   CO2;
  SESubstance*                                   N2;
  SESubstance*                                   CO;
  QScalarWidget*                                 AmbientO2;
  QScalarWidget*                                 AmbientCO2;
  QScalarWidget*                                 AmbientN2;
  QScalarWidget*                                 AmbientCO;
  SEScalar0To1                                   invalidFraction;
  // And we should add the ability to add new particulate definitions
  SESubstance*                                   Smoke;
  QScalarQuantityWidget<MassPerVolumeUnit>*      AmbientSmoke;
  SEScalarMassPerVolume                          invalidConcentration;

  QScalarQuantityWidget<PowerUnit>*              CoolingPower;
  QScalarWidget*                                 CoolingFraction;
  QScalarQuantityWidget<AreaUnit>*               CoolingArea;

  QScalarQuantityWidget<PowerUnit>*              HeatingPower;
  QScalarWidget*                                 HeatingFraction;
  QScalarQuantityWidget<AreaUnit>*               HeatingArea;

  QScalarWidget*                                 AppliedFraction;
  QScalarQuantityWidget<TemperatureUnit>*        AppliedTemperature;
  QScalarQuantityWidget<AreaUnit>*               AppliedArea;

  SEThermalApplication*                          ThermalApplication;
  SEChangeEnvironmentConditions*                 EnvironmentalConditions;
  bool                                           sendEnvironment = false;
  bool                                           sendAction = false;
  bool                                           CoolingFracLast = false;
  bool                                           HeatingFracLast = false;
  bool                                           AppliedFracLast = false;
};

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

  ////////////////////////////////////
  // Setup Environmental Conditions //
  ////////////////////////////////////

  m_Controls->AirDensity = new QScalarQuantityWidget<MassPerVolumeUnit>("Air Density", 0.0, 10.0, 1, MassPerVolumeUnit::g_Per_L, ScalarOptionWidget::Check, this);
  m_Controls->AirDensity->enableConverter(true);
  m_Controls->AirDensity->enableInput(true);
  m_Controls->AirDensity->addUnit(MassPerVolumeUnit::g_Per_m3);
  m_Controls->ConditionsProperties->layout()->addWidget(m_Controls->AirDensity);
  m_Controls->AirVelocity = new QScalarQuantityWidget<LengthPerTimeUnit>("Air Velocity", 0.0, 30.0, 1, LengthPerTimeUnit::ft_Per_s, ScalarOptionWidget::Check, this);
  m_Controls->AirVelocity->enableConverter(true);
  m_Controls->AirVelocity->enableInput(true);
  m_Controls->AirVelocity->addUnit(LengthPerTimeUnit::m_Per_s);
  m_Controls->ConditionsProperties->layout()->addWidget(m_Controls->AirVelocity);
  m_Controls->AmbientTemperature = new QScalarQuantityWidget<TemperatureUnit>("Ambient Temperature", 0.0, 150.0, 1, TemperatureUnit::F, ScalarOptionWidget::Check, this);
  m_Controls->AmbientTemperature->enableConverter(true);
  m_Controls->AmbientTemperature->enableInput(true);
  m_Controls->AmbientTemperature->addUnit(TemperatureUnit::C);
  m_Controls->ConditionsProperties->layout()->addWidget(m_Controls->AmbientTemperature);
  m_Controls->AtmosphericPressure = new QScalarQuantityWidget<PressureUnit>("Atmospheric Pressure", 0.0, 100.0, 1, PressureUnit::psi, ScalarOptionWidget::Check, this);
  m_Controls->AtmosphericPressure->enableConverter(true);
  m_Controls->AtmosphericPressure->enableInput(true);
  m_Controls->AtmosphericPressure->addUnit(PressureUnit::mmHg);
  m_Controls->AtmosphericPressure->addUnit(PressureUnit::Pa);
  m_Controls->ConditionsProperties->layout()->addWidget(m_Controls->AtmosphericPressure);
  m_Controls->ClothingResistance = new QScalarQuantityWidget<HeatResistanceAreaUnit>("Clothing Resistance", 0, 65, 1, HeatResistanceAreaUnit::clo, ScalarOptionWidget::Check, this);
  m_Controls->ClothingResistance->enableConverter(true);
  m_Controls->ClothingResistance->enableInput(true);
  m_Controls->ClothingResistance->addUnit(HeatResistanceAreaUnit::clo);
  m_Controls->ClothingResistance->addUnit(HeatResistanceAreaUnit::rsi);
  m_Controls->ConditionsProperties->layout()->addWidget(m_Controls->ClothingResistance);
  m_Controls->Emissivity = new QScalarWidget("Emissivity", 0.0, 1.0, .1, ScalarOptionWidget::Check, this);
  m_Controls->Emissivity->enableInput(true);
  m_Controls->ConditionsProperties->layout()->addWidget(m_Controls->Emissivity);
  m_Controls->MeanRadiantTemperature = new QScalarQuantityWidget<TemperatureUnit>("Mean Radiant Temperature", 0.0, 150.0, 1, TemperatureUnit::F, ScalarOptionWidget::Check, this);
  m_Controls->MeanRadiantTemperature->enableConverter(true);
  m_Controls->MeanRadiantTemperature->enableInput(true);
  m_Controls->MeanRadiantTemperature->addUnit(TemperatureUnit::C);
  m_Controls->ConditionsProperties->layout()->addWidget(m_Controls->MeanRadiantTemperature);
  m_Controls->RelativeHumidity = new QScalarWidget("Relative Humidity", 0.0, 1.0, 0.1, ScalarOptionWidget::Check, this);
  m_Controls->RelativeHumidity->enableInput(true);
  m_Controls->ConditionsProperties->layout()->addWidget(m_Controls->RelativeHumidity);
  m_Controls->RespirationAmbientTemperature = new QScalarQuantityWidget<TemperatureUnit>("Respiration Ambient Temperature", 0.0, 150.0, 1, TemperatureUnit::F, ScalarOptionWidget::Check, this);
  m_Controls->RespirationAmbientTemperature->enableConverter(true);
  m_Controls->RespirationAmbientTemperature->enableInput(true);
  m_Controls->RespirationAmbientTemperature->addUnit(TemperatureUnit::C);
  m_Controls->RespirationAmbientTemperature->addUnit(TemperatureUnit::F);
  m_Controls->RespirationAmbientTemperature->addUnit(TemperatureUnit::K);
  m_Controls->ConditionsProperties->layout()->addWidget(m_Controls->RespirationAmbientTemperature);

  ////////////////////////////////////////////////
  // Ambient Environment Gasses and Particulate //
  ////////////////////////////////////////////////
  m_Controls->O2 = qp.GetEngine().GetSubstanceManager().GetSubstance("Oxygen");
  m_Controls->AmbientO2 = new QScalarWidget("Oxygen", 0.0, 1.0, 0.1, ScalarOptionWidget::Check, this);
  m_Controls->AmbientO2->setDecimals(5);
  m_Controls->AmbientO2->enableInput(true);
  m_Controls->AmbientGasses->layout()->addWidget(m_Controls->AmbientO2);
  m_Controls->CO2 = qp.GetEngine().GetSubstanceManager().GetSubstance("CarbonDioxide");
  m_Controls->AmbientCO2 = new QScalarWidget("Carbon Dioxide", 0.0, 1.0, 0.1, ScalarOptionWidget::Check, this);
  m_Controls->AmbientCO2->setDecimals(5);
  m_Controls->AmbientCO2->enableInput(true);
  m_Controls->AmbientGasses->layout()->addWidget(m_Controls->AmbientCO2);
  m_Controls->N2 = qp.GetEngine().GetSubstanceManager().GetSubstance("Nitrogen");
  m_Controls->AmbientN2 = new QScalarWidget("Nitrogen", 0.0, 1.0, 0.1, ScalarOptionWidget::Check, this);
  m_Controls->AmbientN2->setDecimals(5);
  m_Controls->AmbientN2->enableInput(true);
  m_Controls->AmbientGasses->layout()->addWidget(m_Controls->AmbientN2);
  m_Controls->CO = qp.GetEngine().GetSubstanceManager().GetSubstance("CarbonMonoxide");
  m_Controls->AmbientCO = new QScalarWidget("Carbon Monoxide", 0.0, 1.0, 0.1, ScalarOptionWidget::Check, this);
  m_Controls->AmbientCO->setDecimals(5);
  m_Controls->AmbientCO->enableInput(true);
  m_Controls->AmbientGasses->layout()->addWidget(m_Controls->AmbientCO);

  m_Controls->Smoke = qp.GetEngine().GetSubstanceManager().GetSubstance("ForestFireParticulate");
  m_Controls->AmbientSmoke = new QScalarQuantityWidget<MassPerVolumeUnit>("Smoke", 0.0, 1.0, 0.1, MassPerVolumeUnit::mg_Per_m3, ScalarOptionWidget::Check, this);
  m_Controls->AmbientSmoke->enableInput(true);
  m_Controls->AmbientSmoke->enableConverter(true);
  m_Controls->AmbientSmoke->addUnit(MassPerVolumeUnit::g_Per_mL);
  m_Controls->AmbientSmoke->addUnit(MassPerVolumeUnit::g_Per_L);
  m_Controls->AmbientAerosols->layout()->addWidget(m_Controls->AmbientSmoke);

  ///////////////////////////////
  // Setup Environment Actions //
  ///////////////////////////////

  m_Controls->ActiveCoolingCheck->setChecked(false);
  m_Controls->ActiveCoolingCheck->setEnabled(false);
  m_Controls->CoolingPower = new QScalarQuantityWidget<PowerUnit>("Power", 0.0, 150.0, 1, PowerUnit::J_Per_s, ScalarOptionWidget::None, this);
  m_Controls->CoolingPower->setDisabled(true);
  m_Controls->CoolingPower->addUnit(PowerUnit::kcal_Per_hr);
  m_Controls->CoolingPower->addUnit(PowerUnit::BTU_Per_hr);
  m_Controls->CoolingPower->addUnit(PowerUnit::W);
  m_Controls->ActiveCoolingWidget->layout()->addWidget(m_Controls->CoolingPower);
  m_Controls->CoolingFraction = new QScalarWidget("Surface Area Fraction", 0.0, 1.0, 0.1, ScalarOptionWidget::Radio, this);
  m_Controls->CoolingFraction->setDisabled(true);
  m_Controls->ActiveCoolingWidget->layout()->addWidget(m_Controls->CoolingFraction);
  m_Controls->CoolingArea = new QScalarQuantityWidget<AreaUnit>("Surface Area", 0.0, 150.0, 1, AreaUnit::m2, ScalarOptionWidget::Radio, this);
  m_Controls->CoolingArea->setDisabled(true);
  m_Controls->CoolingArea->addUnit(AreaUnit::cm2);
  m_Controls->ActiveCoolingWidget->layout()->addWidget(m_Controls->CoolingArea);
  // Connect Signals/Slots
  connect(m_Controls->ActiveCoolingCheck, SIGNAL(clicked()), this, SLOT(EnableCooling()));
  connect(m_Controls->CoolingFraction->getRadioButton(), SIGNAL(clicked()), this, SLOT(EnableCoolingSurfaceAreaFraction()));
  connect(m_Controls->CoolingArea->getRadioButton(), SIGNAL(clicked()), this, SLOT(EnableCoolingSurfaceArea()));
  m_Controls->CoolingPower->enableConverter(true);
  m_Controls->CoolingArea->enableConverter(true);

  m_Controls->ActiveHeatingCheck->setChecked(false);
  m_Controls->ActiveHeatingCheck->setEnabled(false);
  m_Controls->HeatingPower = new QScalarQuantityWidget<PowerUnit>("Power", 0.0, 150.0, 1, PowerUnit::J_Per_s, ScalarOptionWidget::None, this);
  m_Controls->HeatingPower->setDisabled(true);
  m_Controls->HeatingPower->addUnit(PowerUnit::kcal_Per_hr);
  m_Controls->HeatingPower->addUnit(PowerUnit::BTU_Per_hr);
  m_Controls->HeatingPower->addUnit(PowerUnit::W);
  m_Controls->ActiveHeatingWidget->layout()->addWidget(m_Controls->HeatingPower);
  m_Controls->HeatingFraction = new QScalarWidget("Surface Area Fraction", 0.0, 1.0, 0.1, ScalarOptionWidget::Radio, this);
  m_Controls->HeatingFraction->setDisabled(true);
  m_Controls->ActiveHeatingWidget->layout()->addWidget(m_Controls->HeatingFraction);
  m_Controls->HeatingArea = new QScalarQuantityWidget<AreaUnit>("Surface Area", 0.0, 150.0, 1, AreaUnit::m2, ScalarOptionWidget::Radio, this);
  m_Controls->HeatingArea->setDisabled(true);
  m_Controls->HeatingArea->addUnit(AreaUnit::cm2);
  m_Controls->ActiveHeatingWidget->layout()->addWidget(m_Controls->HeatingArea);
  // Connect Signals/Slots
  connect(m_Controls->ActiveHeatingCheck, SIGNAL(clicked()), this, SLOT(EnableHeating()));
  connect(m_Controls->HeatingFraction->getRadioButton(), SIGNAL(clicked()), this, SLOT(EnableHeatingSurfaceAreaFraction()));
  connect(m_Controls->HeatingArea->getRadioButton(), SIGNAL(clicked()), this, SLOT(EnableHeatingSurfaceArea()));
  m_Controls->HeatingPower->enableConverter(true);
  m_Controls->HeatingArea->enableConverter(true);

  m_Controls->AppliedTempCheck->setChecked(false);
  m_Controls->AppliedTempCheck->setEnabled(false);
  m_Controls->AppliedTemperature = new QScalarQuantityWidget<TemperatureUnit>("Temperature", 0.0, 150.0, 1, TemperatureUnit::F, ScalarOptionWidget::None, this);
  m_Controls->AppliedTemperature->setDisabled(true);
  m_Controls->AppliedTemperature->addUnit(TemperatureUnit::C);
  m_Controls->AppliedTempWidget->layout()->addWidget(m_Controls->AppliedTemperature);
  m_Controls->AppliedFraction = new QScalarWidget("Surface Area Fraction", 0.0, 1.0, 0.1, ScalarOptionWidget::Radio, this);
  m_Controls->AppliedFraction->setDisabled(true);
  m_Controls->AppliedTempWidget->layout()->addWidget(m_Controls->AppliedFraction);
  m_Controls->AppliedArea = new QScalarQuantityWidget<AreaUnit>("Surface Area", 0.0, 150.0, 1, AreaUnit::m2, ScalarOptionWidget::Radio, this);
  m_Controls->AppliedArea->setDisabled(true);
  m_Controls->AppliedArea->addUnit(AreaUnit::cm2);
  m_Controls->AppliedTempWidget->layout()->addWidget(m_Controls->AppliedArea);
  // Connect Signals/Slots
  connect(m_Controls->AppliedTempCheck, SIGNAL(clicked()), this, SLOT(EnableAppliedTemp()));
  connect(m_Controls->AppliedFraction->getRadioButton(), SIGNAL(clicked()), this, SLOT(EnableAppliedSurfaceAreaFraction()));
  connect(m_Controls->AppliedArea->getRadioButton(), SIGNAL(clicked()), this, SLOT(EnableAppliedTempSurfaceArea()));
  m_Controls->AppliedTemperature->enableConverter(true);
  m_Controls->AppliedArea->enableConverter(true);

  m_Controls->ThermalApplication = new SEThermalApplication();
  m_Controls->ThermalApplication->GetActiveCooling().GetPower().SetValue(0, PowerUnit::J_Per_s);
  m_Controls->ThermalApplication->GetActiveHeating().GetPower().SetValue(0, PowerUnit::J_Per_s);
  m_Controls->ThermalApplication->GetAppliedTemperature().SetState(eSwitch::Off);
  m_Controls->EnvironmentalConditions = new SEChangeEnvironmentConditions(qp.GetEngine().GetSubstanceManager());

  connect(m_Controls->ApplyAll, SIGNAL(clicked()), this, SLOT(ControlsToEnvironment()));
  connect(m_Controls->LoadEnvironment, SIGNAL(clicked()), this, SLOT(LoadEnvironmentFile()));
  connect(m_Controls->SaveEnviornment, SIGNAL(clicked()), this, SLOT(SaveEnvironmentFile()));
  Reset();
}

QEnviornmentWidget::~QEnviornmentWidget()
{
  // TODO Clean up all the widgets
  m_Controls->Enviornment->close();
  delete m_Controls;
}

void QEnviornmentWidget::Reset()
{
  LoadEnvironmentFile("./environments/Standard.json");
  m_Controls->sendEnvironment = false;
  m_Controls->sendAction = false;

  m_Controls->CoolingArea->reset();
  m_Controls->CoolingFraction->reset();
  m_Controls->CoolingPower->reset();
  m_Controls->HeatingFraction->reset();
  m_Controls->HeatingArea->reset();
  m_Controls->HeatingPower->reset();
  m_Controls->AppliedFraction->reset();
  m_Controls->AppliedTemperature->reset();
  m_Controls->AppliedArea->reset();
  m_Controls->AppliedFracLast = false;
  m_Controls->CoolingFracLast = false;
  m_Controls->HeatingFracLast = false;

  EnableControls(true, false);
}

void QEnviornmentWidget::EnableControls(bool conditions, bool actions)
{
  m_Controls->AirDensity->enableInput(conditions);
  m_Controls->AirVelocity->enableInput(conditions);
  m_Controls->AmbientTemperature->enableInput(conditions);
  m_Controls->AtmosphericPressure->enableInput(conditions);
  m_Controls->ClothingResistance->enableInput(conditions);
  m_Controls->Emissivity->enableInput(conditions);
  m_Controls->MeanRadiantTemperature->enableInput(conditions);
  m_Controls->RelativeHumidity->enableInput(conditions);
  m_Controls->RespirationAmbientTemperature->enableInput(conditions);

  m_Controls->AmbientO2->enableInput(conditions);
  m_Controls->AmbientCO2->enableInput(conditions);
  m_Controls->AmbientN2->enableInput(conditions);
  m_Controls->AmbientCO->enableInput(conditions);

  m_Controls->AmbientSmoke->enableInput(conditions);

  m_Controls->LoadEnvironment->setEnabled(conditions);
  m_Controls->SaveEnviornment->setEnabled(conditions);

  m_Controls->ActiveCoolingCheck->setChecked(false);
  m_Controls->ActiveCoolingCheck->setEnabled(actions);

  m_Controls->ActiveHeatingCheck->setChecked(false);
  m_Controls->ActiveHeatingCheck->setEnabled(actions);

  m_Controls->AppliedTempCheck->setEnabled(actions);
  m_Controls->AppliedTempCheck->setChecked(false);
  EnableCooling();
  EnableHeating();
  EnableAppliedTemp();
  m_Controls->ApplyAll->setEnabled(actions);
}

void QEnviornmentWidget::LoadEnvironmentFile()
{
  QString fileName = QFileDialog::getOpenFileName(this,
    "Open Environment", "./environments", "Environment Files (*.json)");
  if (fileName.isEmpty())
    return;

  std::string s = fileName.toStdString();
  LoadEnvironmentFile(s);
}
void QEnviornmentWidget::LoadEnvironmentFile(const std::string& fileName)
{
  if(m_Controls->EnvironmentalConditions->GetConditions().SerializeFromFile(fileName, SerializationFormat::JSON))
    EnvironmentToControls();
  else 
  {
    QMessageBox messageBox;
    std::string message = "Unable to load Enviornment File";
    messageBox.critical(0, "Error", QString::fromUtf8(message.c_str()));
    messageBox.setFixedSize(500, 200);
  }
}

void QEnviornmentWidget::SaveEnvironmentFile()
{
  QString fileName = QFileDialog::getSaveFileName(this,
    "Save Enviornment", "./environments", "Environment Files (*.json)");
  if (fileName.isEmpty())
    return;

  std::string s = fileName.toStdString();
  SaveEnviornmentFile(s);
}
void QEnviornmentWidget::SaveEnviornmentFile(const std::string& fileName)
{
  ControlsToEnvironment();
  if (!m_Controls->EnvironmentalConditions->GetConditions().SerializeToFile(fileName, SerializationFormat::JSON) )
  {
    QMessageBox messageBox;
      std::string message = "Unable to save Enviornment File";
      messageBox.critical(0, "Error", QString::fromUtf8(message.c_str()));
      messageBox.setFixedSize(500, 200);
  }
}

void QEnviornmentWidget::ControlsToEnvironment()
{
  m_Controls->AirDensity->getValue(m_Controls->EnvironmentalConditions->GetConditions().GetAirDensity());
  m_Controls->AirVelocity->getValue(m_Controls->EnvironmentalConditions->GetConditions().GetAirVelocity());
  m_Controls->AmbientTemperature->getValue(m_Controls->EnvironmentalConditions->GetConditions().GetAmbientTemperature());
  m_Controls->AtmosphericPressure->getValue(m_Controls->EnvironmentalConditions->GetConditions().GetAtmosphericPressure());
  m_Controls->ClothingResistance->getValue(m_Controls->EnvironmentalConditions->GetConditions().GetClothingResistance());
  m_Controls->Emissivity->getValue(m_Controls->EnvironmentalConditions->GetConditions().GetEmissivity());
  m_Controls->MeanRadiantTemperature->getValue(m_Controls->EnvironmentalConditions->GetConditions().GetMeanRadiantTemperature());
  m_Controls->RelativeHumidity->getValue(m_Controls->EnvironmentalConditions->GetConditions().GetRelativeHumidity());
  m_Controls->RespirationAmbientTemperature->getValue(m_Controls->EnvironmentalConditions->GetConditions().GetRespirationAmbientTemperature());
  double fractotal = 0.0;
  for (auto g : m_Controls->EnvironmentalConditions->GetConditions().GetAmbientGases())
  {
    if (&g->GetSubstance() == m_Controls->O2)
    {
      m_Controls->AmbientO2->getValue(g->GetFractionAmount());
      fractotal = fractotal + g->GetFractionAmount().GetValue();
      continue;
    }
    if (&g->GetSubstance() == m_Controls->CO2)
    {
      m_Controls->AmbientCO2->getValue(g->GetFractionAmount());
      fractotal = fractotal + g->GetFractionAmount().GetValue();
      continue;
    }
    if (&g->GetSubstance() == m_Controls->N2)
    {
      m_Controls->AmbientN2->getValue(g->GetFractionAmount());
      fractotal = fractotal + g->GetFractionAmount().GetValue();
      continue;
    }
    if (&g->GetSubstance() == m_Controls->CO)
    {
      m_Controls->AmbientCO->getValue(g->GetFractionAmount());
      fractotal = fractotal + g->GetFractionAmount().GetValue();
      continue;
    }
  }

  m_Controls->AmbientSmoke->setValue(m_Controls->invalidConcentration);
  for (auto g : m_Controls->EnvironmentalConditions->GetConditions().GetAmbientAerosols())
  {
    if (&g->GetSubstance() == m_Controls->Smoke)
    {
      m_Controls->AmbientSmoke->setValue(g->GetConcentration());
    }
  }
  // Ensure that Ambient Gas Fractions sum up to one, if not throw popup error
  if (abs(fractotal - (double)1)<.000001)
  {
    m_Controls->sendEnvironment = true;
    // TODO Set our send boolean only if data has changed from the UI to what we have
  }
  else
  {
    QMessageBox messageBox;
    std::string frac = std::to_string(fractotal);
    std::string message = "Ambient Gas Fractions Do Not Sum to 1.0";
    messageBox.critical(0, "Error", QString::fromUtf8(message.c_str()));
    messageBox.setFixedSize(500, 200);
  }

  if (m_Controls->ActiveCoolingCheck->isChecked())
  {
    m_Controls->CoolingPower->getValue(m_Controls->ThermalApplication->GetActiveCooling().GetPower());
    if (m_Controls->CoolingArea->getRadioButton()->isChecked())
      m_Controls->CoolingArea->getValue(m_Controls->ThermalApplication->GetActiveCooling().GetSurfaceArea());
    else
      m_Controls->CoolingFraction->getValue(m_Controls->ThermalApplication->GetActiveCooling().GetSurfaceAreaFraction());
  }
  else
    m_Controls->ThermalApplication->GetActiveCooling().GetPower().SetValue(0, PowerUnit::J_Per_s);

  if (m_Controls->ActiveHeatingCheck->isChecked())
  {
    m_Controls->HeatingPower->getValue(m_Controls->ThermalApplication->GetActiveHeating().GetPower());
    if (m_Controls->HeatingArea->getRadioButton()->isChecked())
      m_Controls->HeatingArea->getValue(m_Controls->ThermalApplication->GetActiveHeating().GetSurfaceArea());
    else
      m_Controls->HeatingFraction->getValue(m_Controls->ThermalApplication->GetActiveHeating().GetSurfaceAreaFraction());
  }
  else
    m_Controls->ThermalApplication->GetActiveHeating().GetPower().SetValue(0, PowerUnit::J_Per_s);

  if (m_Controls->AppliedTempCheck->isChecked())
  {
    m_Controls->ThermalApplication->GetAppliedTemperature().SetState(eSwitch::On);
    m_Controls->AppliedTemperature->getValue(m_Controls->ThermalApplication->GetAppliedTemperature().GetTemperature());
    if (m_Controls->AppliedArea->getRadioButton()->isChecked())
      m_Controls->AppliedArea->getValue(m_Controls->ThermalApplication->GetAppliedTemperature().GetSurfaceArea());
    else
      m_Controls->AppliedFraction->getValue(m_Controls->ThermalApplication->GetAppliedTemperature().GetSurfaceAreaFraction());
  }
  else
    m_Controls->ThermalApplication->GetAppliedTemperature().SetState(eSwitch::Off);

  if (m_Controls->AppliedTempCheck->isChecked() || 
      m_Controls->ActiveCoolingCheck->isChecked() || 
      m_Controls->ActiveHeatingCheck->isChecked()) 
  {
    m_Controls->sendAction = true;
    // TODO Set our send boolean only if data has changed from the UI to what we have
  }
}

void QEnviornmentWidget::EnvironmentToControls()
{
  m_Controls->AirDensity->setValue(m_Controls->EnvironmentalConditions->GetConditions().GetAirDensity());
  m_Controls->AirVelocity->setValue(m_Controls->EnvironmentalConditions->GetConditions().GetAirVelocity());
  m_Controls->AmbientTemperature->setValue(m_Controls->EnvironmentalConditions->GetConditions().GetAmbientTemperature());
  m_Controls->AtmosphericPressure->setValue(m_Controls->EnvironmentalConditions->GetConditions().GetAtmosphericPressure());
  m_Controls->ClothingResistance->setValue(m_Controls->EnvironmentalConditions->GetConditions().GetClothingResistance());
  m_Controls->Emissivity->setValue(m_Controls->EnvironmentalConditions->GetConditions().GetEmissivity());
  m_Controls->MeanRadiantTemperature->setValue(m_Controls->EnvironmentalConditions->GetConditions().GetMeanRadiantTemperature());
  m_Controls->RelativeHumidity->setValue(m_Controls->EnvironmentalConditions->GetConditions().GetRelativeHumidity());
  m_Controls->RespirationAmbientTemperature->setValue(m_Controls->EnvironmentalConditions->GetConditions().GetRespirationAmbientTemperature());

  m_Controls->AmbientO2->setValue(m_Controls->invalidFraction);
  m_Controls->AmbientCO2->setValue(m_Controls->invalidFraction);
  m_Controls->AmbientN2->setValue(m_Controls->invalidFraction);
  m_Controls->AmbientCO->setValue(m_Controls->invalidFraction);
  for (auto g : m_Controls->EnvironmentalConditions->GetConditions().GetAmbientGases())
  {
    if (&g->GetSubstance() == m_Controls->O2)
    {
      m_Controls->AmbientO2->setValue(g->GetFractionAmount());
      continue;
    }
    if (&g->GetSubstance() == m_Controls->CO2)
    {
      m_Controls->AmbientCO2->setValue(g->GetFractionAmount());
      continue;
    }
    if (&g->GetSubstance() == m_Controls->N2)
    {
      m_Controls->AmbientN2->setValue(g->GetFractionAmount());
      continue;
    }
    if (&g->GetSubstance() == m_Controls->CO)
    {
      m_Controls->AmbientCO->setValue(g->GetFractionAmount());
      continue;
    }
  }

  m_Controls->AmbientSmoke->setValue(m_Controls->invalidConcentration);
  for (auto g : m_Controls->EnvironmentalConditions->GetConditions().GetAmbientAerosols())
  {
    if (&g->GetSubstance() == m_Controls->Smoke)
    {
      m_Controls->AmbientSmoke->setValue(g->GetConcentration());
    }
  }

  // No need to push actions to the UI
}

void QEnviornmentWidget::AtSteadyState(PhysiologyEngine& pulse)
{
  m_Controls->EnvironmentalConditions->GetConditions().Copy(*pulse.GetEnvironment()->GetConditions());
}
void QEnviornmentWidget::AtSteadyStateUpdateUI()
{
  EnvironmentToControls();
  EnableControls(true, true);
}

void QEnviornmentWidget::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
  
  if (m_Controls->sendEnvironment)
  {
    pulse.ProcessAction(*m_Controls->EnvironmentalConditions);
    m_Controls->sendEnvironment = false;
  }
  if (m_Controls->sendAction)
  {
    pulse.ProcessAction(*m_Controls->ThermalApplication);
    m_Controls->sendAction = false;
  }

}
void QEnviornmentWidget::PhysiologyUpdateUI()
{// This is called from a slot, you can update UI here

  // Nothing is expected to be in the environment
}

void QEnviornmentWidget::EnableCooling()
{
  bool b = m_Controls->ActiveCoolingCheck->isChecked();
  if (b)
  {
    m_Controls->CoolingPower->setEnabled(true);
    m_Controls->CoolingArea->setEnabled(true);
    m_Controls->CoolingFraction->setEnabled(true);

    m_Controls->CoolingPower->enableInput(true);
    if (m_Controls->CoolingFracLast)
    {
      m_Controls->CoolingArea->enableInput(false);
      m_Controls->CoolingFraction->enableInput(true);
    }
    else
    {
      m_Controls->CoolingArea->enableInput(true);
      m_Controls->CoolingFraction->enableInput(false);
    }
  }
  else
  {
    m_Controls->CoolingFracLast = m_Controls->CoolingFraction->getRadioButton()->isChecked();
    m_Controls->CoolingPower->setDisabled(true);
    m_Controls->CoolingArea->setDisabled(true);
    m_Controls->CoolingFraction->setDisabled(true);
  }
}
void QEnviornmentWidget::EnableCoolingSurfaceArea()
{
  bool b = m_Controls->CoolingArea->getRadioButton()->isChecked();
  m_Controls->CoolingArea->enableInput(b);
  m_Controls->CoolingFraction->enableInput(!b);
}
void QEnviornmentWidget::EnableCoolingSurfaceAreaFraction()
{
  bool b = m_Controls->CoolingFraction->getRadioButton()->isChecked();
  m_Controls->CoolingArea->enableInput(!b);
  m_Controls->CoolingFraction->enableInput(b);
}

void QEnviornmentWidget::EnableHeating()
{
  bool b = m_Controls->ActiveHeatingCheck->isChecked();
  if (b)
  {
    m_Controls->HeatingPower->setEnabled(true);
    m_Controls->HeatingArea->setEnabled(true);
    m_Controls->HeatingFraction->setEnabled(true);

    m_Controls->HeatingPower->enableInput(true);
    if (m_Controls->HeatingFracLast)
    {
      m_Controls->HeatingArea->enableInput(false);
      m_Controls->HeatingFraction->enableInput(true);
    }
    else
    {
      m_Controls->HeatingArea->enableInput(true);
      m_Controls->HeatingFraction->enableInput(false);
    }
  }
  else
  {
    m_Controls->HeatingFracLast = m_Controls->HeatingFraction->getRadioButton()->isChecked();
    m_Controls->HeatingPower->setDisabled(true);
    m_Controls->HeatingArea->setDisabled(true);
    m_Controls->HeatingFraction->setDisabled(true);
  }
}
void QEnviornmentWidget::EnableHeatingSurfaceArea()
{
  bool b = m_Controls->HeatingArea->getRadioButton()->isChecked();
  m_Controls->HeatingArea->enableInput(b);
  m_Controls->HeatingFraction->enableInput(!b);
}
void QEnviornmentWidget::EnableHeatingSurfaceAreaFraction()
{
  bool b = m_Controls->HeatingFraction->getRadioButton()->isChecked();
  m_Controls->HeatingArea->enableInput(!b);
  m_Controls->HeatingFraction->enableInput(b);
}

void QEnviornmentWidget::EnableAppliedTemp()
{
  bool b = m_Controls->AppliedTempCheck->isChecked();
  if (b)
  {
    m_Controls->AppliedTemperature->setEnabled(true);
    m_Controls->AppliedArea->setEnabled(true);
    m_Controls->AppliedFraction->setEnabled(true);

    m_Controls->AppliedTemperature->enableInput(true);
    if (m_Controls->AppliedFracLast)
    {
      m_Controls->AppliedArea->enableInput(false);
      m_Controls->AppliedFraction->enableInput(true);
    }
    else
    {
      m_Controls->AppliedArea->enableInput(true);
      m_Controls->AppliedFraction->enableInput(false);
    }
  }
  else
  {
    m_Controls->AppliedFracLast = m_Controls->AppliedFraction->getRadioButton()->isChecked();
    m_Controls->AppliedTemperature->setDisabled(true);
    m_Controls->AppliedArea->setDisabled(true);
    m_Controls->AppliedFraction->setDisabled(true);
  }
}

void QEnviornmentWidget::EnableAppliedTempSurfaceArea()
{
  bool b = m_Controls->AppliedArea->getRadioButton()->isChecked();
  m_Controls->AppliedArea->enableInput(b);
  m_Controls->AppliedFraction->enableInput(!b);
}

void QEnviornmentWidget::EnableAppliedSurfaceAreaFraction()
{
  bool b = m_Controls->AppliedFraction->getRadioButton()->isChecked();
  m_Controls->AppliedArea->enableInput(!b);
  m_Controls->AppliedFraction->enableInput(b);
}


