/*
   mkvmerge -- utility for splicing together matroska files
   from component media subtypes

   Distributed under the GPL v2
   see the file COPYING for details
   or visit http://www.gnu.org/copyleft/gpl.html

   definitions used in all programs, helper functions

   Written by Moritz Bunkus <moritz@bunkus.org>.
*/

#include "common/common_pch.h"

#include "common/memory.h"
#include "common/strings/editing.h"

const std::string empty_string("");

std::vector<std::string>
split(std::string const &text,
      boost::regex const &pattern,
      size_t max,
      boost::match_flag_type match_flags) {
  std::vector<std::string> results;

  auto match = boost::make_regex_iterator(text, pattern, match_flags);
  boost::sregex_iterator end;
  size_t previous_match_end = 0;

  while (   (match != end)
         && (   (0 == max)
             || ((results.size() + 1) < max))) {
    results.push_back(text.substr(previous_match_end, match->position(static_cast<boost::sregex_iterator::value_type::size_type>(0)) - previous_match_end));
    previous_match_end = match->position(static_cast<boost::sregex_iterator::value_type::size_type>(0)) + match->length(0);
    ++match;
  }

  if (previous_match_end <= text.size())
    results.push_back(text.substr(std::min(previous_match_end, std::max<size_t>(text.size(), 1) - 1), text.size() - previous_match_end));

  return results;
}

void
strip_back(std::string &s,
           bool newlines) {
  const char *c = s.c_str();
  int len       = s.length();
  int i         = 0;

  if (newlines)
    while ((i < len) && (isblanktab(c[len - i - 1]) || iscr(c[len - i - 1])))
      ++i;
  else
    while ((i < len) && isblanktab(c[len - i - 1]))
      ++i;

  if (i > 0)
    s.erase(len - i, i);
}

void
strip(std::string &s,
      bool newlines) {
  const char *c = s.c_str();
  int i         = 0;

  if (newlines)
    while ((c[i] != 0) && (isblanktab(c[i]) || iscr(c[i])))
      i++;
  else
    while ((c[i] != 0) && isblanktab(c[i]))
      i++;

  if (i > 0)
    s.erase(0, i);

  strip_back(s, newlines);
}

void
strip(std::vector<std::string> &v,
      bool newlines) {
  size_t i;

  for (i = 0; i < v.size(); i++)
    strip(v[i], newlines);
}

std::string
strip_copy(std::string const &s,
           bool newlines) {
  auto new_s = s;
  strip(new_s, newlines);
  return new_s;
}

std::string &
shrink_whitespace(std::string &s) {
  size_t i                     = 0;
  bool previous_was_whitespace = false;
  while (s.length() > i) {
    if (!isblanktab(s[i])) {
      previous_was_whitespace = false;
      ++i;
      continue;
    }
    if (previous_was_whitespace)
      s.erase(i, 1);
    else {
      previous_was_whitespace = true;
      ++i;
    }
  }

  return s;
}

std::string
escape(const std::string &source) {
  std::string dst;
  std::string::const_iterator src;

  for (src = source.begin(); src < source.end(); src++) {
    if (*src == '\\')
      dst += "\\\\";
    else if (*src == '"')
      dst += "\\2";               // Yes, this IS a trick ;)
    else if (*src == ' ')
      dst += "\\s";
    else if (*src == ':')
      dst += "\\c";
    else if (*src == '#')
      dst += "\\h";
    else if (*src == '[')
      dst += "\\b";
    else if (*src == ']')
      dst += "\\B";
    else
      dst += *src;
  }

  return dst;
}

std::string
unescape(const std::string &source) {
  std::string dst;
  std::string::const_iterator src, next_char;

  src = source.begin();
  next_char = src + 1;
  while (src != source.end()) {
    if (*src == '\\') {
      if (next_char == source.end()) // This is an error...
        dst += '\\';
      else {
        if (*next_char == '2')
          dst += '"';
        else if (*next_char == 's')
          dst += ' ';
        else if (*next_char == 'c')
          dst += ':';
        else if (*next_char == 'h')
          dst += '#';
        else if (*next_char == 'b')
          dst += '[';
        else if (*next_char == 'B')
          dst += ']';
        else
          dst += *next_char;
        src++;
      }
    } else
      dst += *src;
    src++;
    next_char = src + 1;
  }

  return dst;
}

std::string
get_displayable_string(const char *src,
                       int max_len) {
  std::string result;
  int len = (-1 == max_len) ? strlen(src) : max_len;

  for (int i = 0; i < len; ++i)
    result += (' ' > src[i]) ? '?' : src[i];

  return result;
}

std::string
get_displayable_string(std::string const &src) {
  return get_displayable_string(src.c_str(), src.length());
}
