#ifndef CDO_SIMILAR_H
#define CDO_SIMILAR_H

#include <concepts>
#include <ranges>
#include <string>

#include "util_string.h"

/**
 * @param a pointer to a string/substring
 * @param b pointer to a string/substring
 * @param alen length of string a
 * @param blen length of string b
 * @retval true if a is similar to b
 * @retval false if a is not similar to b
 *
 * Recursive function for finding substrings of a operator name that match other operators.
 */
static bool
similar(const char *a, const char *b, unsigned long alen, unsigned long blen)
{
  if (alen > 2 && blen > 2 && std::strstr(b, a)) return true;

  while (*a && *b && *a == *b)
  {
    a++;
    b++;
  }
  if (!*a && !*b) return true;

  //  printf("%d %d %s %s\n", alen, blen, a, b);

  if (alen >= 2 && blen >= 1 && *a && similar(a + 1, b, alen - 2, blen - 1)) return true;

  if (alen >= 1 && blen >= 2 && *b && similar(a, b + 1, alen - 1, blen - 2)) return true;

  return false;
}

/**
 * @param original string tested for similarity to \p other
 * @param other string that \p original will be compared to
 * @retval true if original and other are similar
 * @retval false if not
 *
 * Wrapper function for #similar() to parse c++ strings to c strings
 */
static bool
similar(std::string const &original, std::string const &other)
{
  return (similar(original.c_str(), other.c_str(), original.size(), other.size()));
}


// Accepts any range whose elements can bind to:
//   std::string const&
template <typename T>
concept StringIterable =
    std::ranges::input_range<T> &&
    std::convertible_to<
        std::ranges::range_reference_t<T>,
        std::string const&
    >;

/***
 * function for finding similar operator names for the given string
 * @param operatorName operator name to find similar operators for
 * @returns A string with all found names. The string is seqmented into lines
 * with a max length of 75 characters
 */
template<typename T>
std::string
find_similar(std::string const &operatorName,const T & container )
{
  std::string found_similar_operators = "";
  size_t lines = 1;
  constexpr size_t line_length = 105;

  if (operatorName != "")
  {
    // Searching for similar operator names in operator to module map
    for (auto const &str : container)
    {
      if (similar(string_to_lower(operatorName), str.first))
      {
        if (found_similar_operators.size() + str.first.size() > lines * line_length)
        {
          found_similar_operators += "\n";
          lines++;
        }
        found_similar_operators += str.first;
        found_similar_operators += " ";
      }
    }
  }

  if (found_similar_operators.size() == 0) { found_similar_operators = "(not found)"; }
  return found_similar_operators;
}

#endif
