/* Distributed under the Apache License, Version 2.0.
See accompanying NOTICE file for details.*/
#include "DynamicControlsWidget.h"
#include "ui_DynamicControls.h"
#include <QFileDialog>
#include <QMessageBox>
#include <thread>

#include "PatientEditorWidget.h"
#include "ConditionsEditorWidget.h"
#include "ActionsEditorWidget.h"
#include "ScenarioEditorWidget.h"
//Showcases
#include "showcases/AnaphylaxisShowcaseWidget.h"
#include "showcases/MultiTraumaShowcaseWidget.h"

#include "cdm/CommonDataModel.h"
#include "PulsePhysiologyEngine.h"
#include "cdm/engine/SEDataRequestManager.h"
#include "cdm/engine/SEPatientConfiguration.h"
#include "cdm/engine/SEEngineTracker.h"
#include "cdm/utils/TimingProfile.h"

#include "cdm/properties/SEScalarVolume.h"
#include "cdm/properties/SEScalarVolumePerTime.h"

class QDynamicControlsWidget::Controls : public Ui::DynamicControlsWidget
{
public:
  Controls(QPulse& qp) : Pulse(qp) {}
  ~Controls()
  {
    delete PatientEditor;
    delete AnaphylaxisShowcaseWidget;
    delete MultiTraumaShowcaseWidget;
  }
  QString                     EngineStateFile;
  QString                     ScenarioFile; 
  ScenarioInput               ScenarioMode = ScenarioInput::None;

  QPulse&                     Pulse;
  QPatientEditorWidget*       PatientEditor;
  QConditionsEditorWidget*    ConditionsEditor;
  QActionsEditorWidget*       ActionsEditor;
  QScenarioEditorWidget*      ScenarioEditor;

  QAnaphylaxisShowcaseWidget* AnaphylaxisShowcaseWidget = nullptr;
  QMultiTraumaShowcaseWidget* MultiTraumaShowcaseWidget = nullptr;
};

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

  m_Controls->PatientEditor = new QPatientEditorWidget(m_Controls->Pulse, this);
  m_Controls->PatientEditor->setTitleBarWidget(new QWidget());
  m_Controls->PatientEditor->setVisible(true);
  m_Controls->PatientTab->layout()->addWidget(m_Controls->PatientEditor);

  m_Controls->ConditionsEditor = new QConditionsEditorWidget(m_Controls->Pulse, this);
  m_Controls->ConditionsEditor->setTitleBarWidget(new QWidget());
  m_Controls->ConditionsEditor->setVisible(true);
  m_Controls->ConditionsTab->layout()->addWidget(m_Controls->ConditionsEditor);

  m_Controls->ActionsEditor = new QActionsEditorWidget(m_Controls->Pulse, this);
  m_Controls->ActionsEditor->setTitleBarWidget(new QWidget());
  m_Controls->ActionsEditor->setVisible(true);
  m_Controls->ActionsTab->layout()->addWidget(m_Controls->ActionsEditor);

  m_Controls->ScenarioEditor = new QScenarioEditorWidget(m_Controls->Pulse, this);
  m_Controls->ScenarioEditor->setTitleBarWidget(new QWidget());
  m_Controls->ScenarioEditor->setVisible(true);
  m_Controls->ScenarioTab->layout()->addWidget(m_Controls->ScenarioEditor);

  QPixmap pic("resource/pulse_logo.png");
  m_Controls->Icon->setPixmap(pic);
  m_Controls->LogoWidget->setVisible(true);

  // Add Scenario Widgets
  m_Controls->AnaphylaxisShowcaseWidget = new QAnaphylaxisShowcaseWidget(m_Controls->Pulse, this);
  m_Controls->AnaphylaxisShowcaseWidget->setTitleBarWidget(new QWidget());
  m_Controls->ShowcaseTab->layout()->addWidget(m_Controls->AnaphylaxisShowcaseWidget);
  m_Controls->AnaphylaxisShowcaseWidget->setVisible(false);

  m_Controls->MultiTraumaShowcaseWidget = new QMultiTraumaShowcaseWidget(m_Controls->Pulse, this);
  m_Controls->MultiTraumaShowcaseWidget->setTitleBarWidget(new QWidget());
  m_Controls->ShowcaseTab->layout()->addWidget(m_Controls->MultiTraumaShowcaseWidget);
  m_Controls->MultiTraumaShowcaseWidget->setVisible(false);

}

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

void QDynamicControlsWidget::Reset()
{
  m_Controls->EngineStateFile= "";
  m_Controls->ScenarioFile = "";
  m_Controls->ScenarioMode = ScenarioInput::None;
  m_Controls->PatientEditor->Reset();
  m_Controls->ConditionsEditor->Reset();
  m_Controls->ActionsEditor->Reset();
  m_Controls->ScenarioEditor->Reset();

  m_Controls->LogoWidget->setVisible(true);
  m_Controls->AnaphylaxisShowcaseWidget->setVisible(false);
  m_Controls->MultiTraumaShowcaseWidget->setVisible(false);
  m_Controls->Pulse.RemoveListener(m_Controls->AnaphylaxisShowcaseWidget);
  m_Controls->Pulse.RemoveListener(m_Controls->MultiTraumaShowcaseWidget);
  m_Controls->DynamicControlsTab->setCurrentWidget(m_Controls->PatientTab);
}

bool QDynamicControlsWidget::ValidPatient()
{
  return m_Controls->PatientEditor->ValidPatient();
}

bool QDynamicControlsWidget::SetupShowcase(QString name)
{
  m_Controls->DynamicControlsTab->setCurrentWidget(m_Controls->ShowcaseTab);
  m_Controls->AnaphylaxisShowcaseWidget->setVisible(false);
  m_Controls->MultiTraumaShowcaseWidget->setVisible(false);
  m_Controls->LogoWidget->setVisible(false);

  if (name == "Anaphylaxis")
  {
#ifdef PARAVIEW  
    m_Controls->GeometryView->RenderSpO2(true);
#endif
    m_Controls->Pulse.GetEngineTracker().Clear();
    m_Controls->AnaphylaxisShowcaseWidget->setVisible(true);
    if (!m_Controls->AnaphylaxisShowcaseWidget->ConfigurePulse(m_Controls->Pulse.GetEngine(), m_Controls->Pulse.GetEngineTracker().GetDataRequestManager()))
      return false;
    m_Controls->Pulse.RegisterListener(m_Controls->AnaphylaxisShowcaseWidget);
  }
  else if (name == "MultiTrauma")
  {
    m_Controls->Pulse.GetEngineTracker().Clear();
    m_Controls->MultiTraumaShowcaseWidget->setVisible(true);
    if (!m_Controls->MultiTraumaShowcaseWidget->ConfigurePulse(m_Controls->Pulse.GetEngine(), m_Controls->Pulse.GetEngineTracker().GetDataRequestManager()))
      return false;
    m_Controls->Pulse.RegisterListener(m_Controls->MultiTraumaShowcaseWidget);
  }
  else
    return false;
  m_Controls->PatientEditor->PatientToControls();
  m_Controls->PatientEditor->EnableInput(false);
  return true;
}

bool QDynamicControlsWidget::SetupScenarioEditor()
{
  if (m_Controls->EngineStateFile.isEmpty())
  {
    m_Controls->ScenarioFile = QFileDialog::getOpenFileName(this,
      "Open Scenario", "./", "Pulse Scenario (*.json)");
    if (m_Controls->ScenarioFile.isEmpty())
      return false;
  }
  m_Controls->ScenarioMode = m_Controls->ScenarioEditor->LoadScenario(m_Controls->ScenarioFile.toStdString());
  if (m_Controls->ScenarioMode == ScenarioInput::None)
    return false;

  if (m_Controls->ScenarioMode == ScenarioInput::Patient)
  {
    m_Controls->PatientEditor->EnableInput(true);
    m_Controls->ConditionsEditor->EnableInput(true);
    m_Controls->ActionsEditor->EnableInput(true);
  }
  else if (m_Controls->ScenarioMode == ScenarioInput::State)
  {
    if (!m_Controls->Pulse.GetEngine().SerializeFromFile(m_Controls->Pulse.GetScenario().GetEngineStateFile(),SerializationFormat::JSON))
    {
      QMessageBox msgBox(this);
      msgBox.setWindowTitle("Error!");
      QString err = "Unable to load engine state : " + m_Controls->EngineStateFile;
      msgBox.setText(err);
      msgBox.exec();
      return false;
    }
    m_Controls->PatientEditor->EnableInput(false);
    m_Controls->ConditionsEditor->EnableInput(false);
    m_Controls->ActionsEditor->EnableInput(true);
  }

  m_Controls->PatientEditor->PatientToControls();
  m_Controls->ConditionsEditor->ConditionsToControls();
  m_Controls->DynamicControlsTab->setCurrentWidget(m_Controls->ScenarioTab);
  m_Controls->AnaphylaxisShowcaseWidget->setVisible(false);
  m_Controls->MultiTraumaShowcaseWidget->setVisible(false);
  return true;
}

bool QDynamicControlsWidget::SetupEngineState()
{
  if (m_Controls->EngineStateFile.isEmpty())
  {
    m_Controls->Pulse.GetEngineTracker().Clear();
    m_Controls->EngineStateFile = QFileDialog::getOpenFileName(this,
      "Open State", "./states", "Engine States (*.json)");
    if (m_Controls->EngineStateFile.isEmpty())
      return false;
  }
  if (!m_Controls->Pulse.GetEngine().SerializeFromFile(m_Controls->EngineStateFile.toStdString(), SerializationFormat::JSON))
  {
    QMessageBox msgBox(this);
    msgBox.setWindowTitle("Error!");
    QString err = "Unable to load engine state : " + m_Controls->EngineStateFile;
    msgBox.setText(err);
    msgBox.exec();
    return false;
  }
  m_Controls->Pulse.EngineToPatientConfiguration();

  m_Controls->DynamicControlsTab->setCurrentWidget(m_Controls->PatientTab);
  m_Controls->AnaphylaxisShowcaseWidget->setVisible(false);
  m_Controls->MultiTraumaShowcaseWidget->setVisible(false);
  m_Controls->PatientEditor->PatientToControls();
  m_Controls->PatientEditor->EnableInput(false);
  m_Controls->ConditionsEditor->ConditionsToControls();
  m_Controls->ConditionsEditor->EnableInput(false);
  m_Controls->ActionsEditor->EnableInput(false);
  return true;
}

bool QDynamicControlsWidget::SetupPatientEditor()
{
  m_Controls->DynamicControlsTab->setCurrentWidget(m_Controls->PatientTab);
  m_Controls->AnaphylaxisShowcaseWidget->setVisible(false);
  m_Controls->MultiTraumaShowcaseWidget->setVisible(false);
  m_Controls->PatientEditor->Reset();
  m_Controls->ConditionsEditor->Reset();
  m_Controls->ActionsEditor->EnableInput(false);
  return true;
}

void QDynamicControlsWidget::PrepStabilization(InputMode m)
{
  m_Controls->AnaphylaxisShowcaseWidget->setVisible(false);
  m_Controls->MultiTraumaShowcaseWidget->setVisible(false);
  m_Controls->PatientEditor->EnableInput(false);
  m_Controls->ConditionsEditor->EnableInput(false);
  m_Controls->ActionsEditor->EnableInput(true);

  switch (m)
  {
  case InputMode::Scenario:
  {
    if (m_Controls->ScenarioMode == ScenarioInput::Patient)
      m_Controls->Pulse.StabilizeEngine(true);
    const SEScenario& s = m_Controls->Pulse.GetScenario();
    for (auto dr : s.GetDataRequestManager().GetDataRequests())
      m_Controls->Pulse.GetEngineTracker().GetDataRequestManager().CopyDataRequest(*dr);
    break;
  }
  case InputMode::State:
    m_Controls->Pulse.StabilizeEngine(false);
    break;
  case InputMode::Patient:
    m_Controls->PatientEditor->ControlsToPatient();
    m_Controls->ConditionsEditor->ControlsToConditions();
    m_Controls->DynamicControlsTab->setCurrentWidget(m_Controls->PatientTab);
    m_Controls->Pulse.StabilizeEngine(true);
    break;
  }
  m_Controls->DynamicControlsTab->setCurrentWidget(m_Controls->PatientTab);
}

void QDynamicControlsWidget::AtSteadyState(PhysiologyEngine& pulse)
{
  m_Controls->PatientEditor->AtSteadyState(pulse);
  m_Controls->ConditionsEditor->AtSteadyState(pulse);
  m_Controls->ActionsEditor->AtSteadyState(pulse);
  m_Controls->ScenarioEditor->AtSteadyState(pulse);

  m_Controls->AnaphylaxisShowcaseWidget->AtSteadyState(pulse);
  m_Controls->MultiTraumaShowcaseWidget->AtSteadyState(pulse);
}
void QDynamicControlsWidget::AtSteadyStateUpdateUI()
{
  m_Controls->PatientEditor->AtSteadyStateUpdateUI();
  m_Controls->ConditionsEditor->AtSteadyStateUpdateUI();
  m_Controls->ActionsEditor->AtSteadyStateUpdateUI();
  m_Controls->ScenarioEditor->AtSteadyStateUpdateUI();

  m_Controls->AnaphylaxisShowcaseWidget->AtSteadyStateUpdateUI();
  m_Controls->MultiTraumaShowcaseWidget->AtSteadyStateUpdateUI();
}

void QDynamicControlsWidget::ProcessPhysiology(PhysiologyEngine& pulse)
{
  m_Controls->PatientEditor->ProcessPhysiology(pulse);
  m_Controls->ConditionsEditor->ProcessPhysiology(pulse);
  m_Controls->ActionsEditor->ProcessPhysiology(pulse);
  m_Controls->ScenarioEditor->ProcessPhysiology(pulse);

  m_Controls->AnaphylaxisShowcaseWidget->ProcessPhysiology(pulse);
  m_Controls->MultiTraumaShowcaseWidget->ProcessPhysiology(pulse);
}
void QDynamicControlsWidget::PhysiologyUpdateUI()
{
  m_Controls->PatientEditor->PhysiologyUpdateUI();
  m_Controls->ConditionsEditor->PhysiologyUpdateUI();
  m_Controls->ActionsEditor->PhysiologyUpdateUI();
  m_Controls->ScenarioEditor->PhysiologyUpdateUI();

  m_Controls->AnaphylaxisShowcaseWidget->PhysiologyUpdateUI();
  m_Controls->MultiTraumaShowcaseWidget->PhysiologyUpdateUI();
}

