/**
 * 
 */
package es.um.nosql.streaminginference.json2dbschema.process.util;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.lang3.tuple.Pair;

/**
 * @author dsevilla
 *
 */
public class ReferenceMatcher<T>
{
	// List of affixes to check for references
	private static List<String> Affixes =
			Arrays.asList("id", "ptr", "ref", "ids", "refs", "has", "");

	private static List<String> StopChars =
			Arrays.asList("_", ".", "-", "");

	// Unlikely words to appear in a reference
	private static List<String> UnlikelyWords = Arrays.asList("count");

	private Map<String, T> idRegexps;

	public ReferenceMatcher(Stream<Pair<String, T>> stream)
	{		
		// Build the regexp that will allow checking if a field may be a reference
		// to another entity
		idRegexps = stream.flatMap(entry ->
			Affixes.stream().flatMap(affix ->
				Stream.concat(
					// prefix
					StopChars.stream().map(c ->
						Pair.of(("^" + entry.getKey() + c + affix + ".*$").toLowerCase(), entry.getValue())),
					Stream.concat(StopChars.stream().map(c ->
							Pair.of(("^" + affix + c + entry.getKey() + ".*$").toLowerCase(), entry.getValue())),
						// postfix
						Stream.concat(StopChars.stream().filter(c -> !c.isEmpty() || !affix.isEmpty()).map(c ->
								Pair.of(("^.*?" + entry.getKey() + c + affix + "$").toLowerCase(), entry.getValue())),								
									StopChars.stream().filter(c -> !c.isEmpty() || !affix.isEmpty()).map(c ->
										Pair.of(("^.*?" + affix + c + entry.getKey() + "$").toLowerCase(), entry.getValue()))))
				)
			)
		).collect(Collectors.toMap(Pair::getKey, Pair::getValue, (p, q) -> p));
	}

	public Optional<T> maybeMatch(String id)
	{
		if (UnlikelyWords.stream().anyMatch(w -> id.toLowerCase().contains(w)))
			return Optional.<T>empty();

		return Optional.ofNullable(idRegexps.get(id.toLowerCase()));
	}
}

@@ -712,17 +712,39 @@
 String, 
-T
+Stream%3CPair%3CString, T%3E%3E
 %3E idRege
@@ -1690,16 +1690,89 @@
 %09%09)%0A
+%09%09%09%09.map(pair -%3E Pair.of(entry.getKey().toLowerCase(), Stream.of(pair)))%0A
 %09%09%09)%0A%09%09)
 .col
@@ -1767,16 +1767,19 @@
 %09%09%09)%0A%09%09)
+%0A%09%09
 .collect
@@ -1836,17 +1836,34 @@
 , q) -%3E 
-p
+Stream.concat(p,q)
 ));%0A%09%7D%0A%0A
@@ -1907,16 +1907,53 @@
  id)%0A%09%7B%0A
+%09%09String lowerId = id.toLowerCase();%0A
 %09%09if (Un
@@ -1987,32 +1987,23 @@
 ch(w -%3E 
-id.toLowerCase()
+lowerId
 .contain
@@ -2044,69 +2044,352 @@
 ();%0A
+%09%09
 %0A%09%09
-return Optional.ofNullable(idRegexps.get(id.toLowerCase())
+for (String candidate : idRegexps.keySet()) %0A%09%09%7B%0A%09%09%09if (lowerId.contains(candidate)) %0A%09%09%09%7B%0A%09%09%09%09Optional%3CT%3E op = idRegexps%0A%09%09%09%09%09%09.get(candidate)%0A%09%09%09%09%09%09.filter(pair -%3E lowerId%0A%09%09%09%09%09%09%09%09.matches(pair.getKey()))%0A%09%09%09%09%09%09.findFirst()%0A%09%09%09%09%09%09.map(pair -%3E pair.getValue());%0A%09%09%09%09if (op.isPresent())%0A%09%09%09%09%09return op;%0A%09%09%09%7D%0A%09%09%7D%0A%09%09%0A%09%09return Optional.empty(
 );%0A%09

Fix ReferenceMatcher proposal