package raindrop.utils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Simon Reinisch
 */
public final class RegexUtils {

  private RegexUtils() {}

  /**
   * Match an string and save the matches into an ArrayList.
   *
   * @param content The string wich you want to match.
   * @param regex   The Regular Expressions.
   * @param group   The group wich you want to get. -1 for the full Match.
   */
  public static ArrayList<String> matchAll(String content, String regex, int group) {
    if (content == null || regex == null || group < -1) return null;
    ArrayList<String> matches = new ArrayList<>();
    Matcher mat = Pattern.compile(regex).matcher(content);

    while (mat.find()) {
      if (group == -1)
        matches.add(mat.group());
      else
        matches.add(mat.group(group));
    }

    return matches;
  }

  /**
   * Matches a string into a hashMap.
   *
   * @param content The string wich you want to match.
   * @param regex   The Regular Expressions.
   * @param group1  The first group, wich is the key in the hashMap. (-1
   *                defines the completly match).
   * @param group2  The second group, wich is the value in the hashMap. (-1
   *                defines the completly match).
   * @return A hashMap with the results or null if there is no match or an paramter is invalid or null
   */
  public static HashMap<String, String> hashMap(String content, String regex, int group1, int group2) {
    if (content == null || regex == null || group1 < -1 || group2 < -1) return null;
    HashMap<String, String> map = new HashMap<>();
    Matcher mat = Pattern.compile(regex).matcher(content);
    String a, b;

    while (mat.find()) {

      if (group1 == -1)
        a = mat.group();
      else
        a = mat.group(group1);

      if (group2 == -1)
        b = mat.group();
      else
        b = mat.group(group2);

      map.put(a, b);
    }

    return map;
  }

  /**
   * Match an string only matchOnce.
   *
   * @param content The string wich you want to match.
   * @param regex   The Regular Expressions.
   * @param group   The group wich you want to get. -1 for the full Match.
   * @return From the first match the group or all. If there is no match or an paramter is invalid or null, it
   * returns null.
   */
  public static String matchOnce(String content, String regex, int group) {
    if (content == null || regex == null || group < -1) return null;
    Matcher mat = Pattern.compile(regex).matcher(content);

    if (mat.find()) {
      if (group == -1)
        return mat.group();
      return
          mat.group(group);
    }

    return null;
  }

  /**
   * Replace all certain areas of a string.
   *
   * @param content     The target String.
   * @param regex       The Regular Expressions.
   * @param replacement The new word.
   * @param group       The group wich you want to replace with the new word. -1
   *                    defines the complete match.
   * @return A String where a specific group is replaced, returns null if there is an invalid parameter or null.
   */
  public static String replace(String content, String regex, String replacement, int group) {
    if (content == null || regex == null || replacement == null || group < -1) return null;
    Matcher mat = Pattern.compile(regex).matcher(content);
    StringBuilder sb = new StringBuilder(content);

    int from = 0, to;
    while (mat.find()) {
      from = sb.indexOf(mat.group(), from);

      if (group == -1) {
        to = from + mat.group().length();
        sb.replace(from, to, replacement);
      } else {
        to = from + mat.group(group).length();
        sb.replace(from, to, replacement);
      }
    }

    return sb.toString();
  }

  /**
   * Count an substring in an string.
   *
   * @param sourcestring The source string.
   * @param substring    The string wich you want to count.
   * @return How often the {@code substring} is represent in the souce tring.
   */
  public static int countMatches(String sourcestring, String substring) {
    Matcher mat = Pattern.compile(Pattern.quote(substring)).matcher(sourcestring);
    int count = 0;

    while (mat.find())
      count++;

    return count;
  }

  /**
   * Exec an regular expressions an execute one times,
   * if the regex doesn't match the given string {@code null}
   * will be returned.
   *
   * @param regex   The regular expressions.
   * @param content The content.
   * @return The Matcher.
   */
  public static Matcher exec(String regex, String content) {
    if (regex == null || content == null)
      return null;

    Matcher mat = Pattern.compile(regex).matcher(content);
    if (mat.find())
      return mat;

    return null;
  }
}