package eu.project.ttc.api;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import eu.project.ttc.engines.cleaner.TermProperty;
import eu.project.ttc.models.Term;
import eu.project.ttc.models.TermIndex;
public class Traverser {
private static final String ERR_EMPTY_STRING_NOT_ALLOWED = "Empty string not allowed";
private static final String ERR_TOO_MANY_ARGUMENTS = "Too many arguments: %s";
private static final String ERR_UNKNOWN_DIRECTION = "Unknown direction: ";
public static enum Direction {
ASC, DESC;
public static Direction fromString(String string) {
switch (string.toLowerCase()) {
case "asc":
return ASC;
case "desc":
return DESC;
default:
throw new IllegalArgumentException(ERR_UNKNOWN_DIRECTION + string);
}
}
@Override
public String toString() {
return super.toString().toLowerCase();
}
}
public static class Ordering {
private TermProperty property;
private Direction direction;
public Ordering(TermProperty property, Direction direction) {
super();
this.property = property;
this.direction = direction;
}
public static Ordering fromString(String string) {
List<String> strings = Splitter.on(" ").splitToList(string.trim());
Preconditions.checkArgument(strings.size() > 0, ERR_EMPTY_STRING_NOT_ALLOWED);
Preconditions.checkArgument(strings.size() <= 2, ERR_TOO_MANY_ARGUMENTS, string);
TermProperty property = TermProperty.forName(strings.get(0));
Direction direction = strings.size() == 2 ? Direction.fromString(strings.get(1)) : Direction.ASC;
return new Ordering(property, direction);
}
@Override
public String toString() {
return String.format("%s %s", property.getPropertyName(), direction);
}
}
private List<Ordering> orderings;
public Traverser(List<Ordering> orderings) {
super();
this.orderings = orderings;
}
private static final List<Ordering> DEFAULT_ORDERING = Lists.newArrayList(
new Ordering(TermProperty.RANK, Direction.ASC),
new Ordering(TermProperty.SPECIFICITY, Direction.DESC),
new Ordering(TermProperty.FREQUENCY, Direction.DESC),
new Ordering(TermProperty.GROUPING_KEY, Direction.ASC)
);
public static Traverser create() {
return new Traverser(DEFAULT_ORDERING);
}
public static Traverser by(String string) {
Preconditions.checkArgument(!string.trim().isEmpty(), ERR_EMPTY_STRING_NOT_ALLOWED);
return by(
Splitter.on(",").splitToList(string).stream()
.filter(str -> {
Preconditions.checkArgument(!str.trim().isEmpty(), ERR_EMPTY_STRING_NOT_ALLOWED);
return true;
})
.map(str -> {
return Ordering.fromString(str);
}).collect(Collectors.toList())
);
}
public static Traverser by(Iterator<Ordering> orderings) {
return by(Lists.newArrayList(orderings));
}
public static Traverser by(List<Ordering> orderings) {
orderings.addAll(DEFAULT_ORDERING);
return new Traverser(orderings);
}
public static Traverser by(Ordering... orderings) {
return by(Lists.newArrayList(orderings));
}
public Iterator<Term> iterator(TermIndex termIndex) {
List<Term> terms = toList(termIndex);
return terms.iterator();
}
public Stream<Term> stream(TermIndex termIndex) {
return toList(termIndex).stream();
}
public List<Term> toList(TermIndex termIndex) {
List<Term> terms = Lists.newArrayList(termIndex.getTerms());
Collections.sort(terms, toComparator(termIndex));
return terms;
}
public Comparator<Term> toComparator(final TermIndex termIndex) {
return new Comparator<Term>() {
@Override
public int compare(Term o1, Term o2) {
for(Ordering ordering:orderings) {
int compare = ordering.property.compare(termIndex, o1, o2);
if(compare < 0)
return ordering.direction == Direction.ASC ? -1 : 1;
else if(compare > 0)
return ordering.direction == Direction.ASC ? 1 : -1;
}
return 0;
}
};
}
@Override
public String toString() {
return Joiner.on(", ").join(orderings);
}
}