/* 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 "controls/AddPopup.h"
#include "controls/EnviornmentWidget.h"
#include "controls/ScalarWidget.h"
#include "controls/ScalarQuantityWidget.h"

#include "pulse/PulsePhysiologyEngine.h"
#include "pulse/PulseScenario.h"
#include "pulse/engine/SEPatientConfiguration.h"
#include "pulse/patient/SEPatient.h"
#include "pulse/substance/SESubstance.h"
#include "pulse/substance/SESubstanceManager.h"
#include "pulse/substance/SESubstanceFraction.h"
#include "pulse/substance/SESubstanceConcentration.h"
#include "pulse/system/environment/SEEnvironment.h"
#include "pulse/system/environment/SEEnvironmentalConditions.h"
#include "pulse/system/environment/SEActiveConditioning.h"
#include "pulse/system/environment/SEAppliedTemperature.h"
#include "pulse/system/environment/actions/SEThermalApplication.h"
#include "pulse/system/environment/actions/SEChangeEnvironmentalConditions.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"
#include "pulse/properties/SEScalarHeatResistanceArea.h"
#include "pulse/properties/SEScalarLengthPerTime.h"
#include "pulse/properties/SEScalarTemperature.h"
#include "pulse/properties/SEScalarPower.h"
#include "pulse/utils/FileUtils.h"

class QEnviornmentWidget::Controls : public Ui::EnviornmentWidget
{
public:
  Controls(QPulse& qp) : Pulse(qp) {}

  QPulse&                                        Pulse;
  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;
  SESubstanceManager*                            SubMgr;
  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;
  SEChangeEnvironmentalConditions*               ChangeEnvironmentalConditions;
  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);
  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->SubMgr = &qp.GetScenario().GetSubstanceManager();
  m_Controls->O2 = qp.GetScenario().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.GetScenario().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.GetScenario().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.GetScenario().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.GetScenario().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->ChangeEnvironmentalConditions = new SEChangeEnvironmentalConditions(qp.GetScenario().GetLogger());

  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", "JSON (*.json);;Protobuf Binary (*.pbb)");
  if (fileName.isEmpty())
    return;

  std::string s = fileName.toStdString();
  LoadEnvironmentFile(s);
}
void QEnviornmentWidget::LoadEnvironmentFile(const std::string& fileName)
{
  if(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().SerializeFromFile(fileName, *m_Controls->SubMgr))
    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", "JSON (*.json);;Protobuf Binary (*.pbb)");
  if (fileName.isEmpty())
    return;

  std::string s = fileName.toStdString();
  SaveEnviornmentFile(s);
}
void QEnviornmentWidget::SaveEnviornmentFile(const std::string& fileName)
{
  ControlsToEnvironment();
  if (!m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().SerializeToFile(fileName) )
  {
    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->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetAirDensity());
  m_Controls->AirVelocity->GetValue(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetAirVelocity());
  m_Controls->AmbientTemperature->GetValue(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetAmbientTemperature());
  m_Controls->AtmosphericPressure->GetValue(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetAtmosphericPressure());
  m_Controls->ClothingResistance->GetValue(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetClothingResistance());
  m_Controls->Emissivity->GetValue(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetEmissivity());
  m_Controls->MeanRadiantTemperature->GetValue(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetMeanRadiantTemperature());
  m_Controls->RelativeHumidity->GetValue(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetRelativeHumidity());
  m_Controls->RespirationAmbientTemperature->GetValue(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetRespirationAmbientTemperature());
  double fractotal = 0.0;
  for (auto g : m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().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->ChangeEnvironmentalConditions->GetEnvironmentalConditions().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->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetAirDensity());
  m_Controls->AirVelocity->SetValue(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetAirVelocity());
  m_Controls->AmbientTemperature->SetValue(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetAmbientTemperature());
  m_Controls->AtmosphericPressure->SetValue(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetAtmosphericPressure());
  m_Controls->ClothingResistance->SetValue(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetClothingResistance());
  m_Controls->Emissivity->SetValue(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetEmissivity());
  m_Controls->MeanRadiantTemperature->SetValue(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetMeanRadiantTemperature());
  m_Controls->RelativeHumidity->SetValue(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetRelativeHumidity());
  m_Controls->RespirationAmbientTemperature->SetValue(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().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->ChangeEnvironmentalConditions->GetEnvironmentalConditions().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->ChangeEnvironmentalConditions->GetEnvironmentalConditions().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->ChangeEnvironmentalConditions->GetEnvironmentalConditions().Copy(*pulse.GetEnvironment()->GetEnvironmentalConditions(), *m_Controls->SubMgr);
}
void QEnviornmentWidget::AtSteadyStateUpdateUI()
{
  EnvironmentToControls();
  bool show = (m_Controls->Pulse.GetMode() == ExplorerMode::Editor);
  EnableControls(show, show);
}

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->ChangeEnvironmentalConditions);
    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);
}
