package models.terms;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeMap;
import com.google.common.collect.TreeMultiset;
import exceptions.SyntaxException;
import lombok.Getter;
import models.Position;
@Getter
public class DependencyTerm extends EvaluatableTerm{
private EvaluatableTerm dependingTerm;
private TreeMap<EvaluatableTerm, TreeMultiset<EvaluatableTerm>> termPairs;
public DependencyTerm(EvaluatableTerm dependingTerm, List<EvaluatableTerm> dependedTerms, List<EvaluatableTerm> argumentTerms) {
super(-1, -1);
if (dependedTerms.size() != argumentTerms.size()) {
throw new SyntaxException("DependedTerms size must equal arugmetTerms size.");
}
this.size = dependingTerm.getSize();
int dependedOrder = dependedTerms.get(0).getOrder();
int maxArgOrder = 0;
this.dependingTerm = dependingTerm;
this.termPairs = new TreeMap<>();
addChild(dependingTerm);
for (int i = 0; i < dependedTerms.size(); i++) {
EvaluatableTerm dependedTerm = dependedTerms.get(i);
EvaluatableTerm argTerm = argumentTerms.get(i);
if (dependedTerm.getOrder() != dependedOrder) {
throw new SyntaxException("All dependedTerm must have the same order");
}
maxArgOrder = Math.max(maxArgOrder, argTerm.getOrder());
termPairs.computeIfAbsent(dependedTerm, k -> TreeMultiset.create()).add(argTerm);
this.size += dependedTerm.getSize();
this.size += argTerm.getSize();
}
if (dependedOrder <= maxArgOrder) {
this.order = maxArgOrder;
} else {
this.order = dependedOrder - 1;
}
for (EvaluatableTerm dependedTerm : termPairs.keySet()) {
for (EvaluatableTerm argTerm : termPairs.get(dependedTerm)) {
addChild(dependedTerm);
addChild(argTerm);
}
}
}
@Deprecated
public DependencyTerm(EvaluatableTerm dependingTerm, List<EvaluatableTerm> terms) {
super(-1, -1);
if (terms.size() % 2 != 0) {
throw new SyntaxException("Args size must be odd.");
}
this.size = dependingTerm.getSize();
int dependedOrder = terms.get(0).getOrder();
int maxArgOrder = 0;
this.dependingTerm = dependingTerm;
this.termPairs = new TreeMap<>();
addChild(dependingTerm);
for (int i = 0; i < terms.size() / 2; i++) {
EvaluatableTerm dependedTerm = terms.get(2 * i);
EvaluatableTerm argTerm = terms.get(2 * i + 1);
if (dependedTerm.getOrder() != dependedOrder) {
throw new SyntaxException("depended term's order not same");
}
maxArgOrder = Math.max(maxArgOrder, argTerm.getOrder());
termPairs.computeIfAbsent(dependedTerm, k -> TreeMultiset.create()).add(argTerm);
this.size += dependedTerm.getSize();
this.size += argTerm.getSize();
}
if (dependedOrder <= maxArgOrder) {
this.order = maxArgOrder;
} else {
this.order = dependedOrder - 1;
}
for (EvaluatableTerm dependedTerm : termPairs.keySet()) {
for (EvaluatableTerm argTerm : termPairs.get(dependedTerm)) {
addChild(dependedTerm);
addChild(argTerm);
}
}
}
public DependencyTerm(EvaluatableTerm dependingTerm, EvaluatableTerm ...terms) {
this(dependingTerm, Arrays.asList(terms));
}
@Override
public Dependency getDependency() {
return new Dependency(dependingTerm, getDependedTerms());
}
public Dependency getNoArgumentDependency() {
if (dependingTerm instanceof DependencyTerm dt) {
return new Dependency(dt.getNoArgumentDependency(), getDependedTerms());
}
return getDependency();
}
public Set<Dependency> requiredDependenciesForDefinitionFormulaLeftHandSide() {
Set<Dependency> result = new HashSet<>();
result.add(getDependency());
if (this.dependingTerm instanceof DependencyTerm dt) {
for (Dependency d : dt.requiredDependenciesForDefinitionFormulaLeftHandSide()) {
result.add(new Dependency(d, getDependedTerms()));
}
}
return result;
}
public Set<Dependency> requiredDependenciesForAdmissible() {
Set<Dependency> result = new HashSet<>();
if (dependingTerm instanceof Resource) {
result.add(getDependency());
} else {
DependencyTerm dt = (DependencyTerm) dependingTerm;
for (Dependency d: dt.requiredDependenciesForAdmissible()) {
DependencyTerm dependingTerm = new DependencyTerm((EvaluatableTerm) d.getDependingTerm(), getDependedTerms(), getArgumentTerms());
List<EvaluatableTerm> dts = new ArrayList<>();
for (EvaluatableTerm te: d.getDependedTerms()) {
dts.add(new DependencyTerm(te, getDependedTerms(), getArgumentTerms()));
}
result.add(new Dependency(dependingTerm, dts));
}
}
return result;
}
@Override
public RDLTerm replace(Position targetPosition, RDLTerm term, Position curPosition) {
if (targetPosition.equals(curPosition)) {
return term;
} else {
int nextPath = targetPosition.getPath(curPosition.size());
List<EvaluatableTerm> children = new ArrayList<>();
for (int i = 1; i < getChildren().size(); i++) {
children.add((EvaluatableTerm) getChild(i));
}
if (nextPath == 0) {
return new DependencyTerm((EvaluatableTerm) dependingTerm.replace(targetPosition, term, curPosition.addPath(nextPath)), children);
} else {
children.set(nextPath - 1, (EvaluatableTerm) children.get(nextPath - 1).replace(targetPosition, term, curPosition.addPath(nextPath)));
return new DependencyTerm(dependingTerm, children);
}
}
}
@Override
public int getMaxIndex() {
int result = 1;
for (EvaluatableTerm dependedTerm : termPairs.keySet()) {
for (EvaluatableTerm argTerm : termPairs.get(dependedTerm)) {
result += 2;
}
}
return result;
}
@Override
public int getMaxDepth() {
int result = 0;
if (dependingTerm instanceof Resource || dependingTerm instanceof ResourceConstant) {
result = dependingTerm.getMaxDepth();
} else {
result = dependingTerm.getMaxDepth() + 1;
}
for (EvaluatableTerm dependedTerm : termPairs.keySet()) {
int dependedTermDepth = dependedTerm.getMaxDepth();
if (! (dependedTerm instanceof Resource || dependedTerm instanceof ResourceConstant)) {
dependedTermDepth++;
}
result = Math.max(result, dependedTermDepth);
for (EvaluatableTerm argTerm : termPairs.get(dependedTerm)) {
int argTermDepth = dependedTerm.getMaxDepth();
if (! (argTerm instanceof Resource || argTerm instanceof ResourceConstant)) {
argTermDepth++;
}
result = Math.max(result, argTermDepth);
}
}
return result;
}
@Override
public boolean isLinearRightNormalized() {
return isLinearRightNormaled(0);
}
@Override
public EvaluatableTerm linearRightNormalize() {
DependencyTerm newTerm = (DependencyTerm) clone();
newTerm.selfLinearRightNormalize();
return newTerm;
}
@Override
public void selfLinearRightNormalize() {
}
private boolean isLinearRightNormaled(int depth) {
return false;
}
public List<EvaluatableTerm> getDependedTerms() {
return new ArrayList<>(termPairs.keySet());
}
public List<EvaluatableTerm> getArgumentTerms() {
List<EvaluatableTerm> result = new ArrayList<>();
for (TreeMultiset<EvaluatableTerm> terms: termPairs.values()) {
result.addAll(terms);
}
return result;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append('[');
sb.append(getDependingTerm().toString());
sb.append(" : ");
for (EvaluatableTerm dependedTerm: termPairs.keySet()) {
for (EvaluatableTerm argTerm: termPairs.get(dependedTerm)) {
sb.append(dependedTerm.toString());
sb.append(" -> ");
sb.append(argTerm.toString());
sb.append(", ");
}
}
sb.deleteCharAt(sb.length() - 1);
sb.deleteCharAt(sb.length() - 1);
sb.append(']');
return sb.toString();
}
@Override
public String toStringWithOrder() {
StringBuilder sb = new StringBuilder();
sb.append('[');
sb.append(getDependingTerm().toStringWithOrder());
sb.append(" : ");
for (EvaluatableTerm dependedTerm: termPairs.keySet()) {
for (EvaluatableTerm argTerm : termPairs.get(dependedTerm)) {
sb.append(dependedTerm.toStringWithOrder());
sb.append(" -> ");
sb.append(argTerm.toStringWithOrder());
sb.append(", ");
}
}
sb.deleteCharAt(sb.length() - 1);
sb.deleteCharAt(sb.length() - 1);
sb.append(']');
sb.append('(');
sb.append(order);
sb.append(')');
return sb.toString();
}
@Override
public boolean equals(Object another) {
if(! (another instanceof DependencyTerm)) {
return false;
}
DependencyTerm term = (DependencyTerm) another;
return dependingTerm.equals(term.getDependingTerm()) &&
termPairs.equals(term.getTermPairs());
}
@Override
public int hashCode() {
return ("DT" + toString()).hashCode();
}
@Override
public Object clone() {
List<EvaluatableTerm> termPairs = new ArrayList<>();
for (EvaluatableTerm dependedTerm : this.termPairs.keySet()) {
for (EvaluatableTerm argTerm: this.termPairs.get(dependedTerm)) {
termPairs.add((EvaluatableTerm) dependedTerm.clone());
termPairs.add((EvaluatableTerm) argTerm.clone());
}
}
return new DependencyTerm(
(EvaluatableTerm) dependingTerm.clone(),
termPairs
);
}
}