package agg.xt_basis;
import java.util.BitSet;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Dictionary;
import agg.attribute.impl.VarTuple;
import agg.attribute.AttrContext;
import agg.util.csp.Variable;
import agg.xt_basis.csp.CompletionPropertyBits;
/**
* A decorator class which adds support for negative application conditions
* (NACs) to a given completion strategy implementation.
*/
public class Completion_NAC extends MorphCompletionStrategy {
private MorphCompletionStrategy itsStrategy;
private final Vector<GraphObject> itsSavedState = new Vector<GraphObject>();
private boolean globalNAC, globalPAC;
/**
* Construct myself to be a NAC-supporting completion strategy. This uses
* the given <code>strategy</code> for the basic (non-NAC related) morphism
* completion functionality. The same holds for PAC-supporting.
* <p>
* <b>Post:</b> <code>getProperties().get(NAC) == true</code>.
* <b>Post:</b> <code>getProperties().get(PAC) == true</code>.
* <b>Post:</b> <code>getProperties().get(GAC) == true</code>.
*/
public Completion_NAC(MorphCompletionStrategy strategy) {
BitSet aSupportedBits = (BitSet) strategy.getSupportedProperties().clone();
aSupportedBits.set(CompletionPropertyBits.NAC);
aSupportedBits.set(CompletionPropertyBits.PAC);
aSupportedBits.set(CompletionPropertyBits.GAC);
initialize(aSupportedBits, strategy.getProperties());
getProperties().set(CompletionPropertyBits.NAC);
getProperties().set(CompletionPropertyBits.PAC);
getProperties().set(CompletionPropertyBits.GAC);
this.itsStrategy = strategy;
this.randomDomain = strategy.randomDomain;
// showProperties();
}
public void dispose() {
this.itsStrategy.dispose();
this.itsSavedState.clear();
}
public String getName() {
return this.itsStrategy.getName();
}
public void setRandomisedDomain(boolean b) {
this.itsStrategy.setRandomisedDomain(b);
this.randomDomain = b;
}
public MorphCompletionStrategy getSourceStrategy() {
return this.itsStrategy;
}
public AttrContext getAttrContext() {
return this.itsStrategy.getAttrContext();
}
public void setProperties(MorphCompletionStrategy fromStrategy) {
BitSet aSupportedBits = (BitSet) fromStrategy.getSupportedProperties()
.clone();
aSupportedBits.set(CompletionPropertyBits.NAC);
aSupportedBits.set(CompletionPropertyBits.PAC);
aSupportedBits.set(CompletionPropertyBits.GAC);
initialize(aSupportedBits,
(BitSet) fromStrategy.getProperties().clone());
getProperties().set(CompletionPropertyBits.NAC);
getProperties().set(CompletionPropertyBits.PAC);
getProperties().set(CompletionPropertyBits.GAC);
}
public final void reset() {
this.itsStrategy.reset();
}
public void enableParallelSearch(boolean b) {
this.parallel = b;
this.itsStrategy.enableParallelSearch(b);
}
public void setStartParallelSearchByFirst(boolean b) {
this.startParallelMatchByFirstCSPVar = b;
this.itsStrategy.setStartParallelSearchByFirst(b);
}
public void resetSolverQuery_Type() {
this.itsStrategy.resetSolverQuery_Type();
}
public void resetSolver(boolean doUpdateQueries) {
this.itsStrategy.resetSolver(doUpdateQueries);
}
public final void initialize(OrdinaryMorphism morph) {
this.itsStrategy.initialize(morph);
}
public void reinitializeSolver(boolean doUpdateQueries) {
this.itsStrategy.reinitializeSolver(doUpdateQueries);
}
public void resetSolverVariables() {
this.itsStrategy.resetSolverVariables();
}
public void removeFromObjectVarMap(GraphObject anObj) {
this.itsStrategy.removeFromObjectVarMap(anObj);
}
public void removeFromTypeObjectsMap(GraphObject anObj) {
this.itsStrategy.removeFromTypeObjectsMap(anObj);
}
public void resetTypeMap(Hashtable<String, HashSet<GraphObject>> typeMap) {
this.itsStrategy.resetTypeMap(typeMap);
}
public void resetTypeMap(Graph g) {
this.itsStrategy.resetTypeMap(g);
}
public void resetVariableDomain(boolean resetByNull) {
this.itsStrategy.resetVariableDomain(resetByNull);
}
public void resetVariableDomain(GraphObject go) {
this.itsStrategy.resetVariableDomain(go);
}
public void setPartialMorphism(OrdinaryMorphism morph) {
this.itsStrategy.setPartialMorphism(morph);
}
public boolean isDomainOfTypeEmpty(Type t) {
return this.itsStrategy.isDomainOfTypeEmpty(t);
}
public boolean isDomainOfTypeEmpty(Type t, Type src, Type tar) {
return this.itsStrategy.isDomainOfTypeEmpty(t, src, tar);
}
public void setRelatedInstanceVarMap(
Dictionary<Object, Variable> relatedVarMap) {
this.itsStrategy.setRelatedInstanceVarMap(relatedVarMap);
}
public Dictionary<Object, Variable> getInstanceVarMap() {
return this.itsStrategy.getInstanceVarMap();
}
public Object clone() {
Completion_NAC aClone = new Completion_NAC(
(MorphCompletionStrategy) this.itsStrategy.clone());
aClone.itsProperties = (BitSet) this.itsProperties.clone();
aClone.randomDomain = this.randomDomain;
aClone.parallel = this.parallel;
aClone.startParallelMatchByFirstCSPVar = this.startParallelMatchByFirstCSPVar;
return aClone;
}
public final boolean next(final OrdinaryMorphism morph) {
if (morph instanceof Match) {
// ((VarTuple) aMatch.getAttrContext().getVariables())
// .unsetNotInputVariables();
// ((VarTuple) morph.getAttrContext().getVariables()).showVariables();
if (this.itsStrategy.next(morph)) {
return areLeftApplCondSatisfied((Match) morph);
}
return false;
}
return this.itsStrategy.next(morph);
}
public final boolean next(final OrdinaryMorphism morph,
Collection<Node> nodes,
Collection<Arc> edges) {
if (morph instanceof Match) {
// ((VarTuple) aMatch.getAttrContext().getVariables())
// .unsetNotInputVariables();
if (this.itsStrategy.next(morph, nodes, edges)) {
return areLeftApplCondSatisfied((Match) morph);
}
return false;
}
return this.itsStrategy.next(morph, nodes, edges);
}
private boolean areLeftApplCondSatisfied(final Match aMatch) {
boolean matchCompletionDone = true;
while (matchCompletionDone) {
if (!this.itsProperties.get(CompletionPropertyBits.GAC)
|| aMatch.getRule().evalFormula()) {
// check more
if (this.itsProperties.get(CompletionPropertyBits.PAC)) {
if(arePACsSatisfied(aMatch)) {
// check more
if (this.itsProperties.get(CompletionPropertyBits.NAC)) {
if (areNACsSatisfied(aMatch)) {
return true;
}
if ( this.globalNAC
&& !aMatch.getTarget().isAttributed()
&& (((VarTuple) aMatch.getAttrContext()
.getVariables()).getSize() == 0) ) {
return false;
}
// ((VarTuple) aMatch.getAttrContext().getVariables())
// .unsetNotInputVariables();
matchCompletionDone = this.itsStrategy.next(aMatch);
}
else
return true;
} else {
if ( this.globalPAC
&& !aMatch.getTarget().isAttributed()
&& (((VarTuple) aMatch.getAttrContext()
.getVariables()).getSize() == 0) ) {
return false;
}
// ((VarTuple) aMatch.getAttrContext().getVariables())
// .unsetNotInputVariables();
matchCompletionDone = this.itsStrategy.next(aMatch);
}
} else if (getProperties().get(CompletionPropertyBits.NAC)) {
if (areNACsSatisfied(aMatch)) {
return true;
}
if (this.globalNAC
&& !aMatch.getTarget().isAttributed()
&& (((VarTuple) aMatch.getAttrContext()
.getVariables()).getSize() == 0)) {
return false;
}
// ((VarTuple) aMatch.getAttrContext().getVariables())
// .unsetNotInputVariables();
matchCompletionDone = this.itsStrategy.next(aMatch);
}
else
return true;
}
else {
matchCompletionDone = this.itsStrategy.next(aMatch);
}
}
return false;
}
private final boolean areNACsSatisfied(Match match) {
if (match.getRule().hasNACs()) {
this.globalNAC = true;
final Enumeration<OrdinaryMorphism> nacs = match.getRule().getNACs();
while (nacs.hasMoreElements()) {
final OrdinaryMorphism nac = nacs.nextElement();
if (!nac.isEnabled())
continue;
if (nac.getSize() != 0)
this.globalNAC = false;
if (!MatchHelper.isDomainOfApplCondEmpty(match, nac)) {
if (match.checkNAC(nac) != null) {
return false;
}
}
}
}
return true;
}
private final boolean arePACsSatisfied(Match match) {
if (match.getRule().hasPACs()) {
this.globalPAC = true;
final Enumeration<OrdinaryMorphism> pacs = match.getRule().getPACs();
while (pacs.hasMoreElements()) {
final OrdinaryMorphism pac = pacs.nextElement();
if (pac.isEnabled() && !pac.isShifted()) {
if (pac.getSize() != 0)
this.globalPAC = false;
if (!MatchHelper.isDomainOfApplCondEmpty(match, pac)) {
if (match.checkPAC(pac) == null) {
return false;
}
} else {
return false;
}
}
}
}
// check PACs shifted from source rule to concurrent rule during its creation
if (!areShiftedPACsSatisfied(match)) {
return false;
}
return true;
}
private boolean areShiftedPACsSatisfied(Match match) {
boolean ok = match.getRule().getShiftedPACs() == null
|| match.getRule().getShiftedPACs().isEmpty();
if (!ok) {
for (int i=0; i<match.getRule().getShiftedPACs().size() && !ok; i++) {
final ShiftedPAC shiftedPAC = match.getRule().getShiftedPACs().get(i);
if (shiftedPAC.eval(match)) {
ok = true;
}
}
this.globalPAC = false;
}
return ok;
}
/*
private final void saveState(OrdinaryMorphism morph) {
GraphObject anObj;
itsSavedState.clear();
Enumeration<GraphObject> aDomainEnum = morph.getDomain();
while (aDomainEnum.hasMoreElements()) {
anObj = aDomainEnum.nextElement();
itsSavedState.addElement(anObj);
itsSavedState.addElement(morph.getImage(anObj));
}
}
private final void restoreState(OrdinaryMorphism morph) {
morph.clear();
for (int i = 0; i < itsSavedState.size() - 1; i = i + 2) {
morph.addMapping(itsSavedState.elementAt(i), itsSavedState
.elementAt(i + 1));
}
itsSavedState.clear();
}
*/
}