#include "stdafx.h"

#include "xtr/dialog/RSModelPage.h"

#include "resource.h"

#include "xtr/cclDescriptor.h"
#include "xtr/xtrProcedures.h"
#include "xtr/ExteorOptions.h"
#include "xtr/doc/RSModelDoc.h"

#include "xtr/ui/KeyboardHandler.h"
#include "xtr/ui/HelpHandler.h"

#include "xtr/dialog/EditConstituenta.h"

namespace xtr::dialog {

using ui::Keyboard;

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

BEGIN_MESSAGE_MAP(RSModelPage, CPropertyPage)
  ON_CBN_SELCHANGE(IXTRC_NAME_CB, &ThisClass::OnSelchangeName)
  ON_CBN_KILLFOCUS(IXTRC_EDIT_DATA, &ThisClass::OnCbnKillfocusEditData)
  ON_BN_CLICKED(IXTRC_FILL_INTERP, &ThisClass::OnBnClickedFillInterp)
  ON_BN_CLICKED(IXTRC_ERASE_DATA, &ThisClass::OnEraseData)
  ON_BN_CLICKED(IXTRC_EXPORT_DATA, &ThisClass::OnExportData)
  ON_BN_CLICKED(IXTRC_IMPORT_CSTDATA, &ThisClass::OnImportData)

  ON_BN_CLICKED(IXTRC_PREV, &ThisClass::OnPrev)
  ON_BN_CLICKED(IXTRC_NEXT, &ThisClass::OnNext)

  ON_NOTIFY(LVN_ITEMCHANGED, IXTRC_DATA_TABLE, &ThisClass::OnDataChange)
END_MESSAGE_MAP()

#pragma warning( pop )

RSModelPage::RSModelPage(EditConstituentaDlg& parent)
  : CPropertyPage(IXTRD_CST_EDIT_MODEL), parent{ parent } {}

BOOL RSModelPage::OnInitDialog() {
  CPropertyPage::OnInitDialog();

  InitControls();
  InitCstNameList();
  UpdateData(FALSE);

  return TRUE;
}

void RSModelPage::InitControls() {
  static constexpr UINT PROPERTI_DROPPED_WIDTH = 820;

  exprCtrl.InitRE(Keyboard::Layout::MATH, TRUE, TRUE);
  textCtr.InitRE(Keyboard::Layout::RUS);
  nameCtrl.SetDroppedWidth(PROPERTI_DROPPED_WIDTH);
  nameCtrl.SetFont(&XTROptions::App().fontText);
  textCtr.SetFont(&XTROptions::App().fontText);
  textBtn.SetCheck(XTROptions::Model().m_DataMode);
  dataCtrl.Init(&dataEditCtrl, textBtn.GetCheck(),  dynamic_cast<doc::RSModelDoc&>(parent.editor->Document()));
  dataEditCtrl.ShowWindow(SW_HIDE);
}

void RSModelPage::InitCstNameList() {
  nameCtrl.SetRedraw(FALSE);

  const auto sel = nameCtrl.GetCurSel();
  nameCtrl.ResetContent();
  for (const auto uid : parent.editor->List()) {
    const auto& cst = parent.editor->GetText(uid);
    auto str = mfc::ToMFC(cst.alias);
    str += LR"( - )" + mfc::ToMFC(cst.definition.Str());
    str.Replace(L"\n", L" ");
    nameCtrl.AddString(str);
  }
  nameCtrl.SetCurSel(sel);

  nameCtrl.SetRedraw(TRUE);
}

void RSModelPage::DoDataExchange(CDataExchange* pDX) {
  CPropertyPage::DoDataExchange(pDX);

  ::DDX_Control(pDX, IXTRC_NAME_CB, nameCtrl);
  ::DDX_Control(pDX, IXTRC_TYPIFICATION, exprCtrl);
  ::DDX_Control(pDX, IXTRC_INTERPRETATION, textCtr);
  ::DDX_Control(pDX, IXTRC_DATA_TABLE, dataCtrl);
  ::DDX_Control(pDX, IXTRC_EDIT_DATA, dataEditCtrl);
  ::DDX_Control(pDX, IXTRC_FILL_INTERP, textBtn);

  if (!pDX->m_bSaveAndValidate)  {
    typification = info::Label(parent.editor->GetParse(parent.activeUID).TypePtr());
    textDef  = mfc::ToMFC(parent.editor->GetText(parent.activeUID).definition.Str());
    if (dataCtrl.IsInit()) {
      dataCtrl.SetActive(parent.activeUID);
    }
  }

  auto sellectedName = mfc::ToMFC(parent.editor->GetText(parent.activeUID).alias);
  ::DDX_Text(pDX, IXTRC_TYPIFICATION, typification);
  ::DDX_Text(pDX, IXTRC_INTERPRETATION, textDef);
  ::DDX_CBString(pDX, IXTRC_NAME_CB, sellectedName);

  if (pDX->m_bSaveAndValidate) {
    dataCtrl.SaveData();
    parent.editor->Document().UpdateAllViews(nullptr);
  } else {
    UpdateFormat();
  }
}

void RSModelPage::UpdateFormat() {
  exprCtrl.UpdateFormat();
}

BOOL RSModelPage::PreTranslateMessage(MSG* pMsg) {
  if (pMsg->message == WM_KEYDOWN) {
    if (pMsg->wParam == VK_ESCAPE) {
      if (dataEditCtrl.IsWindowVisible()) {
        CancelEdit();
      } else {
        OnCancel();
      }
      return TRUE;
    }
    if (pMsg->wParam == VK_RETURN) {
      if (dataEditCtrl.IsWindowVisible()) {
        UpdateCellText();
      }
      return TRUE;
    }
    if (pMsg->wParam == VK_F1) { 
      ui::HelpHandler::RunHelp(ui::HelpID::editData);  
      return TRUE; 
    }
  }
  return CPropertyPage::PreTranslateMessage(pMsg);
}

void RSModelPage::CancelEdit() {
  canceled = TRUE;
  dataEditCtrl.ShowWindow(SW_HIDE);
  dataCtrl.SetFocus();
  canceled = FALSE;
}

void RSModelPage::SetModified(BOOL bChanged) {
  isModified = bChanged;
  CPropertyPage::SetModified(bChanged);
}

BOOL RSModelPage::IsModified() const noexcept {
  return isModified;
}

void RSModelPage::OnCbnKillfocusEditData() {
  if (!canceled) {
    UpdateCellText();
  }
}

BOOL RSModelPage::OnApply() {
  if (!CPropertyPage::OnApply()) {
    return FALSE;
  } else if (parent.GetActivePage() != this) {
    return TRUE;
  } else {
    UpdateData(FALSE);
    return TRUE;
  }
}

void RSModelPage::OnCancel() {
  CPropertyPage::OnCancel();
  EndDialog(IDCANCEL);
}

void RSModelPage::OnOK() {
  if (parent.GetActivePage() == this) {
    UpdateData();
    SetModified(FALSE);
    CPropertyPage::OnOK();
  }
}

void RSModelPage::OnConfirm() {
  UpdateData();
}

void RSModelPage::OnSelchangeName() {
  const auto index = nameCtrl.GetCurSel();
  assert(index != mfc::noItems);

  OnApply();

  CString name{};
  nameCtrl.GetLBText(index, name);
  name = mfc::FirstWordOf(name);

  parent.activeUID = parent.editor->Core().FindAlias(mfc::ToSTL(name)).value();
  UpdateData(FALSE);
}

void RSModelPage::OnBnClickedFillInterp() {
  XTROptions::Model().m_DataMode = textBtn.GetCheck();
  dataCtrl.SetTextFlag(textBtn.GetCheck());
}

void RSModelPage::OnImportData() {
  UpdateData(TRUE);
  proc::ImportCstDataFromExcel(parent.editor->EditModel(), parent.activeUID);
  UpdateData(FALSE);
}

void RSModelPage::OnDataChange(NMHDR* /*pNMHDR*/, LRESULT* pResult) {
  if (GetFocus() != nullptr && GetFocus() == GetDlgItem(IXTRC_DATA_TABLE)) {
    SetModified(TRUE);
  }
  *pResult = 1;
}

void RSModelPage::OnExportData() { // NOLINT(readability-make-member-function-const)
  proc::ExportCstDataToExcel(parent.editor->Model(), parent.activeUID);
}

void RSModelPage::OnEraseData() {
  proc::EraseCstData(parent.editor->EditModel(), parent.activeUID);
  UpdateData(FALSE);
}

void RSModelPage::UpdateCellText() {
  canceled = TRUE;
  dataCtrl.UpdateSelectedCellText();
  dataCtrl.SetFocus();
  canceled = FALSE;
}

void RSModelPage::OnPrev() {
  UpdateData(TRUE);
  parent.StepPrev();
  UpdateData(FALSE);
}

void RSModelPage::OnNext() {
  UpdateData(TRUE);
  parent.StepNext();
  UpdateData(FALSE);
}

} // namespace xtr::dialog