#include "MainWindow.hpp"
#include "ChessArbiter.hpp"
#include "pgnp.hpp"
#include "preferences/preferences.hpp"

wxDEFINE_EVENT(REFRESH_TAB_TITLE, wxCommandEvent);
wxDEFINE_EVENT(NEW_GAME_EVENT, wxCommandEvent);

/// ---------- MainWindow ----------

MainWindow::MainWindow()
    : wxFrame(NULL, wxID_ANY, "OChess: The Open Chess software",
              wxDefaultPosition, wxSize(1500, 1000)),
      prefsEditor(NULL) {
  CreateStatusBar();
  SetStatusText("OChess");

  /// File menu
  wxMenu *menuFile = new wxMenu;
  menuFile->Append(1, "Open", "Open file");
  Bind(wxEVT_MENU, &MainWindow::OnOpen, this, 1);
  menuFile->Append(4, "Settings", "Configure OChess");
  Bind(wxEVT_MENU, &MainWindow::OnSettings, this, 4);
  menuFile->AppendSeparator();
  menuFile->Append(wxID_EXIT);
  Bind(wxEVT_MENU, &MainWindow::OnExit, this, wxID_EXIT);

  menuGame = new wxMenu;
  menuGame->Append(2, "New", "Create new game");
  Bind(wxEVT_MENU, &MainWindow::OnNewGame, this, 2);
  menuGame->Append(3, "New from FEN", "Create new game using FEN");
  Bind(wxEVT_MENU, &MainWindow::OnNewGame, this, 3);
  menuGame->AppendSeparator();
  menuGame->Append(10, "Save", "Save current game");
  menuGame->Append(11, "Save As", "Save current game as");

  /// Menu bar
  menuBar = new wxMenuBar;
  menuBar->Append(menuFile, "&File");
  menuBar->Append(menuGame, "&Game");
  SetMenuBar(menuBar);

  // Create the wxNotebook widget
  notebook = new wxAuiNotebook(this, wxID_ANY);
  NewGame(new Game());

  // Test base tab
  BaseTab *bt = new BaseTab((wxFrame *)notebook);
  bt->SetLabel("New Base");
  notebook->AddPage(bt, bt->GetLabel());
  notebook->SetSelection(notebook->GetPageIndex(bt));

  Bind(wxEVT_AUINOTEBOOK_PAGE_CHANGED, &MainWindow::OnPageChange, this,
       wxID_ANY);
  Bind(REFRESH_TAB_TITLE, &MainWindow::OnRefreshTabTitle, this, wxID_ANY);
  Bind(NEW_GAME_EVENT, &MainWindow::OnNewGame2, this, wxID_ANY);
  Bind(wxEVT_CLOSE_WINDOW, &MainWindow::OnClose, this);
}

class AdvancePage : public wxPreferencesPage {
public:
  virtual wxString GetName() const { return "Topics"; }
  virtual wxBitmap GetLargeIcon() {
    return wxArtProvider::GetBitmap(wxART_HELP, wxART_TOOLBAR);
  }
  virtual wxWindow *CreateWindow(wxWindow *parent) {
    wxPanel *p =
        new wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(800, 800));
    wxBoxSizer *s = new wxBoxSizer(wxVERTICAL);
    s->Add(new wxButton(p, COPY_FEN_BTN, L"Copy FEN"), 1, wxEXPAND);
    p->SetSizer(s);
    return p;
  }
};

void MainWindow::OnSettings(wxCommandEvent &event) {
  if (prefsEditor != NULL) {
    delete prefsEditor;
  }
  prefsEditor = new wxPreferencesEditor("Preferences");
  prefsEditor->AddPage(new BoardPrefs());
  prefsEditor->AddPage(new EditorPrefs());
  prefsEditor->Show(this);
}

void MainWindow::ApplyPreferences() {
  for (int i = 0; i < notebook->GetPageCount(); i++) {
    TabInfos *infos = dynamic_cast<TabInfos *>(notebook->GetPage(i));
    infos->ApplyPreferences();
  }
}

void MainWindow::OnExit(wxCommandEvent &event) { Close(true); }

void MainWindow::OnClose(wxCloseEvent &e) {
  if (prefsEditor != NULL) {
    prefsEditor->Dismiss();
  }
  e.Skip();
}

void MainWindow::OnOpen(wxCommandEvent &event) {
  wxFileDialog openFileDialog(this, _("Open file"), "", "",
                              "PGN files (*.pgn)|*.pgn",
                              wxFD_OPEN | wxFD_FILE_MUST_EXIST);
  if (openFileDialog.ShowModal() != wxID_CANCEL) {
    std::string path = openFileDialog.GetPath().ToStdString();
    pgnp::PGN pgn;
    try {
      pgn.FromFile(path);
      pgn.ParseNextGame();
      pgnp::HalfMove *pgnp_moves = new pgnp::HalfMove();
      pgn.GetMoves(pgnp_moves);
      std::string fen =
          "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
      if (pgn.HasTag("FEN")) {
        fen = pgn.GetTagValue("FEN");
      }
      HalfMove *m = new HalfMove(pgnp_moves, fen);
      Game *g = new Game(m, fen);
      for (std::string &s : pgn.GetTagList()) {
        g->SetTag(s, pgn.GetTagValue(s));
      }
      NewGame(g);
    } catch (std::exception &e) {
      SHOW_DIALOG_ERROR("Invalid PGN file: " + std::string(e.what()));
    }
  }
}

void MainWindow::OnNewGame(wxCommandEvent &event) {
  if (event.GetId() == 3) {
    wxTextEntryDialog *dial =
        new wxTextEntryDialog(NULL, wxT("Enter FEN:"), wxT("Error"));
    if (dial->ShowModal() == wxID_OK) {
      try {
        NewGame(new Game(dial->GetValue().ToStdString()));
      } catch (...) {
        SHOW_DIALOG_ERROR("Invalid FEN");
      }
    }
  } else {
    NewGame(new Game());
  }
}

void MainWindow::OnNewGame2(wxCommandEvent &event) {
  Game *g=(Game*)event.GetClientData();
  NewGame(g);
}

void MainWindow::OnPageChange(wxAuiNotebookEvent &event) {
  TabInfos *infos = dynamic_cast<TabInfos *>(notebook->GetCurrentPage());
  if (infos->type != TabInfos::GAME) {
    for (short i = 10; i < 20; i++) {
      if (menuGame->FindChildItem(i) != NULL) {
        menuGame->Enable(i, false);
      }
    }
  }
}

void MainWindow::OnRefreshTabTitle(wxCommandEvent &event) {
  GameTab *win = dynamic_cast<GameTab *>(event.GetEventObject());
  int page = notebook->GetPageIndex(win);
  if (page != wxNOT_FOUND) {
    notebook->SetPageText(page, win->GetLabel());
  }
}

void MainWindow::NewGame(Game *game) {
  GameTab *gt = new GameTab((wxFrame *)notebook, game);
  notebook->AddPage(gt, gt->GetLabel());
  notebook->SetSelection(notebook->GetPageIndex(gt));
}