package models.terms;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import com.google.common.collect.TreeMultiset;
import exceptions.SyntaxException;
import lombok.Getter;
import models.Position;
@Getter
public class Dependency extends RDLTerm{
private RDLTerm dependingTerm;
private TreeMultiset<EvaluatableTerm> dependedTerms;
public Dependency(RDLTerm dependingTerm, List<? extends EvaluatableTerm> dependedTerms) {
super(dependedTerms.iterator().next().getOrder(), dependingTerm.getSize() + dependedTerms.stream().mapToInt(v -> v.size).sum());
this.dependingTerm = dependingTerm;
this.dependedTerms = TreeMultiset.create(dependedTerms);
this.addChild(dependingTerm);
if (dependingTerm.getTermOrder() > getOrder()) {
throw new SyntaxException("dependingTerm's order must be less than " + (getOrder() + 1) + ", but " + dependingTerm + "'s order is " + dependingTerm.getOrder());
}
for (EvaluatableTerm dependedTerm: dependedTerms) {
this.addChild(dependedTerm);
if (dependedTerm.getTermOrder() != getOrder()) {
throw new SyntaxException(dependedTerm + " order is not " + getOrder());
}
}
}
public Dependency(RDLTerm dependingTerm, TreeMultiset<EvaluatableTerm> dependedTerms) {
this(dependingTerm, new ArrayList<>(dependedTerms));
}
public Dependency(RDLTerm dependingTerm, EvaluatableTerm ...dependedTerms) {
this(dependingTerm, Arrays.asList(dependedTerms));
}
@Override
public Dependency getDependency() {
return this;
}
@Override
public RDLTerm replace(Position targetPosition, RDLTerm term, Position curPosition) {
if (targetPosition.equals(curPosition)) {
return term;
} else {
int nextPath = targetPosition.getPath(curPosition.size());
if (nextPath == 0) {
return new Dependency(dependingTerm.replace(targetPosition, term, curPosition.addPath(nextPath)), this.dependedTerms);
} else {
List<EvaluatableTerm> dependedTerms = new ArrayList<>();
for (int i = 1; i < getChildren().size(); i++) {
if (i == nextPath) {
dependedTerms.add((EvaluatableTerm) ((RDLTerm) getChild(i)).replace(targetPosition, term, curPosition.addPath(i)));
} else {
dependedTerms.add((EvaluatableTerm) getChild(i));
}
}
return new Dependency(dependingTerm, dependedTerms);
}
}
}
@Override
public int getMaxIndex() {
return 1 + dependedTerms.size();
}
@Override
public int getMaxDepth() {
int result = dependingTerm.getMaxDepth();
if (! (dependingTerm instanceof Resource || dependingTerm instanceof ResourceConstant)) {
result++;
}
for (RDLTerm dependedTerm : dependedTerms) {
int dependedTermDepth = dependedTerm.getMaxDepth();
if (! (dependedTerm instanceof Resource || dependedTerm instanceof ResourceConstant)) {
dependedTermDepth++;
}
result = Math.max(result, dependedTermDepth);
}
return result;
}
@Override
public int getTermOrder() {
return getOrder() - 1;
}
public boolean isDependeingTermEvaluatable() {
return dependingTerm instanceof EvaluatableTerm;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(dependingTerm.toTermString());
sb.append(" : ");
sb.append(dependedTerms.stream().map(RDLTerm::toString).collect(Collectors.joining(", ")));
return sb.toString();
}
@Override
public String toStringWithOrder() {
StringBuilder sb = new StringBuilder();
sb.append(dependingTerm.toStringWithOrder());
sb.append(" : ");
sb.append(dependedTerms.stream().map(RDLTerm::toStringWithOrder).collect(Collectors.joining(", ")));
return sb.toString() + "(" + order + ")";
}
@Override
public String toTermString() {
return "[" + toString() + "]";
}
@Override
public boolean equals(Object another) {
if(! (another instanceof Dependency)) {
return false;
}
Dependency anotherDep = (Dependency) another;
return anotherDep.getDependingTerm().equals(dependingTerm)
&& anotherDep.getDependedTerms().equals(dependedTerms);
}
@Override
public int hashCode() {
return ("Dep" + toString()).hashCode();
}
@Override
public Object clone() {
List<EvaluatableTerm> newTerms = new ArrayList<>();
for (EvaluatableTerm term: this.dependedTerms) {
newTerms.add((EvaluatableTerm) term.clone());
}
return new Dependency((RDLTerm) dependingTerm.clone(), newTerms);
}
}