package io.monokkel.core.utils;
import com.google.common.base.CharMatcher;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.stream.Collectors;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Lists.newArrayList;
/**
* Created by tarjei on 20/09/14.
*/
public class CleanerFunction implements MapTransformationFunction<String,Object>{
public static final String VIM_SEARCH_AND_REPLACE_PATTERN = "(?=.*/.*/g)s/.*";
private Logger log = LoggerFactory.getLogger(CleanerFunction.class);
public static final char REPLACEMENT_WHITESPACE = ' ';
@Override
public Object transform(final String key, final Object value, final Map<String, Object> transformationMap) {
final Set<Map.Entry<String, Object>> expressionEntries = transformationMap.entrySet();
return value instanceof String ? cleanStringWithKey(key,value,expressionEntries): value;
}
private Object cleanStringWithKey(final String key, final Object value, final Set<Map.Entry<String, Object>> expressionEntries) {
String castedValue = value.toString();
// Regular expressions do not match on char whitespaces ascii < 39
// This is therefore a hack!
final String whiteSpaceRemovedString = CharMatcher.WHITESPACE.collapseFrom(castedValue, REPLACEMENT_WHITESPACE);
final String extractedExpression = findAllSingleExpressionsThatMatchesKey(key, expressionEntries);
// Filter will remove all none String elements
// Arrays with subobjects will not work
final List<String> expressions = newArrayList(filter(findAllMultiExpressionThatMatchesKey(key, expressionEntries), String.class));
if(!StringUtils.isEmpty(extractedExpression)) {
return replaceByExpressionOrVimReplace(whiteSpaceRemovedString, extractedExpression);
} if(expressions.size() > 1){
return expressions.stream().reduce(whiteSpaceRemovedString, this::replaceByExpressionOrVimReplace);
} else {
return whiteSpaceRemovedString;
}
}
private String replaceByExpressionOrVimReplace(String s, String extractedExpression) {
log.debug("Clean {} with expression {}",s,extractedExpression);
if(extractedExpression.matches(VIM_SEARCH_AND_REPLACE_PATTERN)){
final List<String> expressionSplit = Arrays.asList(extractedExpression.split("/", 5));
List<String> expressionList = splitVimSearchIntoIndividualExpressions(expressionSplit);
if(expressionList.size() == 2){
return s.replaceAll(expressionList.get(0),expressionList.get(1));
} else {
log.warn("Failed to parse expression {}. Please make sure that it is in the format s/text/rext/g",extractedExpression);
return s;
}
} else {
return s.replaceAll(extractedExpression, "");
}
}
private List<String> splitVimSearchIntoIndividualExpressions(List<String> expressionSplit) {
return expressionSplit.stream().filter(split -> !StringUtils.isEmpty(split)).filter(split -> !split.equals("s")).filter(split -> !split.equals("g")).collect(Collectors.toList());
}
private String findAllSingleExpressionsThatMatchesKey(String key, Set<Map.Entry<String, Object>> expressionEntries) {
return expressionEntries.stream()
.filter(expression -> (expression.getKey().equals(key) && expression.getValue() instanceof String))
.map(expression -> (String) expression.getValue()).reduce("", (a, b) -> a + b);
}
private ArrayList findAllMultiExpressionThatMatchesKey(String key, Set<Map.Entry<String, Object>> expressionEntries) {
return expressionEntries.stream().
filter(ex -> (ex.getKey().equals(key) && ex.getValue()
instanceof ArrayList))
.map(ex -> (ArrayList) ex.getValue())
.reduce(newArrayList(), (ex1, ex2) -> newArrayList(concat(ex1, ex2)));
}
}