#include "mainFrame.h"

#include "bars/menuBar.h"
#include "bars/statusBar.h"
#include "bars/toolBar.h"
#include "requirementsPanel/requirementsPanel.h"

#include <filesystem>

/* --- */
#include "api/project.h"
#include "api/requirement.h"
/* --- */

using namespace std;
using namespace gui;
//--------------------------------------------------------------
/* Constructor */
MainFrame::MainFrame(dBus::Bus &bus)
  : wxFrame(nullptr, wxID_ANY, _("kwa.Fr"), wxDefaultPosition, wxDefaultSize)
  , dBus::wxNode(this, bus)
{
  // Initialization
  SetIcon(wxICON(AAAA_ICON));

  const wxSize minSize(1024, 768);
  const wxSize maxSize(1200, -1);
  SetMinSize(minSize);
  SetMaxSize(maxSize);
  SetSize(minSize);

  // Creating controls
  createControls();

  // Post-initialization
  m_menuBar->Bind(wxEVT_MENU, &MainFrame::on_menuBarItemClick, this);

  CenterOnScreen();

  subscribe(dBus::makeID("log.message"));

  // Iconize();
}
//--------------------------------------------------------------
/* Creating controls */
void MainFrame::createControls()
{
  m_menuBar             = new MenuBar(this);
  m_statusBar           = new StatusBar(this);
  const auto framePanel = new wxPanel(this /*, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER*/);
  m_toolBar             = new ToolBar(framePanel);

  m_pageNotebook      = new wxNotebook(framePanel, wxID_ANY);
  m_requirementsPanel = new RequirementsPanel(m_pageNotebook, m_bus);

  m_pageNotebook->AddPage(m_requirementsPanel, "Requirements", true);

  // Controls positioning
  const auto mainSizer = new wxBoxSizer(wxVERTICAL);
  mainSizer->Add(m_toolBar, wxSizerFlags(0).Expand());
  mainSizer->Add(m_pageNotebook, wxSizerFlags(1).Expand().Border(wxALL, 5));

  framePanel->SetSizer(mainSizer);
  Layout();
}
//--------------------------------------------------------------
/* Create a new project */
void MainFrame::createProject()
{
  try
  {
    const auto ret = api::project::postProjectOperationRequest(m_bus, api::project::OperationType::Create);
    if (!ret)
    {
      wxMessageBox("No manager found for project creation request.\n\n"
                   "The manager responsible for handling project creation "
                   "did not respond to the request. Please ensure that "
                   "the project management component is running and try again.",
                   "Failed...",
                   wxOK | wxICON_WARNING,
                   this);
    }
  }
  catch (const std::exception &e)
  {
    wxMessageBox("An unexpected error occurred while creating a new project\n\n" + wxString(e.what()),
                 "Critical Error",
                 wxOK | wxICON_ERROR,
                 this);
  }
}
//--------------------------------------------------------------
/* Open an existing project */
void MainFrame::openProject()
{
  try
  {
    wxFileDialog dlg(this,
                     _("Open Project"),
                     wxEmptyString,
                     wxEmptyString,
                     "Project Files (*.kwaProj)|*.kwaProj|All Files (*.*)|*.*",
                     wxFD_OPEN | wxFD_FILE_MUST_EXIST);
    if (dlg.ShowModal() != wxID_OK)
      return;

    const auto filepath = filesystem::path(dlg.GetPath().ToStdString());
    const auto ret      = api::project::postProjectOperationRequest(m_bus, api::project::OperationType::Open, filepath);
    if (!ret)
    {
      wxMessageBox("No manager found for project opening request.\n\n"
                   "The manager responsible for handling project opening "
                   "did not respond to the request. Please ensure that "
                   "the project management component is running and try again.",
                   "Failed...",
                   wxOK | wxICON_WARNING,
                   this);
    }
  }
  catch (const std::exception &e)
  {
    wxMessageBox("An unexpected error occurred while opening a project\n\n" + wxString(e.what()),
                 "Critical Error",
                 wxOK | wxICON_ERROR,
                 this);
  }
}
//--------------------------------------------------------------
/* Save the current project */
void MainFrame::saveProject()
{
  try
  {
    const auto ret = api::project::postProjectOperationRequest(m_bus, api::project::OperationType::Save);
    if (!ret)
    {
      wxMessageBox("No manager found for project saving request.\n\n"
                   "The manager responsible for handling project saving "
                   "did not respond to the request. Please ensure that "
                   "the project management component is running and try again.",
                   "Failed...",
                   wxOK | wxICON_WARNING,
                   this);
    }
  }
  catch (const std::exception &e)
  {
    wxMessageBox("An unexpected error occurred while saving the project\n\n" + wxString(e.what()),
                 "Critical Error",
                 wxOK | wxICON_ERROR,
                 this);
  }
}
//--------------------------------------------------------------
/* Save the current project as... */
void MainFrame::saveProjectAs()
{
  try
  {
    wxFileDialog dlg(this,
                     _("Save Project"),
                     wxEmptyString,
                     wxEmptyString,
                     "Project Files (*.kwaProj)|*.kwaProj|All Files (*.*)|*.*",
                     wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
    if (dlg.ShowModal() != wxID_OK)
      return;

    const auto filepath = filesystem::path(dlg.GetPath().ToStdString());
    const auto ret      = api::project::postProjectOperationRequest(m_bus, api::project::OperationType::SaveAs, filepath);
    if (!ret)
    {
      wxMessageBox("No manager found for project saving request.\n\n"
                   "The manager responsible for handling project saving "
                   "did not respond to the request. Please ensure that "
                   "the project management component is running and try again.",
                   "Failed...",
                   wxOK | wxICON_WARNING,
                   this);
    }
  }
  catch (const std::exception &e)
  {
    wxMessageBox("An unexpected error occurred while saving the project\n\n" + wxString(e.what()),
                 "Critical Error",
                 wxOK | wxICON_ERROR,
                 this);
  }
}
//--------------------------------------------------------------
/* Close the current project */
void MainFrame::closeProject()
{
  try
  {
    const auto ret = api::project::postProjectOperationRequest(m_bus, api::project::OperationType::Close);
    if (!ret)
    {
      wxMessageBox("No manager found for project closing request.\n\n"
                   "The manager responsible for handling project closing "
                   "did not respond to the request. Please ensure that "
                   "the project management component is running and try again.",
                   "Failed...",
                   wxOK | wxICON_WARNING,
                   this);
    }
  }
  catch (const std::exception &e)
  {
    wxMessageBox("An unexpected error occurred while closing the project\n\n" + wxString(e.what()),
                 "Critical Error",
                 wxOK | wxICON_ERROR,
                 this);
  }
}
//--------------------------------------------------------------
/* Menu bar item click event */
void MainFrame::on_menuBarItemClick(wxCommandEvent &event)
{
  switch (static_cast<MenuBar::IDs>(event.GetId()))
  {
    using enum MenuBar::IDs;
    // File menu
    case ID_MENU_FILE_NEW:
    {
      createProject();
      break;
    }
    case ID_MENU_FILE_OPEN:
    {
      openProject();
      break;
    }
    case ID_MENU_FILE_SAVE:
    {
      saveProject();
      break;
    }
    case ID_MENU_FILE_SAVE_AS:
    {
      saveProjectAs();
      break;
    }
    case ID_MENU_FILE_CLOSE:
    {
      closeProject();
      break;
    }
    case ID_MENU_FILE_QUIT:
    {
      Close();
      break;
    }

    // Requirement menu
    case ID_MENU_REQ_CREATE:
    {
      break;
    }

    // Help menu
    default:
    {
    }
  }
}
//--------------------------------------------------------------
/* dBus message reception handler */
void MainFrame::on_receiveMessageFromBus(const MessageID messageID, const MessagePtr message)
{
  cout << "From MainFrame::on_receiveMessageFromBus: " << message->toString() << endl;
}
//--------------------------------------------------------------
