/* Distributed under the Apache License, Version 2.0.
See accompanying NOTICE file for details.*/
#include "DataRequestsWidget.h"
#include "ui_DataRequests.h"

#include <QLayout>

#include "QPulsePlot.h"

#include "cdm/CommonDataModel.h"
#include "PulsePhysiologyEngine.h"
#include "cdm/engine/SEEngineTracker.h"
#include "cdm/engine/SEDataRequest.h"
#include "cdm/engine/SEDataRequestManager.h"
#include "cdm/system/equipment/electrocardiogram/SEElectroCardioGramWaveformInterpolator.h"
#include "cdm/utils/FileUtils.h"

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



class QDataRequestsWidget::Controls : public Ui::DataRequestsWidget
{
public:
  Controls(QTextEdit& log) : LogBox(log) {}
  QTextEdit&                         LogBox;
  size_t                             CurrentPlot=-1;
  std::vector<QPulsePlot*>           Plots;
  std::vector<double>                Values; // New value for the plot
  std::vector<std::string>           Titles;
};

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

  connect(m_Controls->DataRequested, SIGNAL(currentIndexChanged(int)), SLOT(ChangePlot(int)));
}

QDataRequestsWidget::~QDataRequestsWidget()
{
  Reset();
  delete m_Controls;
}

void QDataRequestsWidget::Reset()
{
  m_Controls->CurrentPlot = -1;
  DELETE_VECTOR(m_Controls->Plots);
  m_Controls->DataRequested->clear();
}

void QDataRequestsWidget::ChangePlot(int idx)
{
  if (m_Controls->CurrentPlot != -1)
  {
    m_Controls->Plots[m_Controls->CurrentPlot]->GetView().setVisible(false);
    m_Controls->CurrentPlot = idx;
  }
}

void QDataRequestsWidget::BuildGraphs(PhysiologyEngine& pulse)
{
  std::stringstream ss;
  SEDataRequestManager& drMgr = pulse.GetEngineTracker()->GetDataRequestManager();
  std::string title;
  std::string unit;
  m_Controls->Titles.clear();
  if (drMgr.GetDataRequests().empty())
  {
    // Let's load up some default requests
    drMgr.CreatePhysiologyDataRequest("TidalVolume", VolumeUnit::mL);
    drMgr.CreatePhysiologyDataRequest("CardiacOutput", VolumePerTimeUnit::L_Per_min);
    drMgr.CreateGasCompartmentDataRequest(pulse::PulmonaryCompartment::LeftLung, "Volume", VolumeUnit::mL);
    drMgr.CreateGasCompartmentDataRequest(pulse::PulmonaryCompartment::RightLung, "Volume", VolumeUnit::mL);
  }
  for (SEDataRequest* dr : drMgr.GetDataRequests())
  {
    if (dr->HasUnit())
      unit = " (" + dr->GetUnit()->GetString() + ")";
    else
      unit = "";
    switch (dr->GetCategory())
    {
    case eDataRequest_Category::Patient:
      title = "Patient " + dr->GetPropertyName() + unit;
      break;
    case eDataRequest_Category::Physiology:
      title = dr->GetPropertyName() + unit;
      break;
    case eDataRequest_Category::Environment:
      title = dr->GetPropertyName() + unit;
      break;
    case eDataRequest_Category::GasCompartment:
    case eDataRequest_Category::LiquidCompartment:
      if (dr->HasSubstanceName())
        title = dr->GetCompartmentName() + " " + dr->GetSubstanceName() + " " + dr->GetPropertyName() + unit;
      else
        title = dr->GetCompartmentName() + " " + dr->GetPropertyName() + unit;
      break;
    case eDataRequest_Category::ThermalCompartment:
      title = dr->GetCompartmentName() + " " + dr->GetPropertyName() + unit;
      break;
    case eDataRequest_Category::TissueCompartment:
      title = dr->GetCompartmentName() + " " + dr->GetPropertyName() + unit;
      break;
    case eDataRequest_Category::Substance:
      if (dr->HasCompartmentName())
        title = dr->GetSubstanceName() + " " + dr->GetCompartmentName() + " " + dr->GetPropertyName() + unit;
      else
        title = dr->GetSubstanceName() + " " + dr->GetPropertyName() + unit;
      break;
    case eDataRequest_Category::AnesthesiaMachine:
      title = dr->GetPropertyName() + unit;
      break;
    case eDataRequest_Category::ECG:
      title = dr->GetPropertyName() + unit;
      break;
    case eDataRequest_Category::Inhaler:
      title = dr->GetPropertyName() + unit;
      break;
    }
    if (!pulse.GetEngineTracker()->TrackRequest(*dr))
    {// Could not hook this up, get rid of it
      ss << "Unable to find data for " << title;
      m_Controls->LogBox.append(ss.str().c_str());
      continue;
    }
    m_Controls->Titles.push_back(title);
  }
}


void QDataRequestsWidget::AtSteadyState(PhysiologyEngine& pulse)
{
  BuildGraphs(pulse);
}
void QDataRequestsWidget::AtSteadyStateUpdateUI()
{
  Reset();
  for (std::string title : m_Controls->Titles)
  {
    QPulsePlot *p = new QPulsePlot(1000);
    p->GetChart().setTitle(title.c_str());
    m_Controls->DataGraphWidget->layout()->addWidget(&p->GetView());
    m_Controls->Plots.push_back(p);
    m_Controls->DataRequested->addItem(QString(title.c_str()));
  }
  m_Controls->CurrentPlot = 0;
  m_Controls->DataRequested->setCurrentIndex(m_Controls->CurrentPlot);
  m_Controls->Plots[0]->GetView().setVisible(true);
}

void QDataRequestsWidget::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
  size_t i = 0;
  QPulsePlot* plot;
  pulse.GetEngineTracker()->PullData();
  double  v;
  for (SEDataRequest* dr : pulse.GetEngineTracker()->GetDataRequestManager().GetDataRequests())
  {
    plot = m_Controls->Plots[i++];
    if (dr->HasUnit())
     v=pulse.GetEngineTracker()->GetScalar(*dr)->GetValue(*dr->GetUnit());
    else
     v=pulse.GetEngineTracker()->GetScalar(*dr)->GetValue();
    plot->Append(pulse.GetSimulationTime(TimeUnit::s),v);
  }
}
void QDataRequestsWidget::PhysiologyUpdateUI()
{// This is called from a slot, you can update UI here
  if(!m_Controls->Plots.empty())
   m_Controls->Plots[m_Controls->CurrentPlot]->UpdateUI();
}


