/*
* Copyright (c) 2003- michael lawley and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation
* which accompanies this distribution, and is available by writing to
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Contributors:
* michael lawley
* David Hearnden
*
*
*/
package tefkat.engine;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import tefkat.model.Extent;
public class Tree {
static int counter = 0;
private final Extent trackingExtent;
private final Binding context;
private final Context parentContext;
private final Collection answers = new ArrayList();
private final List unresolvedNodes = new ArrayList();
private final Set listeners = new HashSet();
private final boolean isNegation;
private boolean completed;
private int level = Integer.MAX_VALUE;
public Tree(Context parentContext, Node node, Binding context, Extent trackingExtent, boolean isNegation) {
increment();
this.parentContext = parentContext;
this.context = context;
this.trackingExtent = trackingExtent;
this.isNegation = isNegation;
if (null != node) {
addUnresolvedNode(node);
}
}
private static void increment() {
counter++;
}
public void addTreeListener(TreeListener listener) {
listeners.add(listener);
}
public void removeTreeListener(TreeListener listener) {
listeners.remove(listener);
}
void setLevel(int level) {
this.level = level;
}
int getLevel() {
return level;
}
Extent getTrackingExtent() {
return trackingExtent;
}
Binding getContext() {
return context;
}
Node getUnresolvedNode() {
if (unresolvedNodes.size() > 0) {
return (Node) unresolvedNodes.remove(0);
} else {
return null;
}
}
void addUnresolvedNode(Node node) {
// insert the node at the start of the list
// This means we perform a depth-first traversal which will
// make debugging easier.
unresolvedNodes.add(0, node);
}
/**
* Create a branch from parent. goal and
* unifier are associated with the new Node. The selected literal in
* parent is replaced with the body of rule to create the child's goal,
* and this is then substituted under unifier.
* @param parent The parent node for the new edge.
* @param unifier The unifier of the parent's selected literal.
*/
void createBranch(Node parent, Binding unifier, Collection childGoal) {
if (null != parent) {
if (null == unifier) {
unifier = parent.getBindings(); // Inherit bindings from parent
} else {
unifier.composeLeft(parent.getBindings());
}
}
Node child = new Node(childGoal, unifier, parent);
addUnresolvedNode(child);
}
public void completed() {
completed = true;
// Need to avoid problems if the TreeListener tries to remove itself
Object[] array = listeners.toArray();
for (int i = array.length - 1; i >= 0; i--) {
TreeListener listener = (TreeListener) array[i];
listener.completed(this);
}
}
Node flounder(Collection reasons) {
// Tell any listeners so they can clean up
floundered();
if (null != parentContext) {
// Delay the node that originally created this tree
parentContext.node.delay(reasons);
// // grab the currently delayed terms
// final Collection delayed = parentContext.node.getDelayed();
// // traverse this Tree to find non-failed leaf Nodes and compute the output binding
// // for each output binding, unifier, create a branch in the parent Tree
// parentContext.tree.createBranch(parentContext.node, unifier, parentContext.node.goal());
parentContext.tree.addUnresolvedNode(parentContext.node);
return parentContext.node;
}
return null;
}
private void floundered() {
for (final Iterator itr = listeners.iterator(); itr.hasNext(); ) {
TreeListener listener = (TreeListener) itr.next();
listener.floundered(this);
}
}
public void success(Node node) throws ResolutionException {
node.setIsSuccess(true);
Binding answer = node.getBindings();
if (!answers.contains(answer)) {
answers.add(answer);
for (final Iterator itr = listeners.iterator(); itr.hasNext(); ) {
TreeListener listener = (TreeListener) itr.next();
listener.solution(answer);
}
}
if (isNegation) {
completed();
}
}
public Collection getAnswers() {
return Collections.unmodifiableCollection(answers);
}
public boolean isSuccess() {
return (answers.size() > 0);
}
public boolean isCompleted() {
return completed;
}
boolean isNegation() {
return isNegation;
}
}