#include "stdafx.h"

#include "xtr/view/TermTreeView.h"
#include "xtr/doc/RSFormDoc.h"
#include "xtr/doc/RSModelDoc.h"

#include "resource.h"

#include "xtr/ui/HelpHandler.h"

namespace xtr::view {

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

IMPLEMENT_DYNCREATE(TermTreeView, CFormView)

BEGIN_MESSAGE_MAP(TermTreeView, CFormView)
  ON_NOTIFY(NM_DBLCLK, IXTRC_TERM_TREE, &ThisClass::OnDblclkTermTree)
  ON_COMMAND(IXTRC_XTR_HELP, &ThisClass::OpenHelp)
END_MESSAGE_MAP()

#pragma warning( pop )

TermTreeView::TermTreeView()
  : CFormView(IXTRD_VIEW_TERMTREE) {}

void TermTreeView::OnInitialUpdate() {
  document = dynamic_cast<doc::SelectableDoc*>(m_pDocument);
  if (const auto* modelDoc = dynamic_cast<doc::RSModelDoc*>(document); modelDoc != nullptr) {
    core = &modelDoc->Model().Core();
  } else if (document != nullptr) {
    core = &dynamic_cast<doc::RSFormDoc*>(document)->Schema().Core();
  }

  CFormView::OnInitialUpdate();
}

void TermTreeView::DoDataExchange(CDataExchange* pDX) {
  CFormView::DoDataExchange(pDX);

  ::DDX_Control(pDX, IXTRC_TERM_TREE, termTreeCtrl);

  if (!pDX->m_bSaveAndValidate) {
    BuildTree();
  }
}

BOOL TermTreeView::BuildTree() {
  termTreeCtrl.SetRedraw(FALSE);
  termTreeCtrl.DeleteAllItems();
  for (const auto uid : core->List()) {
    const auto& cst = core->GetRS(uid);
    auto* root = termTreeCtrl.InsertItem(mfc::ToMFC(cst.alias));
    const auto connections = core->RSLang().Graph().InputsFor(cst.uid);
    const auto sorted = core->List().SortSubset(connections);
    for (const auto child : sorted) {
      auto sNextName = mfc::ToMFC(core->GetRS(child).alias);
      auto* const current = termTreeCtrl.InsertItem(sNextName, root);
      InsertSubTree(&termTreeCtrl, current, sNextName);
    }

    if (document->IsSelected(cst.uid)) {
      termTreeCtrl.Expand(root, TVE_EXPAND);
      termTreeCtrl.SelectItem(root);
    }
  }
  termTreeCtrl.SetRedraw(TRUE);
  termTreeCtrl.RedrawWindow();
  return TRUE;
}

void TermTreeView::OpenHelp() { // NOLINT(readability-convert-member-functions-to-static)
  ui::HelpHandler::RunHelp(ui::HelpID::viewRSForm);
}

void TermTreeView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) {
  CView::OnUpdate(pSender, lHint, pHint);
  if (document != nullptr && pSender != this) {
    UpdateData(FALSE);
  }
}

void TermTreeView::OnBuild() {
  BuildTree();
}

void TermTreeView::OnDblclkTermTree(NMHDR* /*pNMHDR*/, LRESULT* pResult) {
  auto* const hItem = termTreeCtrl.GetSelectedItem();
  const auto sName = termTreeCtrl.GetItemText(hItem);
  InsertSubTree(&termTreeCtrl, hItem, sName);
  *pResult = FALSE;
}

int32_t TermTreeView::InsertSubTree(CTreeCtrl* termTree, HTREEITEM current, const CString sName) {
  auto result = 0;
  auto* item = FindItemInTree(termTree, sName);
  if (termTree->GetNextItem(current, TVGN_CHILD) != nullptr) {
    return 0;
  } else {
    auto* child = termTree->GetNextItem(item, TVGN_CHILD);
    while (child != nullptr) {
      auto sSubName = termTree->GetItemText(child);
      termTree->InsertItem(sSubName, current);
      ++result;
      child = termTree->GetNextItem(child, TVGN_NEXT);
    }
    return result;
  }
}

HTREEITEM TermTreeView::FindItemInTree(const CTreeCtrl* termTree, const CString sFindName) {
  auto* root = termTree->GetRootItem();
  if (root == nullptr) {
    return root;
  }

  auto* item = termTree->GetNextItem(root, TVGN_ROOT);
  while (item != nullptr) {
    if (sFindName == termTree->GetItemText(item)) {
      return item;
    } else {
      item = termTree->GetNextItem(item, TVGN_NEXT);
    }
  }
  return nullptr;
}

} // namespace xtr::view