package models.terms.meta;
import com.google.common.collect.TreeMultiset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import exceptions.SubstituteFailedException;
import exceptions.SyntaxException;
import models.Position;
import models.algebra.Variable;
import models.terms.RDLTerm;
public class MetaDynamicDependencyTerm extends MetaDependencyTerm implements MetaDynamicTerm{
private final MetaTermGenerator generator;
public MetaDynamicDependencyTerm (MetaTermGenerator generator) {
this.generator = generator;
}
public MetaDynamicDependencyTerm(MetaTermGenerator generator, List<? extends RDLTerm> terms) {
this.generator = generator;
if (terms.size() != 0 && terms.size() % 2 != 1) {
throw new SyntaxException("");
}
this.dependingTerm = terms.size() > 0 ? terms.get(0) : null;
addChild(dependingTerm);
for (int i = 0; i < (terms.size() - 1) / 2; i++) {
RDLTerm dependedTerm = terms.get(i * 2 + 1);
RDLTerm argTerm = terms.get(i * 2 + 2);
this.termPairs.computeIfAbsent(dependedTerm, k -> TreeMultiset.create()).add(argTerm);
addChild(dependedTerm);
addChild(argTerm);
}
}
public MetaDynamicDependencyTerm(MetaTermGenerator generator, RDLTerm ...terms) {
this(generator, Arrays.asList(terms));
}
@Override
public MetaRDLTerm generate(int depth, int maxIndex, int maxDepth, Map<Object, Object> context) {
if (maxIndex % 2 == 0 && maxIndex <= 2) return null;
RDLTerm dependingTerm;
List<RDLTerm> termPairs = new ArrayList<>();
if (this.dependingTerm != null) {
dependingTerm = this.dependingTerm;
} else {
dependingTerm = generator.generate(0, depth, maxIndex, maxDepth, context);
}
if (maxIndex == 1) {
return (MetaRDLTerm) dependingTerm;
}
int index = 1;
for (RDLTerm dependedTerm : this.termPairs.keySet()) {
for (RDLTerm argTerm : this.termPairs.get(dependedTerm)) {
termPairs.add(dependedTerm);
termPairs.add(argTerm);
index+=2;
}
}
for (int i = 0; i < (maxIndex - index) / 2; i++) {
RDLTerm dependedTerm = generator.generate(i * 2 + index, depth, maxIndex, maxDepth, context);
if (dependedTerm == null) {
break;
}
RDLTerm argTerm = generator.generate(i * 2 + index + 1, depth, maxIndex, maxDepth, context);
if (argTerm == null) {
break;
}
termPairs.add(dependedTerm);
termPairs.add(argTerm);
}
if (termPairs.isEmpty()) {
return (MetaRDLTerm) dependingTerm;
}
return new MetaDependencyTerm(dependingTerm, termPairs);
}
@Override
public MetaRDLTerm allGenerate(int depth, int maxIndex, int maxDepth, Map<Object, Object> context) {
if (maxIndex % 2 == 0 && maxIndex <= 2) return null;
RDLTerm dependingTerm;
List<RDLTerm> termPairs = new ArrayList<>();
if (this.dependingTerm != null) {
dependingTerm = this.dependingTerm;
} else {
dependingTerm = generator.generate(0, depth, maxIndex, maxDepth, context);
}
while (dependingTerm instanceof MetaDynamicTerm dynamicTerm) {
dependingTerm = dynamicTerm.allGenerate(depth + 1, maxIndex, maxDepth, context);
}
if (maxIndex == 1) {
return (MetaRDLTerm) dependingTerm;
}
int index = 1;
for (RDLTerm dependedTerm : this.termPairs.keySet()) {
for (RDLTerm argTerm : this.termPairs.get(dependedTerm)) {
while (dependedTerm instanceof MetaDynamicTerm dynamicTerm) {
dependedTerm = dynamicTerm.allGenerate(depth + 1, maxIndex, maxDepth, context);
}
while (argTerm instanceof MetaDynamicTerm dynamicTerm) {
argTerm = dynamicTerm.allGenerate(depth + 1, maxIndex, maxDepth, context);
}
termPairs.add(dependedTerm);
termPairs.add(argTerm);
index+=2;
}
}
for (int i = 0; i < (maxIndex - index) / 2; i++) {
RDLTerm dependedTerm = generator.generate(i * 2 + index, depth, maxIndex, maxDepth, context);
if (dependedTerm == null) {
break;
}
RDLTerm argTerm = generator.generate(i * 2 + index + 1, depth, maxIndex, maxDepth, context);
if (argTerm == null) {
break;
}
while (dependedTerm instanceof MetaDynamicTerm dynamicTerm) {
dependedTerm = dynamicTerm.generate(depth + 1, maxIndex, maxDepth, context);
}
while (argTerm instanceof MetaDynamicTerm dynamicTerm) {
argTerm = dynamicTerm.generate(depth + 1, maxIndex, maxDepth, context);
}
termPairs.add(dependedTerm);
termPairs.add(argTerm);
}
if (termPairs.isEmpty()) {
return (MetaRDLTerm) dependingTerm;
}
return new MetaDependencyTerm(dependingTerm, termPairs);
}
@Override
public Set<MatchConstraint> isMatchedBy(RDLTerm another, MatchConstraint constraint, Position position) {
int maxIndex = another.getMaxIndex();
Set<MatchConstraint> result = new HashSet<>();
constraint.getContext().put(position, maxIndex);
if (! (Boolean) constraint.getContext().getOrDefault("isDynamicStarted", false)) {
int maxDepth = another.getMaxDepth();
constraint.getContext().put("isDynamicStarted", true);
for (int i = maxDepth; i > 0; i--) {
MatchConstraint newConstraint = new MatchConstraint(constraint);
newConstraint.getContext().put("maxDepth", i);
MetaRDLTerm metaTerm = generate(position.size(), maxIndex, i, newConstraint.getContext());
result.addAll(metaTerm.isMatchedBy(another, newConstraint, position));
}
} else {
int maxDepth = (Integer) constraint.getContext().get("maxDepth");
MetaRDLTerm metaTerm = generate(position.size(), maxIndex, maxDepth, constraint.getContext());
result.addAll(metaTerm.isMatchedBy(another, constraint, position));
}
return result;
}
@Override
public RDLTerm substitute(Map<Variable, RDLTerm> binding, Map<Object, Object> context, Position position) {
if (! context.containsKey(position)) throw new SubstituteFailedException();
if (! context.containsKey("maxDepth")) throw new SubstituteFailedException();
int maxIndex = (int) context.get(position);
int maxDepth = (int) context.get("maxDepth");
return generate(position.size(), maxIndex, maxDepth, context).substitute(binding, context, position);
}
@Override
public String toString() {
if (dependingTerm != null) {
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(", ")) + " ...? ]";
}
return "[ ...? ]";
}
}