package com.parship.roperty;

import com.parship.commons.util.Ensure;

import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern;


/**
 * @author mfinsterwalder
 * @since 2013-03-26 09:18
 */
public class KeyValues {

	private static class DomainPattern implements Comparable<DomainPattern> {
		private final Pattern pattern;
		private final int ordering;
		private final Object value;

		public DomainPattern(final String domainPattern, final int order, Object value) {
			Ensure.notNull(domainPattern, "domainPattern");
			String patternStr = domainPattern.replaceAll("\\|", "\\\\|").replaceAll("\\*", "[^|]*");
			patternStr += ".*";
			this.pattern = Pattern.compile(patternStr);
			this.ordering = order;
			this.value = value;
		}

		@Override
		public int compareTo(final DomainPattern other) {
			int order = this.ordering - other.ordering;
			if (order == 0) {
				return pattern.toString().compareTo(other.pattern.toString());
			}
			return order;
		}

		@Override
		public String toString() {
			return "DomainPattern{" +
				"pattern=" + pattern +
				", ordering=" + ordering +
				", value=" + value +
				'}';
		}
	}

	private Set<DomainPattern> patterns = new TreeSet<>();

	public KeyValues() {
		this("[value undefined]");
	}

	public KeyValues(Object value) {
		Ensure.notNull(value, "value");
		put(value);
	}

	public void put(Object value, String... domains) {
		Ensure.notNull(domains, "domain");
		Ensure.notNull(value, "value");
		createAndAddDomainPattern(value, domains);
	}

	private void createAndAddDomainPattern(final Object value, final String[] domains) {
		int order = 1;
		if (domains.length == 0) {
			addDomainPattern("", order, value);
			return;
		}
		StringBuilder builder = new StringBuilder();
		int i = 0;
		for (String domain : domains) {
			i++;
			appendSeparatorIfNeeded(builder);
			if (!"*".equals(domain)) {
				order = order | (int) Math.pow(2, i);
			}
			builder.append(domain);
		}
		addDomainPattern(builder.toString(), order, value);
	}

	private void appendSeparatorIfNeeded(final StringBuilder builder) {
		if (builder.length() > 0) {
			builder.append("|");
		}
	}

	private void addDomainPattern(final String pattern, final int order, final Object value) {
		DomainPattern domainPattern = new DomainPattern(pattern, order, value);
		patterns.remove(domainPattern);
		patterns.add(domainPattern);
	}

	private String buildDomain(final Iterable<String> domains, final Resolver resolver) {
		StringBuilder builder = new StringBuilder();
		for (String domain : domains) {
			appendSeparatorIfNeeded(builder);
			builder.append(resolver.getDomainValue(domain));
		}
		return builder.toString();
	}

	public <T> T get(List<String> domains, final Resolver resolver) {
		T value = null;
		for (DomainPattern pattern : patterns) {
			String domainStr = buildDomain(domains, resolver);
			if (pattern.pattern.matcher(domainStr).matches()) {
				value = (T)pattern.value;
			}
		}
		return value;
//		if (resolver == null) {
//			return value;
//		}
//		StringBuilder builder = new StringBuilder();
//		for (String domain : domains) {
//			if (builder.length() > 0) {
//				builder.append("|");
//			} domain1|domain2|domain3
//			String domainValue = resolver.getDomainValue(domain);
//			Ensure.notEmpty(domainValue, "domainValue");
//			builder.append(domainValue);
//			T overriddenValue = (T)values.get(builder.toString());
//			if (overriddenValue != null) {
//				value = overriddenValue;
//			}
//		}
//		return value;
	}

	@Override
	public String toString() {
		return "KeyValues{" +
			"patterns=" + patterns +
			'}';
	}
}

@@ -347,31 +347,30 @@
 e final 
-Pattern
+String
  pattern
 ;%0A%09%09priv
@@ -361,16 +361,19 @@
  pattern
+Str
 ;%0A%09%09priv
@@ -562,16 +562,51 @@
 tern%22);%0A
+%09%09%09Ensure.notNull(value, %22value%22);%0A
 %09%09%09Strin
@@ -731,38 +731,27 @@
 tern
- = Pattern.compile(p
+Str = domainP
 attern
-Str)
 ;%0A%09%09
@@ -945,23 +945,28 @@
 %09return 
-p
+getP
 attern
+()
 .toStrin
@@ -985,23 +985,28 @@
 o(other.
-p
+getP
 attern
+()
 .toStrin
@@ -1125,23 +1125,28 @@
 ern=%22 + 
-p
+getP
 attern
+()
  +%0A%09%09%09%09%22
@@ -1196,16 +1196,16 @@
 value +%0A
-
 %09%09%09%09'%7D';
@@ -1204,24 +1204,101 @@
 %09%09%09%09'%7D';%0A%09%09%7D
+%0A%0A%09%09private Pattern getPattern() %7B%0A%09%09%09return Pattern.compile(patternStr);%0A%09%09%7D
 %0A%09%7D%0A%0A%09privat
@@ -3008,23 +3008,28 @@
 pattern.
-p
+getP
 attern
+()
 .matcher

store Patterns as Strings and not as Patterns and compile Patterns on the fly