// This file is part of AspectC++.
// Copyright (C) 1999-2015  The AspectC++ developer team.
//                                                                
// This program is free software;  you can redistribute it and/or 
// modify it under the terms of the GNU General Public License as 
// published by the Free Software Foundation; either version 2 of 
// the License, or (at your option) any later version.            
//                                                                
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
// GNU General Public License for more details.                   
//                                                                
// You should have received a copy of the GNU General Public      
// License along with this program; if not, write to the Free     
// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
// MA  02111-1307  USA                                            

#include "StringUtils.h"

namespace ACBase {

// Return true if the string consists only of spaces.
bool only_whitespace(const std::string &str) {
  for (auto c : str)
    if (!std::isspace(static_cast<unsigned char>(c)))
      return false;
  return true;
}

// Calculate a hash value for a string using the standard C++ algorithm.
size_t hash(const std::string &str) {
  auto hash = std::hash<std::string>(); // use the standard library function; it probably makes sense
  return hash(str);
}

// Replace environment variables of the form ${ENVVAR} in the given string.
std::string& replace_environment_variables(std::string& str) {
  std::string::size_type varbegin = 0, varend = 0;

  // find first opening parenthesis
  varbegin = str.find("${", 0);
  while (varbegin != std::string::npos) {

    // find closing parenthesis
    varend = str.find("}", varbegin + 2);
    if (varend != std::string::npos) {

      // check if '$' is protected by a backslash
      std::string::size_type pos = varbegin, even = 1;
      while (pos > 0 ? str.at(--pos) == '\\' : (even = 0))
        ;
      if ((varbegin - pos) % 2 != even) {
        // odd number of backslashes, do not replace, but remove last backslash
        str.erase(varbegin - 1, 1);
        varend = varbegin;
      } else {
        // get the value of the environment variable
        const char* vstr = getenv(str.substr(varbegin + 2, varend - varbegin - 2).c_str());
        std::string value = vstr ? vstr : "";
        // replace the variable with its value
        str.replace(varbegin, varend - varbegin + 1, value);
        varend = varbegin + value.length();
      }
      // find next variable
      varbegin = str.find("${", varend);

    } else {
      // end of string
      varbegin = std::string::npos;
    }
  }
  return str;
}

// Check whether a given string starts with some other string
bool starts_with(const std::string &str, const std::string &prefix) {
  return str.substr(0, prefix.length()) == prefix;
}

// Check whether a given string end with some other string
bool ends_with(const std::string &str, const std::string &suffix) {
  auto suffix_len = suffix.length();
  return str.length() >= suffix_len && str.substr(str.length() - suffix_len) == suffix;
}

// replace a substring within a string
void replace_in_string(std::string& subject, const std::string& search,
    const std::string& replace, bool is_id) {
  size_t pos = 0;
  while ((pos = subject.find(search, pos)) != std::string::npos) {
    bool id_before = (pos > 0 && (subject[pos - 1] == '_' || std::isalpha(subject[pos - 1])));
    bool id_after  = ((pos + search.length () < subject.length()) &&
        (subject[pos + search.length()] == '_' || std::isalnum(subject[pos + search.length()])));
    if (!is_id || (!id_before && !id_after)) {
      subject.replace(pos, search.length(), replace);
      pos += replace.length();
    }
    else
      pos += search.length();
  }
}

} // namespace ACBase
