/**
* 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.vocabulary.attribute;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* Represents information of data-flow views.
* @since 0.9.1
*/
public final class ViewInfo implements Attribute {
private static final ViewInfo FLAT_INSTANCE =
new ViewInfo(ViewKind.FLAT, Collections.emptyList(), Collections.emptyList());
private final ViewKind kind;
private final List<String> grouping;
private final List<Ordering> ordering;
private ViewInfo(ViewKind kind, List<String> grouping, List<Ordering> ordering) {
this.kind = kind;
this.grouping = Collections.unmodifiableList(new ArrayList<>(grouping));
this.ordering = Collections.unmodifiableList(new ArrayList<>(ordering));
}
/**
* Returns an instance of flat view information.
* @return the instance
*/
public static ViewInfo flat() {
return FLAT_INSTANCE;
}
/**
* Creates a new group view information instance from the given grouping term list.
* Each term must start with either {@code =} (grouping), {@code +} (ascendant order), or {@code -} (descendant
* order), and follow its property name.
* @param terms the property terms
* @return the created instance
* @see #getTerms()
*/
public static ViewInfo groupOf(String... terms) {
List<String> grouping = new ArrayList<>();
List<Ordering> ordering = new ArrayList<>();
for (String term : terms) {
if (term.isEmpty()) {
throw new IllegalArgumentException(term);
}
char operator = term.charAt(0);
String name = term.substring(1);
switch (operator) {
case '=':
grouping.add(name);
break;
case '+':
ordering.add(new Ordering(name, Direction.ASCENDANT));
break;
case '-':
ordering.add(new Ordering(name, Direction.DESCENDANT));
break;
default:
throw new IllegalArgumentException(term);
}
}
return new ViewInfo(ViewKind.GROUP, grouping, ordering);
}
/**
* Returns the view kind.
* @return the view kind
*/
public ViewKind getKind() {
return kind;
}
/**
* Returns the property terms.
* Each term must start with either {@code =} (grouping), {@code +} (ascendant order), or {@code -} (descendant
* order), and follow its property name.
* @return the property terms
* @see #groupOf(String...)
*/
public List<String> getTerms() {
List<String> results = new ArrayList<>();
results.addAll(getGrouping());
results.addAll(getOrdering().stream()
.map(o -> o.getDirection().getOperator() + o.getPropertyName())
.collect(Collectors.toList()));
return results;
}
/**
* Returns the grouping properties.
* @return the grouping properties
*/
public List<String> getGrouping() {
return grouping;
}
/**
* Returns the sort expression in each group.
* @return the sort expression
*/
public List<Ordering> getOrdering() {
return ordering;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Objects.hashCode(kind);
result = prime * result + Objects.hashCode(grouping);
result = prime * result + Objects.hashCode(ordering);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
ViewInfo other = (ViewInfo) obj;
if (!Objects.equals(kind, other.kind)) {
return false;
}
if (!Objects.equals(grouping, other.grouping)) {
return false;
}
if (!Objects.equals(ordering, other.ordering)) {
return false;
}
return true;
}
@Override
public String toString() {
switch (kind) {
case FLAT:
return "PlainView"; //$NON-NLS-1$
case GROUP: {
List<String> elements = new ArrayList<>();
for (String name : grouping) {
elements.add(String.format("=%s", name)); //$NON-NLS-1$
}
for (Ordering order : ordering) {
elements.add(order.toString());
}
return MessageFormat.format(
"GroupView{0}", //$NON-NLS-1$
elements);
}
default:
return "UnknownView"; //$NON-NLS-1$
}
}
/**
* Represents a kind of view.
* @since 0.9.1
*/
public enum ViewKind {
/**
* Represents a plain {@code View}.
*/
FLAT,
/**
* Represents a {@code GroupView}.
*/
GROUP,
}
/**
* Represents an ordering atom.
* @since 0.9.1
*/
public static final class Ordering {
private final String propertyName;
private final Direction direction;
/**
* Creates new instance.
* @param propertyName the property name
* @param direction the ordering direction
*/
public Ordering(String propertyName, Direction direction) {
this.propertyName = propertyName;
this.direction = direction;
}
/**
* Returns the property name.
* @return the property name
*/
public String getPropertyName() {
return propertyName;
}
/**
* Returns the ordering direction.
* @return the ordering direction
*/
public Direction getDirection() {
return direction;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Objects.hashCode(direction);
result = prime * result + Objects.hashCode(propertyName);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Ordering other = (Ordering) obj;
if (!Objects.equals(direction, other.direction)) {
return false;
}
if (!Objects.equals(propertyName, other.propertyName)) {
return false;
}
return true;
}
@Override
public String toString() {
return MessageFormat.format(
"{1}{0}", //$NON-NLS-1$
propertyName,
direction);
}
}
/**
* Represents a kind of ordering direction.
* @since 0.9.1
*/
public enum Direction {
/**
* Ascendant order.
*/
ASCENDANT("+"), //$NON-NLS-1$
/**
* Descendant order.
*/
DESCENDANT("-"), //$NON-NLS-1$
;
private final String operator;
Direction(String symbol) {
this.operator = symbol;
}
/**
* Returns the direction operator.
* @return the direction operator
*/
public String getOperator() {
return operator;
}
@Override
public String toString() {
return getOperator();
}
}
}