package com.airbnb.aerosolve.core.transforms;

import com.airbnb.aerosolve.core.FeatureVector;
import com.airbnb.aerosolve.core.util.Util;

import java.text.Normalizer;
import java.util.Map;
import java.util.Set;

import com.typesafe.config.Config;

/**
 * Normalizes strings to UTF-8 NFC, NFD, NFKC or NFKD form (NFD by default)
 * "field1" specifies the key of the feature
 * "normalization_form" optionally specifies whether to use NFC, NFD, NFKC or NFKD form
 */
public class NormalizeUtf8Transform implements Transform {
  public static final Normalizer.Form DEFAULT_NORMALIZATION_FORM = Normalizer.Form.NFD;

  private String fieldName1;
  private Normalizer.Form normalizationForm;
  private String outputName;

  @Override
  public void configure(Config config, String key) {
    fieldName1 = config.getString(key + ".field1");
    String normalizationFormString = DEFAULT_NORMALIZATION_FORM.name();
    if (config.hasPath(key + ".normalization_form")) {
      normalizationFormString = config.getString(key + ".normalization_form");
    }
    if (normalizationFormString.equalsIgnoreCase("NFC")) {
      normalizationForm = Normalizer.Form.NFC;
    } else if (normalizationFormString.equalsIgnoreCase("NFD")) {
      normalizationForm = Normalizer.Form.NFD;
    } else if (normalizationFormString.equalsIgnoreCase("NFKC")) {
      normalizationForm = Normalizer.Form.NFKC;
    } else if (normalizationFormString.equalsIgnoreCase("NFKD")) {
      normalizationForm = Normalizer.Form.NFKD;
    } else {
      normalizationForm = DEFAULT_NORMALIZATION_FORM;
    }
    outputName = config.getString(key + ".output");
  }

  @Override
  public void doTransform(FeatureVector featureVector) {
    Map<String, Set<String>> stringFeatures = featureVector.getStringFeatures();
    if (stringFeatures == null) {
      return;
    }

    Set<String> feature1 = stringFeatures.get(fieldName1);
    if (feature1 == null) {
      return;
    }

    Set<String> output = Util.getOrCreateStringFeature(outputName, stringFeatures);

    for (String rawString : feature1) {
      if (rawString == null) continue;
      String normalizedString = Normalizer.normalize(rawString, normalizationForm);
      output.add(normalizedString);
    }
  }
}

@@ -162,16 +162,43 @@
 alizer;%0A
+import java.util.Iterator;%0A
 import j
@@ -211,16 +211,16 @@
 il.Map;%0A
-
 import j
@@ -483,16 +483,156 @@
 KD form%0A
+ * %22output%22 optionally specifies the key of the output feature, if it is not given the transform%0A * overwrites / replaces the input feature%0A
  */%0Apubl
@@ -1726,24 +1726,69 @@
 FORM;%0A    %7D%0A
+    if (config.hasPath(key + %22.output%22)) %7B%0A  
     outputNa
@@ -1827,16 +1827,66 @@
 tput%22);%0A
+    %7D else %7B%0A      outputName = fieldName1;%0A    %7D%0A
   %7D%0A%0A  @
@@ -2293,38 +2293,122 @@
 or (
-String rawString : feature1) %7B
+Iterator%3CString%3E iterator = feature1.iterator(); iterator.hasNext();) %7B%0A      String rawString = iterator.next();%0A
 %0A   
@@ -2424,25 +2424,25 @@
 wString 
-=
+!
 = null) 
 continue
@@ -2437,18 +2437,12 @@
 ll) 
-continue;%0A
+%7B%0A  
     
@@ -2523,24 +2523,26 @@
 orm);%0A      
+  
 output.add(n
@@ -2559,16 +2559,185 @@
 tring);%0A
+      %7D%0A%0A      // Check reference equality to determine whether the output should overwrite the input%0A      if (output == feature1) %7B%0A        iterator.remove();%0A      %7D%0A
     %7D%0A  

Make output optional for NormalizeUtf8Transform