/* Distributed under the Apache License, Version 2.0.
See accompanying NOTICE file for details.*/
#include "ScenarioEditorWidget.h"
#include "ui_ScenarioEditor.h"
#include <QMessageBox>
#include <QLabel>

#include "CollapsableWidget.h"
#include "conditions/ChronicAnemiaWidget.h"

#include "cdm/CommonDataModel.h"
#include "cdm/engine/SEAction.h"
#include "cdm/engine/SEAdvanceTime.h"
#include "cdm/engine/SEPatientConfiguration.h"
#include "cdm/patient/SEPatient.h"
#include "cdm/properties/SEScalarTime.h"

class QScenarioEditorWidget::Controls : public Ui::ScenarioEditorWidget
{
public:
  Controls(QPulse& qp) : Pulse(qp) {}
  QPulse&                Pulse;
  ;
};

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

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

void QScenarioEditorWidget::Reset()
{
  QLayoutItem *item;
  while ((item = m_Controls->ActionWidgets->layout()->takeAt(0)) != 0)
  {
    delete item->widget();
    delete item;
  }
  delete m_Controls->ActionWidgets->layout();
  m_Controls->ActionWidgets->setLayout(new QVBoxLayout());
}

ScenarioInput QScenarioEditorWidget::LoadScenario(std::string const& scenario_file)
{
  ScenarioInput ret = ScenarioInput::None;
  PulseScenario& Scenario = m_Controls->Pulse.GetScenario();

  if (!Scenario.SerializeFromFile(scenario_file, SerializationFormat::JSON))
  {
    QMessageBox msgBox(this);
    msgBox.setWindowTitle("Error!");
    msgBox.setText("Unable to load scenario file : " + QString::fromStdString(scenario_file));
    msgBox.exec();
    return ret;
  }
  if (Scenario.HasEngineStateFile())
    return ScenarioInput::State;
  else if (Scenario.HasPatientConfiguration())
  {
    if (Scenario.GetPatientConfiguration().HasPatient())
      ret = ScenarioInput::Patient;
    else if (Scenario.GetPatientConfiguration().HasPatientFile())
    {
      std::string patient_file = Scenario.GetPatientConfiguration().GetPatientFile();
      if (patient_file.find("/") == std::string::npos)
        patient_file = "./patients/" + patient_file;

      if (!Scenario.GetPatientConfiguration().HasConditions())
      {
        // Let's check to see if there is an initial state associated with this patient file
        std::string state_file = patient_file;
        size_t start_pos = state_file.find("patients");
        if (start_pos != std::string::npos)
        {
          state_file.replace(start_pos, 8, "states");
          start_pos = state_file.find(".json");
          state_file.replace(start_pos, 7, "@0s.json");
          // Does this file exist
          if (FILE *file = fopen(state_file.c_str(), "r"))
          {
            fclose(file);
            Scenario.SetEngineStateFile(state_file);
            m_Controls->Pulse.GetLogBox().append("Replacing Patient with associated initial state");
            ret = ScenarioInput::State;
          }
        }
      }
      if (ret == ScenarioInput::None)
      {// Still not set, not using a state
        if (Scenario.GetPatientConfiguration().GetPatient().SerializeFromFile(patient_file, SerializationFormat::JSON))
          ret = ScenarioInput::Patient;
        else
        {
          QMessageBox msgBox(this);
          msgBox.setWindowTitle("Error!");
          msgBox.setText("Unable to load patient file : " + QString::fromStdString(patient_file));
          msgBox.exec();
          return ScenarioInput::None;
        }
      }
    }
    else
    {
      QMessageBox msgBox(this);
      msgBox.setWindowTitle("Error!");
      msgBox.setText("Scenario patient configuration is invalid");
      msgBox.exec();
      return ScenarioInput::None;
    }
  }
  else
  {
    QMessageBox msgBox(this);
    msgBox.setWindowTitle("Error!");
    msgBox.setText("Scenario does not contain patient or state information");
    msgBox.exec();
    return ScenarioInput::None;
  }
  DisplayActions(Scenario.GetActions());
  return ret;
}

void QScenarioEditorWidget::DisplayActions(const std::vector<const SEAction*>& actions)
{
  QString aStr;
  std::stringstream timeStr;
  double simTime = 0;
  std::ostringstream aText;
  const SEAdvanceTime* adv = nullptr;
  for (const SEAction* action : actions)
  {
    aText.str("");
    action->ToString(aText);
    aStr = QString::fromStdString(aText.str());
    adv = dynamic_cast<const SEAdvanceTime*>(action);
    if (adv != nullptr)
    {
      simTime += adv->GetTime(TimeUnit::s);
      timeStr << "\n To simulation time " << simTime << "(s)";
      aStr.append(timeStr.str().c_str());
      timeStr.str("");
    }
    QStringList pieces = aStr.split("\n");
    QCollapsableWidget* a = new QCollapsableWidget(pieces[0], 120, this);
    a->setVisible(true);
    QWidget* aWidget = new QWidget(this); 
    QVBoxLayout* layout = new QVBoxLayout();
    layout->setSpacing(6);
    layout->setContentsMargins(-1, 6, -1, 6);
    aWidget->setLayout(layout);
    for (int i = 1; i < pieces.length(); i++)
      layout->addWidget(new QLabel(pieces[i]));
    a->layout()->addWidget(aWidget);
    a->setContentLayout(*aWidget->layout());
    a->expand(true);
    m_Controls->ActionWidgets->layout()->addWidget(a);
  }
  QSpacerItem *spacer = new QSpacerItem(40, 1000, QSizePolicy::Expanding, QSizePolicy::Expanding);
  m_Controls->ActionWidgets->layout()->addItem(spacer);
}