package models.terms.meta;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import lombok.Getter;
import models.algebra.Expression;
import models.algebra.Symbol;
import models.algebra.Variable;
import models.terms.Dependency;
import models.terms.DependencyTerm;
import models.terms.EvaluatableTerm;
import models.terms.LinearRightNormalizedType;
import models.terms.RDLTerm;
import models.terms.Resource;
@Getter
public abstract class MetaRDLTerm extends RDLTerm {
protected TermType termType;
protected LinearRightNormalizedType linearRightNormalizedType = LinearRightNormalizedType.UNDEFINED;
protected MetaRDLTerm(Symbol symbol, TermType termType, int size) {
super(symbol, -1, size);
this.termType = termType;
if (isResource()) {
linearRightNormalizedType = LinearRightNormalizedType.LINEAR_RIGHT_NORMALIZED;
}
}
public Set<MatchConstraint> isMatchedBy(RDLTerm another) {
return isMatchedBy(another, MatchConstraint.createDefault(), 0);
}
public Set<MatchConstraint> isMatchedBy(RDLTerm another, MatchConstraint constraint) {
return isMatchedBy(another, constraint, 0);
}
public Set<MatchConstraint> isMatchedBy(RDLTerm another, Set<MatchConstraint> constraints) {
return isMatchedBy(another, constraints, 0);
}
protected Set<MatchConstraint> isMatchedBy(RDLTerm another, Set<MatchConstraint> constraints, int depth) {
Set<MatchConstraint> result = new HashSet<>();
for (MatchConstraint constraint : constraints) {
result.addAll(isMatchedBy(another, constraint, depth + 1));
}
return result;
}
abstract protected Set<MatchConstraint> isMatchedBy(RDLTerm another, MatchConstraint constraint, int depth);
public RDLTerm substitute(Map<Variable, RDLTerm> binding) {
return substitute(binding, 0);
}
abstract protected RDLTerm substitute(Map<Variable, RDLTerm> binding, int depth);
public boolean checkTermType(Class<? extends RDLTerm> clazz) {
return clazz.isAssignableFrom(termType.getBaseTermClass());
}
public boolean isVariable() {
return false;
}
public boolean isDependency() {
return checkTermType(Dependency.class);
}
public boolean isEvaluatableTerm() {
return checkTermType(EvaluatableTerm.class);
}
public boolean isDependencyTerm() {
return checkTermType(DependencyTerm.class);
}
public boolean isResource() {
return checkTermType(Resource.class);
}
public void setLinearRightNormalizedType(LinearRightNormalizedType next) {
if (isDependency()) {
return;
}
this.linearRightNormalizedType = next;
}
public Collection<MetaVariable> getAllVariables() {
return getSubTerms(MetaVariable.class).values();
}
protected boolean islinearRightNormalizedMatchedBy(RDLTerm another) {
if (linearRightNormalizedType != LinearRightNormalizedType.UNDEFINED) {
if (another instanceof DependencyTerm) {
if (((DependencyTerm) another).getLinearRightNormalizedType() != linearRightNormalizedType) {
return false;
}
}
else if (another instanceof MetaRDLTerm) {
if (((MetaRDLTerm) another).getLinearRightNormalizedType() != linearRightNormalizedType) {
return false;
}
}
}
return true;
}
@Override
public String toString() {
switch(termType) {
case META_DEPENDENCY:
return "[" + getChild(0).toString() + " : " + getChildren().stream().skip(1).map(Expression::toString).collect(Collectors.joining(",")) + "]";
case META_DEPENDENCY_TERM:
return "[" + getChild(0).toString() + " : " + IntStream.range(0, (getChildren().size() - 1) / 2)
.mapToObj(i -> getChild(i * 2 + 1).toString() + " -> " + getChild(i * 2 + 2)).collect(Collectors.joining(",")) + "]";
default:
return "";
}
}
@Override
public String toStringWithOrder() {
switch(termType) {
case META_DEPENDENCY:
return "[" + ((RDLTerm) getChild(0)).toStringWithOrder() + " : " + ((RDLTerm) getChild(1)).toStringWithOrder() + "]";
case META_DEPENDENCY_LIST:
return "[" + ((RDLTerm) getChild(0)).toStringWithOrder() + "]";
case META_DEPENDENCY_TERM:
return "[" + ((RDLTerm) getChild(0)).toStringWithOrder() + " : "
+ ((RDLTerm) getChild(1)).toStringWithOrder() + " -> " + ((RDLTerm) getChild(2)).toStringWithOrder() + "]";
default:
return "";
}
}
@Override
public boolean equals(Object another) {
if(! (another instanceof MetaRDLTerm)) {
return false;
}
MetaRDLTerm anotherTerm = (MetaRDLTerm) another;
return super.equals(another) && termType == anotherTerm.getTermType();
}
@Override
public int hashCode() {
return (termType.toString() + toStringWithOrder()).hashCode();
}
@Override
public Object clone() {
return null;
}
protected static enum TermType {
META_RDL_TERM(RDLTerm.class),
META_DEPENDENCY(Dependency.class),
META_DEPENDENCY_LIST(Dependency.class),
META_DEPENDENCY_VARIABLE(Dependency.class),
META_DEPENDENCY_TERM(DependencyTerm.class),
META_DEPENDENCY_TERM_VARIABLE(DependencyTerm.class),
META_EVALUATABLE_TERM_VARIABLE(EvaluatableTerm.class),
META_RESOURCE_VARIABLE(Resource.class);
@Getter
private Class<?> baseTermClass;
private TermType(Class<?> clazz) {
this.baseTermClass = clazz;
}
}
}