package fr.neamar.kiss.normalizer;

import android.util.Pair;

import java.text.Normalizer;

/**
 * String utils to handle accented characters for search and highlighting
 */
public class StringNormalizer {
    /**
     * Return the input string, lower-cased, with all combining characters parts stripped
     * (i.e. `ë` → `e`) and combination characters, consisting of one or more basic characters
     * (i.e. `Ⅱ` → `II`), decomposed into their respective parts
     *
     * @param input string input, with accents and anything else you can think of
     * @return normalized string and list that maps each result string position to its source
     *         string position
     */
    public static Pair<String, int[]> normalizeWithMap(String input) {
        StringBuilder    resultString = new StringBuilder();
        IntSequenceBuilder resultMap    = new IntSequenceBuilder(input.length() * 3 / 2);

        StringBuilder charBuffer = new StringBuilder(2);

        int inputOffset = 0, inputLength = input.length();
        while(inputOffset < inputLength) {
            int inputChar = input.codePointAt(inputOffset);

            // Decompose codepoint at given position
            charBuffer.append(Character.toChars(inputChar));
            String decomposedCharString = Normalizer.normalize(charBuffer, Normalizer.Form.NFKD);
            charBuffer.delete(0, charBuffer.length());

            // `inputChar` codepoint may be decomposed to four (or maybe even more) new code points
            int decomposedCharOffset = 0;
            while(decomposedCharOffset < decomposedCharString.length()) {
                int resultChar = decomposedCharString.codePointAt(decomposedCharOffset);

                // Only process characters that are not combining Unicode
                // characters. This way all the decomposed diacritical marks
                // (and some other not-that-important modifiers), that were
                // part of the original string or produced by the NFKD
                // normalizer above, disappear.
                switch(Character.getType(resultChar)) {
                    case Character.NON_SPACING_MARK:
                    case Character.COMBINING_SPACING_MARK:
                        // Some combining character found
                        break;

                    default:
                        resultString.appendCodePoint(Character.toLowerCase(resultChar));
                        resultMap.add(inputOffset);
                }

                decomposedCharOffset += Character.charCount(resultChar);
            }

            inputOffset += Character.charCount(inputChar);
        }

        // Since we stripped all combining Unicode characters in the
        // previous while-loop there should be no combining character
        // remaining in the string and the composed and decomposed
        // versions of the string should be equivalent. This also means
        // we do not need to convert the string back to composed Unicode
        // before returning it.
        return new Pair<>(resultString.toString(), resultMap.toArray());
    }


    /**
     * Normalize input string
     * 
     * @param input string input, with accents and anything else you can think of
     * @return normalized string
     */
    public static String normalize(String input) {
        return StringNormalizer.normalizeWithMap(input).first;
    }
}

@@ -219,50 +219,203 @@
   * 
-Return the input string, lower-cased, with
+Make the given string easier to compare by performing a number of simplifications on it%0A     *%0A     *  1. Decompose combination characters into their respective parts (see below)%0A     *  2. Strip
  all
@@ -438,184 +438,653 @@
 cter
-s parts stripped%0A     * (i.e. %60%C3%AB%60 %E2%86%92 %60e%60) and combination characters, consist
+ marks (see below)%0A     *  3. Strip some other common-but-not-very-useful characters (such as dashes)%0A     *  4. Lower-case the string%0A     *%0A     * Combination characters are characters that (essentially) have the same mean
 ing 
-of
+as
  one or
- more basic characters%0A     * (i.e. %60%E2%85%A1%60 %E2%86%92 %60II%60), decomposed into their respective parts
+%0A     * more other, more common, characters. Examples for these include:%0A     * Roman numerals (%60%E2%85%A1%60 %E2%86%92 %60II%60) and half-width katakana (%60%EF%BE%90%60 %E2%86%92 %60%E3%83%9F%60)%0A     *%0A     * Combining character marks are diacritics and other extra strokes that are often found as%0A     * part of many characters in non-English roman scripts. Examples for these include:%0A     * Diaereses (%60%C3%AB%60 %E2%86%92 %60e%60), acutes (%60%C3%A1%60 %E2%86%92 %60a%60) and macrons (%60%C5%8D%60 %E2%86%92 %60o%60)
 %0A   
@@ -1472,18 +1472,16 @@
 ultMap  
-  
 = new In
@@ -2341,334 +2341,249 @@
  // 
-Only process characters that are not combining Unicode%0A                // characters. This way all the decomposed diacritical marks%0A                // (and some other not-that-important modifiers), that were%0A                // part of the original string or produced by the NFKD%0A                // normalizer above, disappear.
+Skip characters for some unicode character classes, including:%0A                //  * combining characters produced by the NFKD normalizer above%0A                //  * dashes%0A                // See the method's description for more information
 %0A   
@@ -2837,16 +2837,164 @@
 break;%0A%0A
+                    case Character.DASH_PUNCTUATION:%0A                        // Some other unwanted character found%0A                        break;%0A%0A
         
@@ -3815,38 +3815,163 @@
   * 
-Normalize input s
+Make the given string easier to compare by performing a number of simplifications on it%0A     *%0A     * @see StringNormalizer#normalizeWithMap(S
 tring
+)
 %0A     *
- 
 %0A   

Update StringNormalizer to strip dashes from normalized strings (fixes #261)