#include "EngineTab.hpp"

EngineTab::EngineTab(wxWindow *parent, uciadapter::UCI *engine,
                     std::string engine_path)
    : TabEngine(parent), TabInfos(TabInfos::ENGINE),
      enginePath(engine_path), engine(engine) {
  
  // Init engine name and location
  SetLabel("New Engine");
  engine_location->SetValue(engine_path);

  // Fetch engine id
  CONFIG_OPEN(conf);
  conf->SetPath("engines/");
  engine_id=conf->GetNumberOfGroups();
  CONFIG_CLOSE(conf);
  confGroup = "engines/" + std::to_string(engine_id);

  // Init data
  InitConfiguration();
  LoadConfiguration();
  RefreshItemList();

  Bind(wxEVT_BUTTON, &EngineTab::OnSave, this, ENGINE_SAVE_CONF_BUTTON);
  Bind(wxEVT_BUTTON, &EngineTab::OnDelete, this, ENGINE_DELETE_CONF_BUTTON);
  Bind(wxEVT_PG_CHANGED, [p=this](wxPropertyGridEvent& event){ UNUSED(event); p->is_dirty=true;});
}

EngineTab::EngineTab(wxWindow *parent, std::uint32_t id)
    : TabEngine(parent), TabInfos(TabInfos::ENGINE), engine(nullptr) {
  // Init engine group
  std::string id_str=std::to_string(id);
  confGroup = "engines/" + std::to_string(id);

  // Fetch name and path
  CONFIG_OPEN(conf);
  wxString name=conf->Read(confGroup + "/name");
  SetLabel(name);
  engine_name->SetValue(name);
  engine_location->SetValue(conf->Read(confGroup + "/path"));
  engine_id=id;
  CONFIG_CLOSE(conf);

  // Load existing configuration
  LoadConfiguration();

  Bind(wxEVT_BUTTON, &EngineTab::OnSave, this, ENGINE_SAVE_CONF_BUTTON);
  Bind(wxEVT_BUTTON, &EngineTab::OnDelete, this, ENGINE_DELETE_CONF_BUTTON);
  Bind(wxEVT_PG_CHANGED, [p=this](wxPropertyGridEvent& event){ UNUSED(event); p->is_dirty=true;});
}

EngineTab::~EngineTab() {
  if (engine != nullptr) {
    wxLogDebug("EngineTab destructor: destroying engine!");
    engine->quit();
    delete engine;
  }
}

void EngineTab::OnDelete(wxCommandEvent &event) {
  UNUSED(event);
  CONFIG_OPEN(conf);
  conf->DeleteGroup(confGroup);
  CONFIG_CLOSE(conf);
  RefreshItemList();

  wxCommandEvent closeTabEvent(CLOSE_TAB_EVENT, GetId());
  closeTabEvent.SetEventObject(this);
  ProcessEvent(closeTabEvent);
}

void EngineTab::RefreshItemList() {
  wxCommandEvent refreshEngineList(REFRESH_ENGINE_LIST, GetId());
  refreshEngineList.SetEventObject(this);
  ProcessEvent(refreshEngineList);
}

void EngineTab::LoadConfiguration() {
  // Build wxPropertyGrid according to engine configuration
  CONFIG_OPEN(conf2);
  long index;
  std::string optsPath = confGroup + "/options";
  conf2->SetPath(optsPath);
  wxString opt_name;
  if (conf2->GetFirstGroup(opt_name, index)) {
    do {
      wxString optPath = opt_name + "/";
      wxString type = conf2->Read(optPath + "type");
      wxString default_value_wxString = conf2->Read(optPath + "value");
      std::string default_value = default_value_wxString.ToStdString();
      if (type == "check") {
        engine_parameters->Append(
            new wxBoolProperty(opt_name, wxPG_LABEL, default_value == "true"));
      } else if (type == "spin") {
        engine_parameters->Append(
            new wxIntProperty(opt_name, wxPG_LABEL, std::stoi(default_value)));
      } else if (type == "string" || type == "button") {
        engine_parameters->Append(
            new wxStringProperty(opt_name, wxPG_LABEL, default_value));
      }
    } while (conf2->GetNextGroup(opt_name, index));
  }
  CONFIG_CLOSE(conf2);
}

void EngineTab::OnSave(wxCommandEvent &event) {
  UNUSED(event);
  CONFIG_OPEN(conf2);
  // Update engine name:
  conf2->Write(confGroup + "/name", engine_name->GetValue());
  
  // Update engine configuration:
  long index;
  std::string optsPath = confGroup + "/options";
  conf2->SetPath(optsPath);
  wxString opt_name;
  if (conf2->GetFirstGroup(opt_name, index)) {
    do {
      wxString optPath = opt_name + "/";
      wxString type = conf2->Read(optPath + "type");
      wxPGProperty *property = engine_parameters->GetProperty(opt_name);
      wxVariant value = property->GetValue();
      if (value.IsType(wxPG_VARIANT_TYPE_BOOL)) {
        conf2->Write(optPath + "/value", value.GetBool());
      } else if (value.IsType(wxPG_VARIANT_TYPE_LONG)) {
        conf2->Write(optPath + "/value", value.GetLong());
      } else if (value.IsType(wxPG_VARIANT_TYPE_STRING)) {
        conf2->Write(optPath + "/value", value.GetString());
      }
    } while (conf2->GetNextGroup(opt_name, index));
  }
  CONFIG_CLOSE(conf2);
  // Notify all other tabs about this new configuration
  RefreshItemList();
}

void EngineTab::InitConfiguration() {
  wxLogDebug("Called!");
  CONFIG_OPEN(conf);
  conf->Write(confGroup + "/path", wxString(enginePath));
  conf->Write(confGroup + "/name", wxString(engine->GetName()));
  conf->Write(confGroup + "/authors", wxString(engine->GetAuthor()));
  std::vector<uciadapter::Option> opts = engine->GetOptions();
  for (uciadapter::Option &opt : opts) {
    std::string optPath = confGroup + "/options/" + opt.name;
    conf->Write(wxString(optPath + "/type"), wxString(opt.type));
    if (opt.type == "check") {
      conf->Write(wxString(optPath + "/value"), opt.default_value == "true");
    } else if (opt.type == "spin") {
      conf->Write(wxString(optPath + "/value"), std::stoi(opt.default_value));
      conf->Write(wxString(optPath + "/min"), std::stoi(opt.min));
      conf->Write(wxString(optPath + "/max"), std::stoi(opt.max));
    } else if (opt.type == "string") {
      conf->Write(wxString(optPath + "/value"), wxString(opt.default_value));
    } else if (opt.type == "button") {
      conf->Write(wxString(optPath + "/name"), wxString(opt.default_value));
    }
  }
  CONFIG_CLOSE(conf);
}