#ifndef __core__strings_h
#define __core__strings_h

#include <string>
#include <vector>
#include <array>
#include <limits>
#include <stdexcept>
#include <cstdint>

class QString;
class QByteArray;

namespace Strings {

/* Implode function: takes a vector of strings and turns it
   into a string, separated by delimiters. */
std::string Implode(const std::vector<std::string>& vector, const std::string& delimiter);
std::vector<std::string> Split(const std::string &text, const std::string& delimiter);

/* Substring removal functions */
std::string ReplaceAll(std::string string, const std::string& find, const std::string& replace);
std::string SanitizeLineEndings(const std::string& string);
std::string RemoveHtmlTags(std::string string);
std::string ParseHtmlEntities(std::string string);

/* stupid HTML bullshit */
std::string TextifySynopsis(const std::string& string);

std::string ToUpper(const std::string& string);
std::string ToLower(const std::string& string);

/* functions that make the way we convert from and to
   different string formats universal */
std::wstring ToWstring(const std::string& string);
std::wstring ToWstring(const QString& string);
std::string ToUtf8String(const std::wstring& wstring);
std::string ToUtf8String(const QString& string);
std::string ToUtf8String(const QByteArray& ba);
QString ToQString(const std::string& string);
QString ToQString(const std::wstring& wstring);

/* arithmetic :) */
template<typename T = int>
T ToInt(const std::string& str, T def = 0) {
   auto clamp = [](const T& val, const T& min, const T& max){
      return std::max(min, std::min(val, max));
   };

   try {
      if constexpr (std::is_signed<T>::value) {
         return clamp(std::stoll(str), std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
      } else if constexpr (std::is_unsigned<T>::value) {
         return clamp(std::stoull(str), std::numeric_limits<T>::max(), std::numeric_limits<T>::max());
      } else {
         throw std::invalid_argument("Invalid input to Strings::ToInt()!");
      }
   } catch (std::invalid_argument const& ex) {
      return def;
   }
}

bool ToBool(const std::string& s, const bool def = false);
std::string ToUtf8String(const bool b);

uint64_t HumanReadableSizeToBytes(const std::string& str);

std::string RemoveLeadingChars(std::string s, const char c);
std::string RemoveTrailingChars(std::string s, const char c);

bool BeginningMatchesSubstring(const std::string& str, const std::string& sub);

}; // namespace Strings

#endif // __core__strings_h