#include "BaseImportTab.hpp"
#include <algorithm>
#include "gamebase/GameBase.hpp"

// Foreign events
wxDECLARE_EVENT(REFRESH_MANAGE_TAB, wxCommandEvent);

BaseImportTab::BaseImportTab(wxFrame *parent,  std::shared_ptr<GameBase> db, TabInfos *main_tab):
TabBase_TabImport(parent), main_tab(main_tab), base(db)
{
  // Init counters
  import_ndb=0;
  import_ngames=0;
  import_nselect=0;

  glm=std::make_shared<GameListManager>(game_list);
  RefreshImportLists();
  RefreshPendingImports();

  opened_db_list->SetHint("No other database open");

  this->Bind(wxEVT_BUTTON, &BaseImportTab::OnLoad, this, ID_LOAD_BUTTON);
  this->Bind(wxEVT_BUTTON, &BaseImportTab::OnImportGame, this, ID_IMPORT_GAME_BUTTON);
  this->Bind(wxEVT_BUTTON, &BaseImportTab::OnImportSelection, this, ID_IMPORT_SELECTION);
  this->Bind(wxEVT_BUTTON, &BaseImportTab::OnImportDatabase, this, ID_IMPORT_DB);
}

void BaseImportTab::OnImportDatabase(wxCommandEvent &event){
  if(std::find(databases_to_import.begin(), databases_to_import.end(), selected_base->GetFilePath()) == databases_to_import.end()){  
    databases_to_import.push_back(selected_base->GetFilePath());
    selected_games_to_import.erase(selected_base->GetFilePath());
    glm->Clear();
    RefreshPendingImports();
  }
  else SHOW_DIALOG_INFO("Database already prepared for import");
}

void BaseImportTab::RefreshPendingImports(){
  // Compute metrics
  import_ndb=databases_to_import.size();
  import_ngames=games_to_import.size();
  import_nselect=0;
  for (auto it = selected_games_to_import.begin(); it != selected_games_to_import.end(); it++){
    import_nselect+=it->second.size();
  }
  // Update message
  pending_imports->Clear();
  if(import_ndb+import_ngames+import_nselect>0){
    pending_imports->AppendText(" Pending imports: "+std::to_string(import_ngames+import_nselect)+" games and "+std::to_string(import_ndb)+" databases");
  }else
    pending_imports->SetHint("No pending imports");
  // Don't forget to notify BaseManageTab
  wxCommandEvent e(REFRESH_MANAGE_TAB,GetId());
  ProcessEvent(e);
}

void BaseImportTab::RefreshImportLists(){
  opened_game_list->Clear();
  opened_db_list->Clear();
  for (TabInfos *i : wxGetApp().ListTabInfos()) {
    if (i->type == TabInfos::GAME) {
      wxWindow *win = dynamic_cast<wxWindow *>(i);
      opened_game_list->Append(win->GetLabel(),i);
      opened_game_list->SetSelection(0);
    }
    else if (i->type == TabInfos::BASE && i->id != main_tab->id) {
      wxWindow *win = dynamic_cast<wxWindow *>(i);
      opened_db_list->Append(win->GetLabel(),i);
      opened_db_list->SetSelection(0);
    }
  }
}

void BaseImportTab::OnImportSelection(wxCommandEvent &event){
  if(std::find(databases_to_import.begin(), databases_to_import.end(), selected_base->GetFilePath()) == databases_to_import.end()){
    long selected = -1;
    while ((selected = game_list->GetNextItem(selected, wxLIST_NEXT_ALL,
                                              wxLIST_STATE_SELECTED)) !=
          wxNOT_FOUND) {
      game_list->SetItemState(selected, 0, wxLIST_STATE_SELECTED);  // First deselect
      // Get game id
      long game_id=glm->GetItemGameId(selected);
      // Select the right db hashmap
      auto &game_list=selected_games_to_import[selected_base->GetFilePath()];
      // If game not in this hasmap add it
      if(game_list.find(game_id) == game_list.end()){
        game_list[game_id]=selected_base->GetGame(glm->GetItemGameId(selected));
        glm->MarkItemAsImported(selected);
      }
    }
  }
  else {
    SHOW_DIALOG_INFO("Database already prepared for import");
  }
  RefreshPendingImports();
}

void BaseImportTab::OnImportGame(wxCommandEvent &event){
  TabInfos *game_tab=(TabInfos*)opened_game_list->GetClientData(opened_game_list->GetSelection());
  std::shared_ptr<Game> g=game_tab->GetGame();
  if(std::find(games_to_import.begin(), games_to_import.end(), g) == games_to_import.end()){    wxLogDebug("Import!");
    games_to_import.push_back(g);
    RefreshPendingImports();
  }
  else SHOW_DIALOG_INFO("Game already prepared for import");
}

void BaseImportTab::OnLoad(wxCommandEvent &event){
  TabInfos *game_tab=(TabInfos*)opened_db_list->GetClientData(opened_db_list->GetSelection());

  // Load all games (for now :)
  glm->Clear();
  selected_base=OpenDatabase(game_tab->GetBase()->GetFilePath());
  SHOW_DIALOG_BUSY("Loading database...");
  auto &game_list=selected_games_to_import[selected_base->GetFilePath()];
  bool baseImported=std::count(databases_to_import.begin(),databases_to_import.end(),selected_base->GetFilePath())>0;
  while (selected_base->NextGame()) {
    long id=glm->AddGame(
      selected_base->GetTag("White"),
      selected_base->GetTag("Black"),
      selected_base->GetTag("Event"),
      selected_base->GetTag("Round"),
      selected_base->GetTag("Result"),
      selected_base->GetTag("ECO"));
    if(game_list.find(id)!=game_list.end() || baseImported){
      glm->MarkItemAsImported(id);
    }
  }
}

void BaseImportTab::Reset(std::shared_ptr<GameBase> base){
  this->base=base;
  this->games_to_import.clear();
  this->databases_to_import.clear();
  this->selected_games_to_import.clear();
  glm->Clear();
  RefreshPendingImports();
}

std::vector<std::shared_ptr<Game>> BaseImportTab::GetGameToImport(){
  std::vector<std::shared_ptr<Game>> to_import;
  for(auto g: games_to_import){to_import.push_back(g);}
  for (auto it = selected_games_to_import.begin(); it != selected_games_to_import.end(); it++){
    for (auto it2 = it->second.begin(); it2 != it->second.end(); it2++){
       to_import.push_back(it2->second);
    }
  }
  return to_import;
}
