#include "stdafx.h"

#include "xtr/ui/ExteorFrame.h"

#include "resource.h"

#include "xtr/Exteor.h"
#include "xtr/doc/OSSDoc.h"
#include "xtr/doc/RSModelDoc.h"
#include "xtr/doc/RSFormDoc.h"
#include "xtr/doc/OSSDoc.h"

#include "xtr/ui/KeyboardHandler.h"

namespace xtr::ui {

#pragma warning( push )
#pragma warning( disable : 26440 26436 26454 )

BEGIN_MESSAGE_MAP(ExteorFrame, CMDIFrameWndEx)
  ON_WM_DROPFILES()
  ON_WM_CREATE()
  ON_WM_COPYDATA()
  ON_WM_ACTIVATEAPP()
END_MESSAGE_MAP()

#pragma warning( pop )

static constexpr UINT BASED_CODE buttons[] = {
  ID_FILE_NEW,
  ID_FILE_OPEN,
  ID_FILE_SAVE,
    ID_SEPARATOR,
  IXTRC_BUG_REPORT,
    ID_SEPARATOR,
  ID_EDIT_COPY,
  ID_EDIT_PASTE,
    ID_SEPARATOR,
  ID_WINDOW_TILE_HORZ,
  ID_WINDOW_TILE_VERT,
  ID_WINDOW_CASCADE,
};

static constexpr UINT BASED_CODE indicators[] = {
  ID_SEPARATOR,
  IXTRC_INDICATOR_CAPS,
  IXTRC_INDICATOR_NUM,
  IXTRC_INDICATOR_SCRL,
  IXTRC_INDICATOR_LANGUAGE,
};

static constexpr UINT BASED_CODE insbuttons[] = {
  IXTRC_INSERT_BASE_SET,
  IXTRC_INSERT_CONST_SET,
    ID_SEPARATOR,
  IXTRC_INSERT_RS,
  IXTRC_INSERT_AXIOM,
  IXTRC_INSERT_TERM,
  IXTRC_INSERT_FUNCTION,
  IXTRC_INSERT_PREDICATE,
  IXTRC_INSERT_THEOREMA,
    ID_SEPARATOR,
  IXTRC_INSERT_FREE,
    ID_SEPARATOR,
  IXTRC_DELETE_CST,
};

static constexpr UINT BASED_CODE ossbuttons[] = {
  IXTRC_OSS_ENABLE_GRID,
  IXTRC_OSS_ENABLE_LEGEND,
    ID_SEPARATOR,
  IXTRC_OSS_SHIFT_LEFT,
  IXTRC_OSS_SHIFT_RIGHT,
    ID_SEPARATOR,
  IXTRC_OSS_ADD,
  IXTRC_OSS_DEL,
  IXTRC_OSS_EDIT_DOC,
  IXTRC_OSS_ASSIGN_DOC,
    ID_SEPARATOR,
  IXTRC_OSS_OP_NEW,
  IXTRC_OSS_OP_EDIT,
    ID_SEPARATOR,
  IXTRC_OSS_OP_RUN_SINGLE,
  IXTRC_OSS_OP_RUN_ALL,
    ID_SEPARATOR,
  IXTRC_OSS_ZOOM_OUT,
  IXTRC_OSS_ZOOM_IN,
};

void ExteorFrame::SetLangStatusText(const CString text) {
  const auto index = statusbar.CommandToIndex(IXTRC_INDICATOR_LANGUAGE);
  statusbar.SetPaneText(index, text, TRUE);
}

BOOL ExteorFrame::PreCreateWindow(CREATESTRUCT& cs) {
  if (!CMDIFrameWndEx::PreCreateWindow(cs)) {
    return FALSE;
  }

  LPCTSTR pszClassName = L"Exteor";
  WNDCLASS wndcls{};
  if (!::GetClassInfoW(AfxGetInstanceHandle(), pszClassName, &wndcls)) {
    // Get the current requested window class
    VERIFY(GetClassInfoW(AfxGetInstanceHandle(), cs.lpszClass, &wndcls));
    wndcls.lpszClassName = pszClassName;

    // Need to preset the icon otherwise the function GetIconWndClass calling us will overwrite our class.
    LPCTSTR pszIcon = MAKEINTRESOURCEW(IXTRAD_MENU_MAINFRAME);
    HINSTANCE hInst = AfxFindResourceHandle(pszIcon, ATL_RT_GROUP_ICON);
    _ASSERTE(hInst != NULL);
    wndcls.hIcon = ::LoadIconW(hInst, pszIcon);

    // Register class
    if (!::RegisterClassW(&wndcls)) {
      return FALSE;
    }
  }

  cs.lpszClass = pszClassName;
  return TRUE;
}

BOOL ExteorFrame::OnCopyData(CWnd* /*pWnd*/, COPYDATASTRUCT* pCDS) { // NOLINT(readability-convert-member-functions-to-static)
  if (const auto* commandLine = static_cast<TCHAR*>(pCDS->lpData); commandLine != nullptr) {
    ::AfxGetApp()->OpenDocumentFile(commandLine);
  }
  return TRUE;
}

void ExteorFrame::OnActivateApp(BOOL bActive, DWORD dwThreadID) {
  CMDIFrameWndEx::OnActivateApp(bActive, dwThreadID);
  if (bActive) {
    Keyboard::Instance().ResetSystemLayout();
    UpdateUI();
  }
}

int32_t ExteorFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) {
  static constexpr auto errorCode = -1;
  static constexpr auto successCode = 0;
  if (CMDIFrameWndEx::OnCreate(lpCreateStruct) == errorCode) {
    return errorCode;
  }

  InitVisualStyle();

  if (!CreateControls()) {
    TRACE0("Failed to create frame controls\n");
    return errorCode;
  }
  InitControls();

  RecalcLayout();

  Keyboard::Instance().ImportSystemLayout();
  return successCode;  
}

void ExteorFrame::InitVisualStyle() {
  CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));
  CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Silver);
}

#pragma warning( push )
#pragma warning( disable : 26485 ) // do not warn about indicators array

BOOL ExteorFrame::CreateControls() {
  static constexpr auto barStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS;
  return 
    statusbar.Create(this) &&
    statusbar.SetIndicators(static_cast<const UINT*>(indicators), sizeof(indicators) / sizeof(UINT)) &&
    mainTool.CreateEx(this, TBSTYLE_FLAT, barStyle, CRect{}, IXTRAD_MENU_MAINFRAME) &&
    mainTool.LoadBitmapW(IXTRR_TOOLBAR_MAINFRAME) &&
    mainTool.SetButtons(static_cast<const UINT*>(buttons), sizeof(buttons) / sizeof(UINT)) &&
    rsTool.CreateEx(this, TBSTYLE_FLAT, barStyle, CRect{}, IXTRAD_MENU_RSFORM) &&
    rsTool.LoadBitmapW(IXTRR_TOOLBAR_RSFORM) &&
    rsTool.SetButtons(static_cast<const UINT*>(insbuttons), sizeof(insbuttons) / sizeof(UINT)) &&
    ossTool.CreateEx(this, TBSTYLE_FLAT, barStyle, CRect{}, IXTRAD_MENU_OSS) &&
    ossTool.LoadBitmapW(IXTRR_TOOLBAR_OSS) &&
    ossTool.SetButtons(static_cast<const UINT*>(ossbuttons), sizeof(ossbuttons) / sizeof(UINT));
}

#pragma warning( pop )

void ExteorFrame::InitControls() {
  mainTool.SetWindowTextW(mfc::LoadSID(IXTRS_TITLE_TOOLBAR));
  rsTool.SetWindowTextW(mfc::LoadSID(IXTRS_TITLE_INSTOOL));
  ossTool.SetWindowTextW(mfc::LoadSID(IXTRS_TITLE_OSS));

  mainTool.EnableDocking(CBRS_ALIGN_TOP);
  rsTool.EnableDocking(CBRS_ALIGN_TOP);
  ossTool.EnableDocking(CBRS_ALIGN_TOP);
  this->EnableDocking(CBRS_ALIGN_TOP);

  DockPane(&ossTool);
  DockPaneLeftOf(&rsTool, &ossTool);
  DockPaneLeftOf(&mainTool, &rsTool);

  ossTool.ShowPane(TRUE, 0, FALSE);
  rsTool.ShowPane(TRUE, 0, FALSE);
  mainTool.ShowPane(TRUE, 0, FALSE);

  CDockingManager::SetDockingMode(DT_SMART);
}

void ExteorFrame::UpdateUI() {
  RecalcLayout();
}

#pragma warning( push )
#pragma warning( disable : 26485 ) // ignore array to pointer decay

void ExteorFrame::OnDropFiles(HDROP hDropInfo) {
  const auto bufferSize = ::DragQueryFileW(hDropInfo, 0, nullptr, 0) + 1;
  CString filename{};
  ::DragQueryFileW(hDropInfo, 0, filename.GetBuffer(bufferSize), bufferSize);
  filename.ReleaseBuffer();

  const CString extension = CString(::PathFindExtensionW(filename)).MakeLower();
  if (extension == ".rsm" || extension == ".oss" || extension == ".trs") {
    CMDIFrameWndEx::OnDropFiles(hDropInfo);
  } else {
    ::AfxMessageBox(mfc::FormatSID(IXTRE_UNKNOWN_EXTENSION, filename.GetString()), MB_ICONERROR);
  }
}

#pragma warning( pop )

} // namespace xtr::ui