#pragma once
#include <iosfwd>
#include <sstream>
#include <vector>
#include "macro.hpp"
namespace a83 {
using Str = std::string;
using v_str_t = std::vector<Str>;
constexpr auto npos = a83::Str::npos;
//! преобразовать адрес в строку
template <class T> a83::Str a2s(const T* ptr) {
  if ( !ptr)
    return "null";
  std::stringstream strm;
  strm << ptr;
  return strm.str();
}
//! convert num to string
template<typename T> a83::Str n2s(T num)
  { return std::to_string(num); }
//! convert num to string + precission
template<typename T> a83::Str n2s(T num, int prec) {
  std::ostringstream out;
  out.precision(prec);
  out << std::fixed << num;
  return out.str();
}
template<typename T> a83::Str n2hex(T num) {
  std::ostringstream out;
  out << std::hex << num;
  return out.str();
}
template<typename T> T s2n(a83::Str str) {
  std::istringstream ss(str);
  T ret;
  ss >> ret;
  return ret;
}
//! замена разделительных символов на совместимые с системой
void convSep(a83::Str& str) {
  #ifdef DEBUG // в дебаге этот вар быстрее работает
  FOR (i, str.size())
    if (str[i] == NSEPARATOR)
        str[i] = SEPARATOR;
  #else
  std::replace(str.begin(), str.end(), NSEPARATOR, SEPARATOR);
  #endif
}
//! делит строку в местах разделительного символа
v_str_t split_str(CN(a83::Str) str, char separator) {
  if (str.empty())
    return {};
  v_str_t ret = {};
  std::stringstream ss(str);
  std::string token;
  while (std::getline(ss, token, separator))
    if ( !token.empty())
      ret.push_back(token);
  return ret;
}
//! делает все буквы строки БОЛЬШИМИ
a83::Str toupper(a83::Str str) {
  std::transform(str.begin(), str.end(),str.begin(), ::toupper);
  return str;
}
//! делает все буквы строки меньше
a83::Str tolower(a83::Str str) {
  std::transform(str.begin(), str.end(),str.begin(), ::tolower);
  return str;
}
//! возвращает слово между двумя символами
a83::Str getWord(CN(a83::Str) src,
char tag1, char tag2) {
  std::size_t tag1_pos = src.find(tag1);
  std::size_t tag2_pos = src.rfind(tag2);
  if (tag1_pos == a83::npos or tag2_pos == a83::npos)
    return {};
  ++tag1_pos;
  return src.substr(tag1_pos, tag2_pos - 1);
}
/** парсит параметр/зрачение между символом op_ch.
 * вырезает cut_ch между ними */
std::pair<a83::Str, a83::Str>
getParamValue(CN(a83::Str) src, char op_ch, char cut_ch) {
  if (src.empty())
    return {};
  std::pair<a83::Str, a83::Str> ret = {};
  auto op_pos = src.find(op_ch);
  if (op_pos == a83::npos)
    return {};
  uint i = op_pos;
  while (i > 0) {
    --i;
    if (src[i] != cut_ch) {
      ret.first = src.substr(0, i + 1);
      break;
    }
  }
  i = op_pos;
  while (i != src.size()) {
    ++i;
    if (src[i] != cut_ch) {
      ret.second = src.substr(i, src.size());
      break;
    }
  }
  return ret;
}
//! удаляет символы ch из строки
void remove_all(a83::Str& str, char ch)
  { str.erase(std::remove(str.begin(), str.end(), ch), str.end()); }
//! переводит секунды в MM:SS.SS
template<class T> Str s2t(T val) {
  cauto sec = std::fmod(val, 60.0f);
  cauto min = int(val * (1.0f / 60.0f));
  return n2s(min) + ":" + n2s(sec, 2);
}
//! удаляет все val строки из str
void delete_all(a83::Str& str, CN(a83::Str) val) {
  while (1) {
    if (cauto pos = str.find(val); pos != a83::npos)
      str.erase(pos, val.length());
    else
      return;
  }
} // delete_all
//! заменяет все подстроки val из str на new_
void replace_all(a83::Str& str, CN(a83::Str) val, CN(a83::Str) new_) {
  #ifdef DEBUG
  IFERROR(val == str, "replace_all: need different args \"" + val + "\", \"" + new_ + "\"");
  #endif
  while (1) {
    if (cauto pos = str.find(val); pos != a83::npos) {
      str.erase(pos, val.length());
      str.insert(pos, new_);
    } else
      return;
  }
} // replace_all
} // end ns