#include "stdafx.h"

#include "xtr/doc/DocumentManager.h"

#include "resource.h"

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

#include "xtr/ui/SplitterFrame.h"

#include "xtr/view/RSFormView.h"
#include "xtr/view/RSModelView.h"
#include "xtr/view/OSSView.h"

#include "xtr/dialog/NewDocument.h"

namespace xtr::doc {

using ccl::semantic::RSForm;
using ccl::semantic::RSModel;

BOOL DocumentManager::Initialize() {
  m_RSFormTemplate = new CMultiDocTemplate( // NOLINT(cppcoreguidelines-owning-memory)
    IXTRAD_MENU_RSFORM,
    RUNTIME_CLASS(doc::RSFormDoc),
    RUNTIME_CLASS(ui::RSFormFrame),
    RUNTIME_CLASS(view::RSFormView));
  assert(m_RSFormTemplate);
  exteor.AddDocTemplate(m_RSFormTemplate);

  m_RSModelTemplate = new CMultiDocTemplate( // NOLINT(cppcoreguidelines-owning-memory)
    IXTRAD_MENU_RSMODEL,
    RUNTIME_CLASS(doc::RSModelDoc),
    RUNTIME_CLASS(ui::RSModelFrame),
    RUNTIME_CLASS(view::RSModelView));
  assert(m_RSModelTemplate);
  exteor.AddDocTemplate(m_RSModelTemplate);

  m_OSSTemplate = new CMultiDocTemplate( // NOLINT(cppcoreguidelines-owning-memory)
    IXTRAD_MENU_OSS,
    RUNTIME_CLASS(doc::OSSDoc),
    RUNTIME_CLASS(ui::OSSFrame),
    RUNTIME_CLASS(view::OSSView));
  assert(m_OSSTemplate);
  exteor.AddDocTemplate(m_OSSTemplate);

  return TRUE;
}

std::vector<const RSForm*> DocumentManager::RSFormList() const {
  std::vector<const RSForm*> result{};
  auto* pos = m_RSFormTemplate->GetFirstDocPosition();
  while(pos != nullptr)  {
    auto* doc = dynamic_cast<doc::RSFormDoc*>(m_RSFormTemplate->GetNextDoc(pos));
    if (doc != nullptr) {
      result.emplace_back(&doc->Schema());
    }
  }
  return result;
}

std::vector<const RSModel*> DocumentManager::RSModelList() const {
  std::vector<const RSModel*> result{};
  auto* pos = m_RSModelTemplate->GetFirstDocPosition();
  while(pos != nullptr)  {
    auto* doc = dynamic_cast<doc::RSModelDoc*>(m_RSModelTemplate->GetNextDoc(pos));
    if (doc != nullptr) {
      result.emplace_back(&doc->Model());
    }
  }
  return result;
}

std::vector<const doc::RSFormDoc*> DocumentManager::RSFormDocList() const {
  std::vector<const doc::RSFormDoc*> result{};
  auto* pos = m_RSFormTemplate->GetFirstDocPosition();
  while(pos != nullptr)  {
    const auto* doc = dynamic_cast<doc::RSFormDoc*>(m_RSFormTemplate->GetNextDoc(pos));
    if (doc != nullptr) {
      result.emplace_back(doc);
    }
  }
  return result;
}

doc::RSFormDoc* DocumentManager::FindRSDocByPath(const CString path) {
  auto* pos = m_RSFormTemplate->GetFirstDocPosition();
  while(pos != nullptr)  {
    auto* doc = dynamic_cast<doc::RSFormDoc*>(m_RSFormTemplate->GetNextDoc(pos));
    if (doc->GetPathName().CompareNoCase(path) == 0) {
      return doc;
    }
  }
  return nullptr;
}

void DocumentManager::ShowDocument(doc::XTRDocument& doc) {
  auto* pos = doc.GetFirstViewPosition();
  if (const auto* view = doc.GetNextView(pos); view != nullptr) {
    doc.UpdateAllViews(nullptr);
    view->GetParentFrame()->ActivateFrame(SW_RESTORE);
  } else if (CreateViewFor(doc)) {
    ShowDocument(doc);
  }
}

BOOL DocumentManager::CreateViewFor(doc::XTRDocument& doc) {
  if (const auto* rsDoc = dynamic_cast<doc::RSFormDoc*>(&doc);  rsDoc == nullptr) {
    return false;
  } else if (auto* frame = m_RSFormTemplate->CreateNewFrame(&doc, nullptr); frame == nullptr) {
    ::AfxMessageBox(IXTRE_DOC_FRAME, MB_ICONERROR);
    return false;
  } else {
    m_RSFormTemplate->InitialUpdateFrame(frame, &doc);
    return true;
  }
}

doc::RSFormDoc* DocumentManager::NewRSFormDoc(const RSForm& schema, BOOL noView) {
  auto* result = NewRSFormDoc(noView);
  if (result != nullptr) {
    const std::string newFull = result->Schema().title;
    const std::string newShort = result->Schema().alias;
    const std::string newComment = result->Schema().comment;

    result->Schema() = schema;
    if (!std::empty(newFull) || !std::empty(newShort) || !std::empty(newComment)) {
      result->Schema().title = newFull;
      result->Schema().alias = newShort;
      result->Schema().comment = newComment;
    }
    result->UpdateAllViews(nullptr);
  }
  return result;
}

doc::RSFormDoc* DocumentManager::NewRSFormDoc(BOOL noView) {
  return dynamic_cast<doc::RSFormDoc*>(NewDoc(*m_RSFormTemplate, noView));
}

doc::RSModelDoc* DocumentManager::NewRSModelDoc(BOOL noView) {
  return dynamic_cast<doc::RSModelDoc*>(NewDoc(*m_RSModelTemplate, noView));
}

doc::OSSDoc* DocumentManager::NewOSSDoc(BOOL noView) {
  return dynamic_cast<doc::OSSDoc*>(NewDoc(*m_OSSTemplate, noView));
}

CDocument* DocumentManager::NewDoc(CMultiDocTemplate& templ, BOOL noView) {
  if (noView) {
    return templ.CreateNewDocument();
  } else {
    return templ.OpenDocumentFile({});
  }
}

doc::RSFormDoc* DocumentManager::OpenRSFormDoc(const CString path, BOOL noView /*= FALSE*/) {
  return dynamic_cast<doc::RSFormDoc*>(OpenDoc(*m_RSFormTemplate, path, noView));
}

CDocument* DocumentManager::OpenDoc(CMultiDocTemplate& templ, const CString path, BOOL noView) {
  if (!noView) {
    return templ.OpenDocumentFile(path);
  } else {
    std::unique_ptr<CDocument> result{ templ.CreateNewDocument() };
    if (result->OnOpenDocument(path)) {
      return result.release();
    } else {
      return nullptr;
    }
  }
}

} // namespace xtr::doc