#include "util_string.hpp"

#include <iostream>
#include <algorithm>

namespace Sass {
  namespace Util {

    // ##########################################################################
    // Special case insensitive string matcher. We can optimize
    // the more general compare case quite a bit by requiring
    // consumers to obey some rules (lowercase and no space).
    // - `literal` must only contain lower case ascii characters
    // there is one edge case where this could give false positives
    // test could contain a (non-ascii) char exactly 32 below literal
    // ##########################################################################
    bool equalsLiteral(const char* lit, const sass::string& test) {
      // Work directly on characters
      const char* src = test.c_str();
      // There is a small chance that the search string
      // Is longer than the rest of the string to look at
      while (*lit && (*src == *lit || *src + 32 == *lit)) {
        ++src, ++lit;
      }
      // True if literal is at end
      // If not test was too long
      return *lit == 0;
    }

    void ascii_str_tolower(sass::string* s) {
      for (auto& ch : *s) {
        ch = ascii_tolower(static_cast<unsigned char>(ch));
      }
    }

    void ascii_str_toupper(sass::string* s) {
      for (auto& ch : *s) {
        ch = ascii_toupper(static_cast<unsigned char>(ch));
      }
    }

    sass::string rtrim(sass::string str) {
      auto it = std::find_if_not(str.rbegin(), str.rend(), ascii_isspace);
      str.erase(str.rend() - it);
      return str;
    }

    // ###########################################################################
    // Returns [name] without a vendor prefix.
    // If [name] has no vendor prefix, it's returned as-is.
    // ###########################################################################
    sass::string unvendor(const sass::string& name)
    {
      if (name.size() < 2) return name;
      if (name[0] != '-') return name;
      if (name[1] == '-') return name;
      for (size_t i = 2; i < name.size(); i++) {
        if (name[i] == '-') return name.substr(i + 1);
      }
      return name;
    }
    // EO unvendor

    sass::string normalize_newlines(const sass::string& str) {
      sass::string result;
      result.reserve(str.size());
      std::size_t pos = 0;
      while (true) {
        const std::size_t newline = str.find_first_of("\n\f\r", pos);
        if (newline == sass::string::npos) break;
        result.append(str, pos, newline - pos);
        result += '\n';
        if (str[newline] == '\r' && str[newline + 1] == '\n') {
          pos = newline + 2;
        }
        else {
          pos = newline + 1;
        }
      }
      result.append(str, pos, sass::string::npos);
      return result;
    }

    sass::string normalize_underscores(const sass::string& str) {
      sass::string normalized = str;
      std::replace(normalized.begin(), normalized.end(), '_', '-');
      return normalized;
    }

    sass::string normalize_decimals(const sass::string& str) {
      sass::string normalized;
      if (!str.empty() && str[0] == '.') {
        normalized.reserve(str.size() + 1);
        normalized += '0';
        normalized += str;
      }
      else {
        normalized = str;
      }
      return normalized;
    }

    char opening_bracket_for(char closing_bracket) {
      switch (closing_bracket) {
      case ')': return '(';
      case ']': return '[';
      case '}': return '{';
      default: return '\0';
      }
    }

    char closing_bracket_for(char opening_bracket) {
      switch (opening_bracket) {
      case '(': return ')';
      case '[': return ']';
      case '{': return '}';
      default: return '\0';
      }
    }

  }
  // namespace Util

}
// namespace Sass