/**
* Copyright 2011-2017 Asakusa Framework Team.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.asakusafw.testdriver.loader;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.asakusafw.testdriver.core.DataModelDefinition;
import com.asakusafw.testdriver.core.DataModelReflection;
import com.asakusafw.testdriver.core.PropertyName;
import com.asakusafw.testdriver.core.PropertyType;
final class Util {
private static final Pattern PATTERN_ORDER = Pattern.compile(
"(\\w+)" // 1 - asc //$NON-NLS-1$
+ "|" + "(\\+\\s*(\\w+))" // 3 - asc //$NON-NLS-1$ //$NON-NLS-2$
+ "|" + "(-\\s*(\\w+))" // 5 - desc //$NON-NLS-1$ //$NON-NLS-2$
+ "|" + "((\\w+)\\s+ASC)" // 7 - asc //$NON-NLS-1$ //$NON-NLS-2$
+ "|" + "((\\w+)\\s+DESC)" // 9 - desc //$NON-NLS-1$ //$NON-NLS-2$
+ "", //$NON-NLS-1$
Pattern.CASE_INSENSITIVE);
private static final Map<Integer, Direction> ORDER_GROUP_DIRECTIONS;
static {
Map<Integer, Direction> map = new LinkedHashMap<>();
map.put(1, Direction.ASCENDANT);
map.put(3, Direction.ASCENDANT);
map.put(5, Direction.DESCENDANT);
map.put(7, Direction.ASCENDANT);
map.put(9, Direction.DESCENDANT);
ORDER_GROUP_DIRECTIONS = map;
}
private Util() {
return;
}
static void checkProperty(DataModelDefinition<?> definition, PropertyName name) {
PropertyType type = definition.getType(name);
if (type == null) {
throw new IllegalArgumentException(MessageFormat.format(
"property \"{1}\" is not defined in {0}",
definition.getClass().getName(),
name));
}
}
static <T> Comparator<DataModelReflection> toComparator(
DataModelDefinition<T> definition,
String... terms) {
if (terms.length == 0) {
return null;
}
List<Comparator<DataModelReflection>> subs = new ArrayList<>();
for (String term : terms) {
subs.add(toComparator(definition, term));
}
return (a, b) -> {
for (Comparator<DataModelReflection> sub : subs) {
int diff = sub.compare(a, b);
if (diff != 0) {
return diff;
}
}
return 0;
};
}
@SuppressWarnings("unchecked")
private static <T> Comparator<DataModelReflection> toComparator(DataModelDefinition<T> definition, String term) {
if (term.isEmpty()) {
throw new IllegalArgumentException("order term must not be empty"); //$NON-NLS-1$
}
Ordering order = parseOrder(term);
checkProperty(definition, order.propertyName);
Comparator<DataModelReflection> comparator = (a, b) -> {
Comparable<Object> aValue = (Comparable<Object>) a.getValue(order.propertyName);
Comparable<Object> bValue = (Comparable<Object>) b.getValue(order.propertyName);
if (aValue == null) {
if (bValue == null) {
return 0;
} else {
return -1;
}
} else if (bValue == null) {
return +1;
}
return aValue.compareTo(bValue);
};
if (order.direction == Direction.ASCENDANT) {
return comparator;
} else {
return comparator.reversed();
}
}
static <T> Comparator<DataModelReflection> toComparator(
DataModelDefinition<T> definition,
Comparator<? super T> objectComparator) {
if (objectComparator == null) {
return null;
}
return (a, b) -> {
T aObj = definition.toObject(a);
T bObj = definition.toObject(b);
return objectComparator.compare(aObj, bObj);
};
}
static Ordering parseOrder(String expression) {
Matcher matcher = PATTERN_ORDER.matcher(expression);
if (matcher.matches() == false) {
throw new IllegalArgumentException(MessageFormat.format(
"invalid group ordering expression: {0}",
expression));
}
String name = null;
Direction direction = null;
for (Map.Entry<Integer, Direction> entry : ORDER_GROUP_DIRECTIONS.entrySet()) {
int index = entry.getKey();
String s = matcher.group(index);
if (s != null) {
name = s;
direction = entry.getValue();
break;
}
}
assert name != null;
assert direction != null;
return new Ordering(PropertyName.parse(name), direction);
}
private static final class Ordering {
final PropertyName propertyName;
final Direction direction;
Ordering(PropertyName propertyName, Direction direction) {
this.propertyName = propertyName;
this.direction = direction;
}
}
private enum Direction {
ASCENDANT,
DESCENDANT,
}
}