#include "GameTabRightPanel.hpp"

wxDEFINE_EVENT(GOTO_MOVE_EVENT, wxCommandEvent);
wxDEFINE_EVENT(DELETE_MOVE_EVENT, wxCommandEvent);
wxDEFINE_EVENT(PROMOTE_MOVE_EVENT, wxCommandEvent);
wxDEFINE_EVENT(SET_AS_MAINLINE_EVENT, wxCommandEvent);
wxDEFINE_EVENT(PREVIOUS_MOVE_EVENT, wxCommandEvent);
wxDEFINE_EVENT(NEXT_MOVE_EVENT, 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");

  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->nag=p->GetNagFromStr(((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();
}

void GameTabRightPanel::OnLiveAnalysis(wxCommandEvent &event) {
  if (live_engine == nullptr) {
    int selection = engine_list->GetSelection();
    if (selection != wxNOT_FOUND) {
      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);
    }
  }
}

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) {
  live_engine = nullptr;
  e.Skip();
}

void GameTabRightPanel::OnCommentChange(wxCommandEvent &event) {
  wxLogDebug("GameTabRightPanel: comment input change");
  HalfMove *m = game->GetCurrentMove();
  if (m != nullptr) {
    m->comment=event.GetString().ToStdString();
  }
  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->comment); // 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());
  }
}

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);
}

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::string 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 "";
}
