Index: fedd/abac-src/ttg/process/StingyStrategy.java
===================================================================
--- fedd/abac-src/ttg/process/StingyStrategy.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/ttg/process/StingyStrategy.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,327 @@
+package com.nailabs.abac.process;
+
+import edu.stanford.peer.rbtm.credential.*;
+import com.nailabs.abac.trust.*;
+import com.nailabs.abac.test.*;
+import java.util.*;
+/**
+ * The strategy handles processing a working list of nodes in the trust target
+ * graph to be processed. This version uses a combination of heuristics with 
+ * a depth first search method.
+ */
+public class StingyStrategy extends Strategy {
+    /** A queue for operations which need to delay */
+    protected Hashtable delayedOps = new Hashtable();
+    
+    /** 
+     * A list of sibling children of the current node being processed. Note,
+     * this is an ordered stack. Node operations are added the bottom of the
+     * stack and implication edges are added to the top. 
+     */
+    protected Vector siblings = new Vector();
+
+    /** The current node being processed. Null if no local processing. */
+    protected TTGNode current = null;
+    
+    /** Is this strategy currently processing locally? */
+    protected boolean isLocal = false;
+
+    /** 
+     * A threshold for determining when isDone is high enough 
+     */
+    public int threshold = 0;
+
+    public float successWeight = 0.0f;
+
+    public CountTable weights = null;
+
+    /** A count of how many criteria have been met for ending a turn */
+    protected int isDone = 0;
+
+    /** Check to see if  already saved weights, which should only occur once */
+    private boolean isSaved = false;
+
+    /** create a new stingy strategy instance */
+    public StingyStrategy(NegotiationContext conf, Properties props) {
+        super(conf);
+        try {
+            if(props.containsKey("successWeight")) {
+                successWeight = 
+                Float.parseFloat(props.getProperty("successWeight"));
+            }
+            if(props.containsKey("weightFile")) {
+                weights = new CountTable(props.getProperty("weightFile"));
+            } else {
+                weights = new CountTable("weights." + context.getSelf());
+            }
+            if(props.containsKey("init")) {
+                weights.INIT = 
+                    Float.parseFloat(props.getProperty("init"));
+            }
+            if(props.containsKey("sat")) {
+                weights.SAT = 
+                    Float.parseFloat(props.getProperty("sat"));
+            }
+            if(props.containsKey("training")) {
+                if(props.getProperty("training").equalsIgnoreCase("true")) {
+                    isSaved = false;
+                } else {
+                    isSaved = true;
+                }
+            }
+        } catch(Exception ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    /**
+     * The stingy strategy needs to save weights when the primary trust target
+     * is satisfied. This is method tests the predicate and saves the weight
+     * states as a side effect.
+     */
+    public int getSatisfactionState() {
+        int state = super.getSatisfactionState();
+        if(state == SatisfactionState.UNKNOWN) {
+            return state;
+        }
+        if(isSaved) {
+            return state;
+        }  
+        isSaved = true;
+        Iterator i = context.getGraph().getNodes();
+        while(i.hasNext()) {
+            TTGNode node = (TTGNode)i.next();
+            EntityExpression expr = getWeightKey(node.getGoal());
+            if(node instanceof TargetNode) {
+                state = ((TargetNode)node).getSatisfactionValue();
+            } else {
+                continue;
+            }
+            if(state == SatisfactionState.SATISFIED) { // increment success
+                weights.addSatisfied(expr);
+            } else {
+                //if(state == SatisfactionState.FAILED) {    
+                //increment failure or unkown nodes
+                weights.addFailed(expr);
+            }
+        }
+        debug("strategy", "Saving weights for " + context.getSelf());
+        weights.save("weights." + context.getSelf());    
+        return state;
+    }
+    
+    /** 
+     * Notify the strategy that a new edge needs to be added to the graph.
+     * The strategy is responsible for performing the operation on the graph,
+     * whether the strategy chooses to  defer the operation or not.
+     */
+    public void scheduleOperation(Operation op) {
+        if(!isLocal) {          // process remote operations directly
+            super.scheduleOperation(op);
+            return;
+        }
+        if(op instanceof NodeOperation) { // add node op to end of vector
+            siblings.add(op);
+        } else if(op instanceof ImplicationEdge) { // add  to front of vector
+            //linking implication edges should be performed NOW
+            if(op instanceof LinkingImplicationEdge) { 
+                super.scheduleOperation(op);
+                siblings.remove(op);
+            } else {
+                siblings.add(0, op);
+            }
+        } else {                // perform the operation immediately
+            super.scheduleOperation(op); 
+            siblings.remove(op);
+        }
+    }
+
+    /** Notify this strategy that a control child has been satisfied */
+    public void addSatisfiedControlChild(TTGNode node) {
+        Goal g = (Goal)node.getGoal();
+        Entity v = g.getVerifier();
+        if(!context.getSelf().equals(v)) {
+            //weights.addSatisfied(getWeightKey(g));
+            isDone++;
+        }
+    }
+
+    /** Notify this strategy that a new node has been added to the graph */
+    public void addNewNode(TTGNode node) {
+        if(!isLocal)return;
+        ProcessingState state = node.getProcessingState();
+        Entity v = node.getGoal().getVerifier();
+        if(context.getSelf().equals(v) && state.isVerifierProcessed()) {
+            //increment the isDone counter
+            isDone++;
+        }
+        debug("strategy", "node  = " + node.getGoal());
+        debug("strategy", "isDone = " + isDone);
+    }
+
+    /** iterate through the work list until it is empty */
+    public void iterate() {
+        isDone = 0;
+        while(true) {
+            debug("strategy", "beginning iteratiion");
+            super.iterate();
+            if(okToEndTurn()) {
+                debug("strategy", "ending turning now!");
+                return;
+            }
+            debug("strategy", "processing the delayed queue");
+            processDelayedOps();
+        }
+    }
+
+    /** utility function for getting the target expression out of a goal */
+    protected EntityExpression getWeightKey(Goal g) {
+        EntityExpression key = null;
+        if(g instanceof LinkingGoal) {
+            String roleName = 
+                ((LinkingGoal)g).getTargetRoleName().toString();
+            key = new Role("?X", roleName);
+        }
+        if(g instanceof TrustTarget) {
+            key = ((TrustTarget)g).getTargetRole();
+        }
+        return key;
+    }
+
+    /** Note the beginning of a new parent node being processed */
+    protected void setCurrentParent(TTGNode parent) {
+        //initialize the state variables
+        siblings = new Vector();
+        current = parent;
+        isLocal = true;
+        //isDone = 0;
+    }
+
+    /** Process all the nodes in the delayed queue */
+    protected void processDelayedOps() {
+        Iterator i = delayedOps.values().iterator();
+        while(i.hasNext()) {
+            Vector s = (Vector)i.next();
+            while(!s.isEmpty()) {
+                debug("strategy", "performing delayed op = " + s.get(0)); 
+                super.scheduleOperation((Operation)s.remove(0));
+            }
+            i.remove();
+        }
+    }
+
+    /** Note the conclusion of a new parent node being processed */
+    protected void scheduleOperationsForNode(TTGNode parent) {
+        Entity v = parent.getVerifier();
+        int doCount = 0;
+
+        // if self is not parent's verifier, perform all the operations now
+        if(!context.getSelf().equals(v)) {
+            while(!siblings.isEmpty()) {
+                super.scheduleOperation((Operation)siblings.remove(0));
+            }
+            current = null;
+            isLocal = false;
+            return;
+        }
+        // If the verifier finds itself processing a node it has already 
+        // processed, it will not add any more operations on that node
+        // (this node has been fully processed; therefore, the delayed 
+        //  operations can be ignored.)
+        if(delayedOps.containsKey(current.getGoal())) {
+            debug("strategy", "Already processed node " + current.getGoal());
+            debug("strategy", "siblings = " + siblings);
+            siblings = new Vector(); // potential memory leak--should be gc'ed
+            current = null;
+            isLocal = false;
+            return;
+        }
+        //otherwise perform at least one child
+        Iterator i = siblings.iterator();
+        while(i.hasNext()) {
+            Operation op = (Operation)i.next();
+
+            if(op instanceof ImplicationEdge) {
+                Goal g = ((EdgeOperation)op).getChild();
+                // embedded decision making heuristics
+                if(weights.getWeight(getWeightKey(g)) < successWeight) {
+                    //do nothing to delay the operation
+                    //super.scheduleOperation(op);                     
+                } else {
+                    super.scheduleOperation(op); 
+                    i.remove();
+                    doCount += 1;
+                }
+            }
+        }
+        // If no edges have been added, take the first implication edge (if
+        // any) and perform it.
+        i = siblings.iterator();
+        while(doCount == 0 && i.hasNext()) { // the while is redundant
+            // node operations are processed in the next loop below
+            Operation op = (Operation)i.next();
+            if(op instanceof ImplicationEdge) {
+                super.scheduleOperation(op);
+                i.remove();
+                doCount += 1;
+            }
+        }
+        //if there are no remaining edge operations, then perform the 
+        //remaining node operation (to mark as processed).
+        //check for delayed ops and determine whether it's ok to add node op
+        if(!siblings.isEmpty()) {
+            if(siblings.get(0) instanceof NodeOperation) { 
+                // if all edges are done
+                NodeOperation nodeOp = (NodeOperation)siblings.remove(0);
+                super.scheduleOperation(nodeOp);        
+            }
+        }
+        //put the remaining child edges in the delayed queue
+        Goal g = current.getGoal();
+        if(!siblings.isEmpty()) {
+            delayedOps.put(g, siblings);
+        }
+        //clean up the state variables
+        current = null;
+        isLocal = false;
+    }
+
+    /** criteria for determining when to end this negotiators turn */
+    protected boolean okToEndTurn() {
+        // isDone = 0; // used this to check that delayedOps is really empty
+        // if there are no more delayed op's, then end this negotiator's turn
+        if(delayedOps.isEmpty()) {
+            isDone++;          
+        }
+        //if the negotiation has suceeded or failed, then return true
+        if(getSatisfactionState() != SatisfactionState.UNKNOWN) {
+            isDone++;
+        }
+        //if the threshold for end-turn criteria has been met then return true
+        if(isDone > threshold) {
+            return true;
+        }
+        // the end-turn criteria have not been met
+        return false;
+    }
+
+    /** 
+     * convenience method for determining whether this negotiator has
+     * a deadlock in processing the negotiation. This method can be
+     * overridden is subsequent versions.
+     */
+    protected boolean isStuck() {
+        // if there's no history, we cannot be stuck yet
+        if(super.isStuck()) {
+            if(lastMessage != null) {
+                // if both messages contain no changes, 
+                //then a deadlock has occurred
+                return (lastMessage.getOperationsCount() == 0 );
+            }
+        }
+        return false;
+   }
+
+
+
+}
