#include "stdafx.h"

namespace xtr::mfc {

static constexpr auto MAX_PATH_LENGHT = 1024;

#pragma warning( push )
#pragma warning( disable : 26446 ) // Note: ignore gsl::at

CString ToMFC(const std::string_view str) {
  if (empty(str)) {
    return {};
  }
  const auto size_input = static_cast<int>(ssize(str));
  const auto size_needed = ::MultiByteToWideChar(CP_UTF8, 0, &str[0], size_input, nullptr, 0);
  CString result{};
  auto* buffer = result.GetBuffer(size_needed);
  const auto realSize = ::MultiByteToWideChar(CP_UTF8, 0, &str[0], size_input, buffer, size_needed);
  result.ReleaseBuffer(realSize);
  return result;
}

CString ToMFC(const std::u8string_view str) {
  std::string intermediary(reinterpret_cast<const char*>(str.data()), ssize(str));
  return ToMFC(intermediary);
}

std::string ToSTL(const CString str) {
  if (str.IsEmpty()) {
    return {};
  }
  const auto size_needed = ::WideCharToMultiByte(CP_UTF8, 0, str.GetString(), str.GetLength(), nullptr, 0, nullptr, nullptr);
  std::string result(size_needed, 0);
  ::WideCharToMultiByte(CP_UTF8, 0, str.GetString(), str.GetLength(), &result[0], size_needed, nullptr, nullptr);
  return result;
}

std::u8string ToUTF8(const CString str) {
  auto result = ToSTL(str);
  return std::u8string{ begin(result), end(result) };
}

#pragma warning( pop )

CString LoadSID(const uint32_t sid) {
  CString result{};
  if (!result.LoadStringW(sid)) {
    throw std::runtime_error(std::format("Failed loading string from table. ID: {}", sid));
  }  else {
    return result;
  }
}

std::optional<CFileStatus> FileStatus(const CFile& file) {
  CFileStatus status;
  if (!file.GetStatus(status)) {
    return std::nullopt;
  } else {
    return status;
  }
}

CString FirstWordOf(const CString str) {
  auto strPos = 0;
  CString word = str.Tokenize(L" \n\r", strPos).Trim();
  if (word.IsEmpty()) {
    word = str;
  }
  return word;
}

std::optional<int> FindBracketEndOrStart(const CString inputText,
                                             const BracketSearchParams& searchParams,
                                             bool findStart) {
  const auto inputLen = inputText.GetLength();
  if (searchParams.initialPosition > inputLen ||
    searchParams.initialPosition < 0 || inputLen < 0) {
    return std::nullopt;
  } else {
    auto currentLevel = findStart ? -1 : 1;
    auto pos = searchParams.initialPosition;
    if (findStart) {
      if (pos == 0) {
        return std::nullopt;
      }
      --pos;
    }
    for (; (findStart && pos >= 0) || (!findStart && pos <= inputLen);
      pos += (findStart ? -1 : 1)) {
      if (inputText[pos] == searchParams.closeBracket) {
        --currentLevel;
      } else if (inputText[pos] == searchParams.openBracket) {
        ++currentLevel;
      }
      if (currentLevel == 0) {
        return pos;
      }
    }
    return std::nullopt;
  }
}

std::optional<int> FindOpeningParanthesis(const CString text, const int startPos) {
  return FindBracketBlockStart(text, { '(', ')', startPos });
}

std::optional<int> FindClosingParanthesis(const CString text, const int startPos) {
  return FindBracketBlockEnd(text, { '(', ')', startPos });
}

std::optional<int> FindBracketBlockStart(const CString inputText, const BracketSearchParams& searchParams) {
  return FindBracketEndOrStart(inputText, searchParams, true);
}

std::optional<int> FindBracketBlockEnd(const CString inputText, const BracketSearchParams& searchParams) {
  return FindBracketEndOrStart(inputText, searchParams, false);
}

} // namespace xtr::mfc
