#include "stdafx.h"

#include "mockDocuments.h"
#include "xtr\io\TRSLegacyLoader.h"
#include "xtr\io\RSMLegacyLoader.h"
#include "xtr\io\OSSLegacyLoader.h"

using RSForm = ccl::semantic::RSForm;
using RSModel = ccl::semantic::RSModel;
using OSSchema = ccl::oss::OSSchema;

std::vector<CString> GetFilesIn(const CString directory) {
  auto dir = xtr::mfc::ToSTL(LocalPathToGlobal(directory));
  std::vector<CString> files{};
  for (const auto& file : std::filesystem::directory_iterator(dir)) {
    files.emplace_back(xtr::mfc::ToMFC(file.path().u8string()));
  }
  return files;
}

CString LocalPathToGlobal(const CString local) {
  CString currentDir{};
  ::GetCurrentDirectory(MAX_PATH, currentDir.GetBuffer(MAX_PATH));
  currentDir.ReleaseBuffer();
  auto endPos = currentDir.Find(L"\\test");
  currentDir = currentDir.Left(endPos + 5);
  currentDir.Append(L"\\");
  currentDir.Append(local);
  return currentDir;
}

MockArchive::~MockArchive() {
  CloseFile();
}

xtr::io::CArchiveAdapter MockArchive::GenerateAdapter() noexcept {
  return xtr::io::CArchiveAdapter{ *archive };
}

bool MockArchive::LoadFile(const CString path, const bool toEdit) {
  CloseFile();
  file = std::make_unique<CMirrorFile>();
  const UINT fileFlags = toEdit ? CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive : CFile::modeRead | CFile::shareDenyWrite;
  if (!file->Open(path, fileFlags)) {
    file = nullptr;
    return false;
  }
  const UINT archiveFlags = toEdit ? CArchive::store : CArchive::load;
  archive = std::make_unique<CArchive>(file.get(), archiveFlags);
  return true;
}

void MockArchive::CloseFile() {
  if (file == nullptr) {
    return;
  }
  archive->Close();
  file->Close();
  archive = nullptr;
  file = nullptr;
}

bool MockRSFormDoc::LoadFrom(const CString path) {
  MockArchive archive{};
  if (archive.LoadFile(path)) {
    auto adapter = archive.GenerateAdapter();
    if (LegacyLoad(adapter)) {
      return true;
    }
    archive.CloseFile();
  }
  return LoadJSON(xtr::mfc::ToUTF8(path));
}

bool MockRSFormDoc::SaveTo(const CString path) {
  return SaveJSON(xtr::mfc::ToUTF8(path));
}

JSON MockRSFormDoc::ExtractData() const {
  auto result = JSON(*schema);
  result["claimed"] = isClaimed;
  result["selection"] = selection;
  return result;
}

bool MockRSFormDoc::LoadData(const JSON& object) {
  schema = std::make_unique<RSForm>();
  selection.clear();
  object.get_to(*schema);
  object.at("selection").get_to(selection);
  object.at("claimed").get_to(isClaimed);
  version = static_cast<xtr::TRSVersion::VersionID>(object.at("version").get<uint16_t>());
  return true;
}

bool MockRSFormDoc::LegacyLoad(xtr::io::CArchiveAdapter& archive) {
  schema = std::make_unique<RSForm>();
  selection.clear();
  xtr::io::TRSLegacyLoader loader(archive, *schema);
  try {
    loader.LoadVersion();
    version = loader.version;
    loader.DoLoad();
    selection = loader.selection;
    isClaimed = loader.isClaimed;
  } catch (...) {
    return false;
  }
  return true;
}

bool MockRSModelDoc::LoadFrom(const CString path) {
  MockArchive archive{};
  if (archive.LoadFile(path)) {
    auto adapter = archive.GenerateAdapter();
    if (LegacyLoad(adapter)) {
      return true;
    }
    archive.CloseFile();
  }
  return LoadJSON(xtr::mfc::ToUTF8(path));
}

bool MockRSModelDoc::SaveTo(const CString path) {
  return SaveJSON(xtr::mfc::ToUTF8(path));
}

JSON MockRSModelDoc::ExtractData() const {
  auto result = JSON(*model);
  result["selection"] = selection;
  return result;
}

bool MockRSModelDoc::LoadData(const JSON& object) {
  model = std::make_unique<RSModel>();
  selection.clear();
  object.get_to(*model);
  object.at("selection").get_to(selection);
  version = static_cast<xtr::RSMVersion::VersionID>(object.at("version").get<uint16_t>());
  return true;
}

bool MockRSModelDoc::LegacyLoad(xtr::io::CArchiveAdapter& archive) {
  model = std::make_unique<RSModel>();
  selection.clear();
  xtr::io::RSMLegacyLoader loader(archive, *model);
  try {
    loader.LoadVersion();
    version = loader.version;
    loader.DoLoad();
    selection = loader.selection;
  } catch (...) {
    return false;
  }
  return true;
}

bool MockOSSDoc::LoadFrom(const CString path) {
  MockArchive archive{};
  if (archive.LoadFile(path)) {
    auto adapter = archive.GenerateAdapter();
    if (LegacyLoad(adapter)) {
      return true;
    }
    archive.CloseFile();
  }
  return LoadJSON(xtr::mfc::ToUTF8(path));
}

bool MockOSSDoc::SaveTo(const CString path) {
  return SaveJSON(xtr::mfc::ToUTF8(path));
}

JSON MockOSSDoc::ExtractData() const {
  auto result = JSON(*oss);
  result["selection"] = selection;
  return result;
}

bool MockOSSDoc::LoadData(const JSON& object) {
  oss = std::make_unique<OSSchema>();
  selection = 0;
  object.get_to(*oss);
  object.at("selection").get_to(selection);
  version = static_cast<xtr::OSSVersion::VersionID>(object.at("version").get<uint16_t>());
  return true;
}

bool MockOSSDoc::LegacyLoad(xtr::io::CArchiveAdapter& archive) {
  oss = std::make_unique<OSSchema>();
  selection = 0;
  xtr::io::OSSLegacyLoader loader(archive, *oss);
  try {
    loader.LoadVersion();
    version = loader.version;
    loader.DoLoad();
    selection = loader.selection;
  } catch (...) {
    return false;
  }
  return true;
}