#include "stdafx.h"

#include "xtr/doc/RSFormDoc.h"

#include "resource.h"

#include "xtr/ExteorOptions.h"
#include "xtr/doc/RSModelDoc.h"
#include "xtr/io/TRSLegacyLoader.h"
#include "xtr/dialog/NewDocument.h"

namespace xtr::doc {

using ccl::semantic::RSForm;
using ccl::src::DataStream;

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

IMPLEMENT_DYNCREATE(RSFormDoc, SelectableDoc)

#pragma warning( pop )

RSFormDoc::RSFormDoc() {
  schema.AddObserver(*this);
}

RSFormDoc::~RSFormDoc() {
  schema.RemoveObserver(*this);
}

bool RSFormDoc::WriteData(ccl::meta::UniqueCPPtr<DataStream> data) {
  if (data == nullptr) {
    return false;
  }

  try {
    schema = dynamic_cast<const RSForm&>(*data);
    selection.clear();
    return true;
  } catch (std::bad_cast& /*e*/) {
    return false;
  }
}

DataStream* RSFormDoc::AccessData() {
  SetModifiedFlag(TRUE);
  return &schema;
}

void RSFormDoc::OnObserve(const ccl::types::Message& change) {
  if (const auto* changePtr = dynamic_cast<const ccl::change::ModMessage*>(&change); changePtr != nullptr) {
    SetModifiedFlag(TRUE);
  }
}

void RSFormDoc::Serialize(CArchive& ar) {
  MFCSerializable<TRSVersion>::Serialize(ar);
}

BOOL RSFormDoc::OnNewDocument() {
  if (!CDocument::OnNewDocument()) {
    return FALSE;
  } else if (XTROptions::App().IsSilent()) {
    return TRUE;
  } else if (dialog::NewRSForm dialog(this->GetTitle()); dialog.DoModal() != IDOK) {
    return FALSE;
  } else {
    schema.title = mfc::ToSTL(dialog.newTitle);
    schema.alias = mfc::ToSTL(dialog.newAlias);
    return TRUE;
  }
}

BOOL RSFormDoc::OnOpenDocument(LPCTSTR path) {
  if (CString(path).Right(4).MakeLower() != ExtensionFor(FileType::trs)) {
    return FALSE;
  } 
  if (!LoadJSON(mfc::ToUTF8(path))
      && !CDocument::OnOpenDocument(path)) {
    return FALSE;
  }
  SetPathName(path, FALSE);
  ccl::Environment::Sources().OnSourceOpen(*this);
  return XTROptions::App().IsSilent() || !IsClaimed() ||
    ccl::Environment::Sources().QuerySrcUse(*this) ||
    ::AfxMessageBox(IXTRS_OPEN_CLAIMED, MB_YESNO | MB_ICONQUESTION) == IDYES;
}

BOOL RSFormDoc::OnSaveDocument(LPCTSTR path) {
  if (path != GetPathName() && !GetPathName().IsEmpty()) {
    ccl::Environment::Sources().OnSourceClose(*this);
  }
  const auto changed = IsModified();

  if (!SaveJSON(mfc::ToUTF8(path))) {
    return FALSE;
  }

  SetPathName(path, FALSE);
  if (changed) {
    ccl::Environment::Sources().OnSourceChange(*this);
  }
  SetModifiedFlag(FALSE);
  return TRUE;
}

void RSFormDoc::OnCloseDocument() {
  ccl::Environment::Sources().OnSourceClose(*this);
  CDocument::OnCloseDocument();
}

JSON RSFormDoc::ExtractData() const {
  auto result = JSON(schema);
  result["claimed"] = IsClaimed();
  result["selection"] = selection;
  return result;
}

bool RSFormDoc::LoadData(const JSON& object) {
  [[maybe_unused]] const auto noObserving = DndGuard();
  object.get_to(schema);
  SetSelection(object.at("selection").get<SetOfEntities>());
  if (object.at("claimed").get<bool>()) {
    Claim();
  }
  return true;
}

bool RSFormDoc::LegacyLoad(io::CArchiveAdapter& archive) {
  [[maybe_unused]] const auto noObserving = DndGuard();
  auto loader = io::TRSLegacyLoader{ archive, schema };
  loader.LoadVersion();
  loader.DoLoad();
  SetSelection(loader.selection);
  if (loader.isClaimed) {
    Claim();
  }
  return true;
}

} // namespace xtr::doc