package com.github.bot.curiosone.core.nlp.base;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * Spelling Corrector.
 */

public class Spelling {

  /**
  * String representation of the path to the dictionary file.
  */
  private static final String DICT_PATH
      = "src/main/res/spelling/dictionary.txt";

  /**
  * The instance of this singleton class.
  */
  private static Spelling instance;

  /**
  * Path to the dictionary file.
  */
  private static Path dictionaryFile = Paths.get(DICT_PATH);

  /** Dictionary. */
  private Map<String, Integer> dict = new HashMap<>();

  /**
   * Spellig.
   */
  private Spelling() {
    try {
      String dictStr = new String(Files.readAllBytes(dictionaryFile))
          .toLowerCase()
          .replaceAll("[^a-z ]", "");
      Stream.of(dictStr.split(" ")).forEach(word -> {
        dict.compute(word, (k, v) -> v == null ? 1 : v + 1);
      });
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  /**
   * Returns a speller.
   */
  public static Spelling getInstance() {
    if  (instance != null) {
      return instance;
    }
    instance = new Spelling();
    return instance;
  }

  /**
   * This method tries to correct a mispelled word. If no correction happens,
   * then the original input value is returned.
   * @param word the word to be corrected.
   * @return the correct word.
   */
  String correct(String word) {
    if (dict.containsKey(word)) {
      return word;
    }
    Optional<String> e1 = known(edits1(word))
        .max((a, b) -> dict.get(a) - dict.get(b));

    if (e1.isPresent()) {
      return e1.get();
    }
    return word;
  }

  /**
   * Edit using streams.
   *
   * @param word as a final string
   * @return a map
   */
  private Stream<String> edits1(final String word) {
    Stream<String> deletes = IntStream.range(0, word.length())
        .mapToObj((i) -> word.substring(0, i) + word.substring(i + 1));
    Stream<String> replaces =
        IntStream.range(0, word.length()).mapToObj((i) -> i)
        .flatMap((i) -> "abcdefghijklmnopqrstuvwxyz".chars()
        .mapToObj((c) -> word.substring(0, i)
            + (char) c + word.substring(i + 1)));
    Stream<String> inserts =
        IntStream.range(0, word.length() + 1)
        .mapToObj((i) -> i)
        .flatMap((i) -> "abcdefghijklmnopqrstuvwxyz".chars()
        .mapToObj((c) -> word.substring(0, i) + (char) c + word.substring(i)));
    Stream<String> transposes
        = IntStream.range(0, word.length() - 1)
        .mapToObj((i) -> word.substring(0, i) + word.substring(i + 1, i + 2)
            + word.charAt(i) + word.substring(i + 2));
    return Stream.of(deletes, replaces, inserts, transposes).flatMap((x) -> x);
  }

  /**
   * Verify if the stream of strings is in {@link #dict}.
   *
   * @param words stream of strings
   * @return words that contains only string in {@link #dict} too
   */
  private Stream<String> known(Stream<String> words) {
    return words.filter((word) -> dict.containsKey(word));
  }
}

@@ -369,16 +369,17 @@
   /**%0A  
+ 
 * String
@@ -422,32 +422,33 @@
 ictionary file.%0A
+ 
   */%0A  private s
@@ -527,24 +527,280 @@
 xt%22;%0A%0A  /**%0A
+   * String representation of the alphabet.%0A   */%0A  private static final String ALPHABET = %22abcdefghijklmnopqrstuvwxyz%22;%0A%0A  /**%0A   * Regex to match all letters from 'a' to 'z' in a String.%0A   */%0A  private static final String REGEX_A_Z = %22%5B%5Ea-z %5D%22;%0A%0A  /**%0A 
   * The inst
@@ -829,16 +829,17 @@
  class.%0A
+ 
   */%0A  p
@@ -880,16 +880,17 @@
   /**%0A  
+ 
 * Path t
@@ -912,16 +912,17 @@
 y file.%0A
+ 
   */%0A  p
@@ -985,16 +985,21 @@
 ;%0A%0A  /**
+%0A   *
  Diction
@@ -1001,17 +1001,62 @@
 ctionary
-.
+ used in spelling and correction processes.%0A  
  */%0A  pr
@@ -1283,25 +1283,25 @@
 laceAll(
-%22%5B%5Ea-z %5D%22
+REGEX_A_Z
 , %22%22);%0A 
@@ -2563,36 +2563,16 @@
  -%3E 
-%22abcdefghijklmnopqrstuvwxyz%22
+ALPHABET
 .cha
@@ -2803,36 +2803,16 @@
  -%3E 
-%22abcdefghijklmnopqrstuvwxyz%22
+ALPHABET
 .cha

remove hardcoded strings