#include "GameTabRightPanel.hpp"

wxDEFINE_EVENT(LIVE_ANALYSIS_STATUS, wxCommandEvent);

GameTabRightPanel::GameTabRightPanel(wxFrame *parent, std::shared_ptr<Game> game)
    : TabGameRightPanel(parent), game(game), selected_item(-1),
      live_engine(nullptr) {
  editor_canvas = new EditorCanvas((wxFrame *)editor_page,game);
  editor_canvas_sizer->Add(editor_canvas, 1, wxEXPAND);
  tags_list->InsertColumn(0, L"Name", wxLIST_FORMAT_LEFT, 200);
  tags_list->InsertColumn(1, L"Value", wxLIST_FORMAT_LEFT, 500);
  tagTextCtrl->SetHint("Tag");
  valueTextCtrl->SetHint("Value");
  opening_label->SetHint("Current opening");
  RefreshTagsList();

  // Bind events
  this->Bind(wxEVT_TEXT, &GameTabRightPanel::OnCommentChange, this,
             COMMENT_INPUT_BOX);
  this->Bind(wxEVT_LIST_ITEM_SELECTED, &GameTabRightPanel::OnTagSelected, this,
             wxID_ANY);
  this->Bind(wxEVT_LIST_ITEM_DESELECTED, &GameTabRightPanel::OnTagDeselected,
             this, wxID_ANY);
  this->Bind(wxEVT_BUTTON, &GameTabRightPanel::OnApply, this, UPDATE_BTN);
  this->Bind(wxEVT_BUTTON, &GameTabRightPanel::OnDelete, this, DELETE_BTN);
  this->Bind(wxEVT_BUTTON, &GameTabRightPanel::OnLiveAnalysis, this,
             LIVE_ANALYSIS_GAME_BUTTON);
  nag_panel->Bind(wxEVT_BUTTON, [p=this](wxCommandEvent &e){
    HalfMove *m = p->game->GetCurrentMove();
    if (m != nullptr) {
      m->SetNAG(p->editor_canvas->GetNAGId(((wxButton*)e.GetEventObject())->GetLabel().ToStdString()));
      p->editor_canvas->Refresh();
    }
  });

  // Propagate key events of the game editor
  editor_page->Bind(wxEVT_KEY_DOWN, [p=this](wxKeyEvent &e){e.ResumePropagation(1);e.Skip();});
  editor_page->Bind(wxEVT_KEY_UP, [p=this](wxKeyEvent &e){e.ResumePropagation(1);e.Skip();});
  notebook->Bind(wxEVT_KEY_DOWN, [p=this](wxKeyEvent &e){e.ResumePropagation(1);e.Skip();});
  notebook->Bind(wxEVT_KEY_UP, [p=this](wxKeyEvent &e){e.ResumePropagation(1);e.Skip();});
  Bind(wxEVT_KEY_DOWN, [p=this](wxKeyEvent &e){e.ResumePropagation(1);e.Skip();});
  Bind(wxEVT_KEY_UP, [p=this](wxKeyEvent &e){e.ResumePropagation(1);e.Skip();});

  ApplyPreferences();
  analyze_game_button->Disable();
}

void GameTabRightPanel::OnLiveAnalysis(wxCommandEvent &event) {
  if (live_engine == nullptr) {
    int selection = engine_list->GetSelection();
    if (selection != wxNOT_FOUND) {
      // Notify about the state of the LiveEngine
      wxCommandEvent notifyEvent(LIVE_ANALYSIS_STATUS,GetId());
      notifyEvent.SetEventObject(this);
      notifyEvent.SetInt(1);
      ProcessEvent(notifyEvent);

      live_engine = new LiveEngineDialog(
          this, engine_list->GetString(selection).ToStdString());
      live_engine->SetFEN(game->GetFen());
      live_engine->Show();
      live_engine->Bind(wxEVT_CLOSE_WINDOW,
                        &GameTabRightPanel::OnLiveEngineClose, this,
                        ID_LIVE_ENGINE_DIALOG);
      live_engine->Bind(SHOW_ENGINE_EVALUATION, [p=this](wxCommandEvent &e){
        wxCommandEvent notifyEvent(SHOW_ENGINE_EVALUATION,p->GetId());
        notifyEvent.SetEventObject(p);
        notifyEvent.SetClientData(e.GetClientData());
        p->ProcessEvent(notifyEvent);
      });
    }
  }
}

void GameTabRightPanel::OnTagSelected(wxListEvent &event) {
  wxListItem item = event.GetItem();
  std::string key = item.GetText().ToStdString();
  tagTextCtrl->ChangeValue(key);
  item.SetColumn(1);
  tags_list->GetItem(item);
  valueTextCtrl->ChangeValue(item.GetText().ToStdString());
  selected_item = item.GetId();
  delete_button->Enable(true);
}

void GameTabRightPanel::OnTagDeselected(wxListEvent &event) {
  selected_item = -1;
  delete_button->Enable(false);
}

void GameTabRightPanel::OnLiveEngineClose(wxCloseEvent &e) {
  // Notify about the state of the LiveEngine
  wxCommandEvent notifyEvent(LIVE_ANALYSIS_STATUS,GetId());
  notifyEvent.SetEventObject(this);
  notifyEvent.SetInt(0);
  ProcessEvent(notifyEvent);
  // Refresh pointer
  live_engine = nullptr;
  e.Skip();
}

void GameTabRightPanel::OnCommentChange(wxCommandEvent &event) {
  wxLogDebug("GameTabRightPanel: comment input change");
  HalfMove *m = game->GetCurrentMove();
  if (m != nullptr) {
    m->SetComment(event.GetString().Trim().ToStdString());
    // Remove newlines:
    for(char &c:m->GetComment()){
      if(c=='\n')
        c=' ';
    }
  }
  editor_canvas->Refresh();
}

void GameTabRightPanel::OnApply(wxCommandEvent &event) {
  std::string key = tagTextCtrl->GetValue().ToStdString();
  if (key == "FEN") {
    SHOW_DIALOG_ERROR("Editing the FEN tag is forbidden");
    return;
  }
  if (key.size() > 0) {
    std::string value = valueTextCtrl->GetValue().ToStdString();
    game->SetTag(key, value);
    RefreshTagsList();
    wxCommandEvent event(GAME_CHANGE, GetId());
    event.SetEventObject(this);
    ProcessEvent(event);
  }
}

void GameTabRightPanel::OnDelete(wxCommandEvent &event) {
  if (selected_item >= 0) {
    wxListItem item;
    item.SetColumn(0);
    item.SetId(selected_item);
    tags_list->GetItem(item);
    std::string key = item.GetText().ToStdString();
    if (key != "FEN") {
      game->DeleteTag(key);
      selected_item = -1;
      RefreshTagsList();
    } else {
      SHOW_DIALOG_ERROR("Deleting the FEN tag is forbidden.");
    }
  }
}

void GameTabRightPanel::Notify() {
  HalfMove *m = game->GetCurrentMove();
  if (m != nullptr) {
    comment_input->ChangeValue(
        m->GetComment()); // ChangeValue do not raise events
  }
  editor_canvas->SetMoves(game->GetMoves(), m);
  // Put it here for now:
  if (live_engine != nullptr) {
    live_engine->SetFEN(game->GetFen());
  }
  // Update opening name
  std::string opening,eco;
  game->GetOpening(opening,eco);
  if(eco.size()>0)
    opening_label->SetValue(eco+": "+opening);
}

void GameTabRightPanel::ApplyPreferences() {
  engine_list->Clear();
  CONFIG_OPEN(conf);
  conf->SetPath("engines/");
  wxString engine_name;
  long index;
  if (conf->GetFirstGroup(engine_name, index)) {
    do {
      engine_list->Append(engine_name);
    } while (conf->GetNextGroup(engine_name, index));
  }
  CONFIG_CLOSE(conf);
  editor_canvas->ApplyPreferences();
}

void GameTabRightPanel::RefreshTagsList() {
  tags_list->DeleteAllItems();
  for (std::string s : game->ListTags()) {
    long index = tags_list->InsertItem(0, s);
    tags_list->SetItem(index, 1, game->GetTag(s));
    if (s == "FEN") {
      tags_list->SetItemBackgroundColour(index, wxColour(200, 200, 200));
    }
  }
}

std::uint8_t GameTabRightPanel::GetNagFromStr(std::string str){
  // TODO: Bind more NAG!
  if(str=="!")
    return 1;
  else if(str=="?")
    return 2;
  else if(str=="!!")
    return 3;
  else if(str=="??")
    return 4;
  else if(str=="!?")
    return 5;
  else if(str=="?!")
    return 6;
  else if(str=="=")
    return 10;
  else if(str=="∞")
    return 13;
  else if(str=="⩲")
    return 14;
  else if(str=="⩱")
    return 15;
  else if(str=="±")
    return 16;
  else if(str=="∓")
    return 17;
  else if(str=="+-")
    return 18;
  else if(str=="-+")
    return 19;
  else if(str=="⨀")
    return 22;
  else if(str=="○")
    return 26;
  else if(str=="⟳")
    return 32;
  else if(str=="↑")
    return 36;
  else if(str=="→")
    return 40;
  else if(str=="⯹")
    return 44;
  else if(str=="⨁")
    return 138;
  return 0;
}