package hdgl.db.query.convert;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import hdgl.db.query.condition.AbstractCondition;
import hdgl.db.query.condition.Conjunction;;
public class SortConditions {
static <TK,TV> void addToMultiMap(Map<TK, Set<TV>> map,TK key, TV value){
Set<TV> set;
if(map.containsKey(key)){
set=map.get(key);
}else{
set=new HashSet<TV>();
map.put(key, set);
}
set.add(value);
}
public static AbstractCondition[] sortConditions(AbstractCondition[] in){
Map<AbstractCondition, Set<AbstractCondition>> coverMap = new HashMap<AbstractCondition, Set<AbstractCondition>>();
Set<AbstractCondition> all = new HashSet<AbstractCondition>();
for(int i = 0; i<in.length; i++){
all.add(in[i]);
for (int j = i + 1; j < in.length; j++) {
AbstractCondition c1 = in[i];
AbstractCondition c2 = in[j];
switch (c1.relationship(c2)) {
case Require:
addToMultiMap(coverMap, c2, c1);
break;
case Sufficient:
addToMultiMap(coverMap, c1, c2);
break;
default:
break;
}
}
}
Set<AbstractCondition> uniqueConditions = new HashSet<AbstractCondition>();
for (AbstractCondition abstractCondition : in) {
if(!coverMap.containsKey(abstractCondition)){
uniqueConditions.add(abstractCondition);
}
}
AbstractCondition[] unique = uniqueConditions.toArray(new AbstractCondition[0]);
ArrayList<Set<AbstractCondition>> uniqueCombinedConditions = new ArrayList<Set<AbstractCondition>>();
outer:for (Set<AbstractCondition> combineConditions : selection(unique)) {
if(combineConditions.size()<=1){
continue;
}
for(AbstractCondition c1:combineConditions){
for(AbstractCondition c2:combineConditions){
if(!c1.equals(c2)){
if(!c1.compatible(c2)){
continue outer;
}
if(c1.require(c2)||c2.require(c1)){
continue outer;
}
}
}
}
uniqueCombinedConditions.add(combineConditions);
}
AbstractCondition[] result2 = topologicalSort(all, coverMap, AbstractCondition.class);
AbstractCondition[] result = new AbstractCondition[uniqueCombinedConditions.size()+result2.length];
for (int i = 0; i < uniqueCombinedConditions.size(); i++) {
result[i] = new Conjunction(uniqueCombinedConditions.get(i).toArray(new AbstractCondition[0]));
}
System.arraycopy(result2, 0, result, uniqueCombinedConditions.size(), result2.length);
return result;
}
@SuppressWarnings("unchecked")
public static <T> Set<T>[] selection(T[] arr){
ArrayList<Set<T>> a = selectionInner(arr,0);
Collections.sort(a, new Comparator<Set<T>>() {
@Override
public int compare(Set<T> o1, Set<T> o2) {
return Integer.valueOf(o2.size()).compareTo(o1.size());
}
});
return a.toArray(new Set[0]);
}
static <T> ArrayList<Set<T>> selectionInner(T[] arr, int startpos){
if(startpos==arr.length-1){
Set<T> c1=new HashSet<T>();
c1.add(arr[startpos]);
Set<T> c2=new HashSet<T>();
ArrayList<Set<T>> res = new ArrayList<Set<T>>();
res.add(c1);
res.add(c2);
return res;
}else{
ArrayList<Set<T>> res = new ArrayList<Set<T>>();
for(Set<T> subset: selectionInner(arr, startpos+1)){
Set<T> c1=new HashSet<T>(subset);
c1.add(arr[startpos]);
Set<T> c2=new HashSet<T>(subset);
res.add(c1);
res.add(c2);
}
return res;
}
}
/**
* Map<T,T> has
* @param cover
* @return
*/
static <T> T[] topologicalSort(Set<T> all, Map<T, Set<T>> cover, Class<T> type){
ArrayList<T> result = new ArrayList<T>();
ArrayList<T> removeList = new ArrayList<T>();
while (!all.isEmpty()) {
T found = null;
for (T t : all) {
if(!cover.keySet().contains(t)){
found = t;
break;
}
}
if(found==null){
throw new IllegalArgumentException("Graph with loops");
}
result.add(found);
all.remove(found);
removeList.clear();
for (Map.Entry<T, Set<T>> t : cover.entrySet()) {
t.getValue().remove(found);
if(t.getValue().size()==0){
removeList.add(t.getKey());
}
}
for (T t : removeList) {
cover.remove(t);
}
}
@SuppressWarnings("unchecked")
T[] foo=(T[]) Array.newInstance(type, 0);
return result.toArray(foo);
}
}