001 package dk.deepthought.sidious.planner;
002 
003 import java.util.Collection;
004 import java.util.HashMap;
005 
006 import org.apache.commons.logging.Log;
007 import org.apache.commons.logging.LogFactory;
008 
009 import dk.deepthought.sidious.goalhandler.Goal;
010 import dk.deepthought.sidious.planner.graph.Graph;
011 import dk.deepthought.sidious.services.ServiceEngine;
012 import dk.deepthought.sidious.supportsystem.Adjustable;
013 import dk.deepthought.sidious.supportsystem.Repository;
014 import dk.deepthought.sidious.supportsystem.State;
015 import dk.deepthought.sidious.supportsystem.SuperLinkID;
016 import dk.deepthought.sidious.util.SidiousQueue;
017 
018 /**
019  * This class constitutes a Blackboard for the planner. Works as a liaison class
020  * between the <code>{@link GraphFactory}</code> and
021  <code>{@link Pathfinder}</code>.
022  <p>
023  * This class holds three <code>SidiousQueue</code> queues for calculating a
024  * plan:
025  <ol>
026  <li> extracting state and generating the graph
027  <li> for processing the pathfinding
028  <li> for plan generation
029  </ol>
030  
031  @author Deepthought
032  
033  */
034 public final class PlannerEngine implements Planner {
035 
036     // XXX se på strategy pattern for at vælge kvilken pathfinder algoritme der
037     // skal bruges.
038     // Måske mest anvendeligt i spil!
039 
040     /**
041      * Logger for this class.
042      */
043     private static final Log logger = LogFactory.getLog(PlannerEngine.class);
044 
045     /**
046      * Mapping between id and pathfinder
047      */
048     private final HashMap<SuperLinkID, Pathfinder> idToPathfinder = new HashMap<SuperLinkID, Pathfinder>();
049 
050     /**
051      * private singleton instance.
052      */
053     private static final Planner INSTANCE = new PlannerEngine();
054 
055     /**
056      * Queue to facilitate generation of the graph.
057      */
058     private SidiousQueue<Goal> graphFactoryQueue = new SidiousQueue<Goal>(
059             "graphFactoryQueue") {
060 
061         protected void process(Goal item) {
062             State start = ServiceEngine.getCurrentState();
063             pathfinderQueue.enqueue(GraphFactory.makeGraph(item.getOrigin(),
064                     start, item.getGoalState()));
065         }
066     };
067 
068     /**
069      * Queue to facilitate the path finding.
070      */
071     private SidiousQueue<Graph> pathfinderQueue = new SidiousQueue<Graph>(
072             "pathfinderQueue") {
073 
074         @Override
075         protected void process(Graph item) {
076             Pathfinder p = new AStarAlgorithm();
077             idToPathfinder.put(item.getId(), p);
078             item.getGoalVertex().getState();
079             p.search(item);
080             planGeneratorQueue.enqueue(item);
081         }
082     };
083 
084     /**
085      * Queue to handle the generation of a plan from a searched graph.
086      */
087     private SidiousQueue<Graph> planGeneratorQueue = new SidiousQueue<Graph>(
088             "planGeneratorQueue") {
089 
090         @Override
091         protected void process(Graph item) {
092             Plan plan = PlanGenerator.generatePlan(item);
093             deliverPlan(plan);
094         }
095     };
096 
097     /**
098      * Private constructor, to facilitate singleton.
099      */
100     private PlannerEngine() {
101     }
102 
103     /**
104      * Delivers the finished plan to the blackboard.
105      
106      @param plan
107      *            the finished plan
108      */
109     private void deliverPlan(Plan plan) {
110         Repository.getBlackboard().deliverResult(plan);
111     }
112 
113     /**
114      * Returns the adjustables of the specified requester.
115      
116      @param requester
117      *            the requester
118      @return the adjustables of the requester
119      */
120     public static Collection<Adjustable> getAdjustables(SuperLinkID requester) {
121         return Repository.getBlackboard().getRequester(requester)
122                 .getAdjustables();
123     }
124 
125     /*
126      * (non-Javadoc)
127      
128      * @see dk.deepthought.sidious.planner.Planner#stop(dk.deepthought.sidious.supportsystem.SuperLinkID)
129      */
130     public void stop(SuperLinkID id) {
131         if (logger.isDebugEnabled()) {
132             logger.debug("stop(SuperLinkID id=" + id
133                     ") - attempting to stop planning");
134         }
135         if (idToPathfinder.containsKey(id)) {
136             Pathfinder pathfinder = idToPathfinder.get(id);
137             pathfinder.cancel();
138             idToPathfinder.remove(id);
139         }
140         if (logger.isDebugEnabled()) {
141             logger.debug("stop(SuperLinkID id=" + id + ") - stopped planning");
142         }
143     }
144 
145     /*
146      * (non-Javadoc)
147      
148      * @see dk.deepthought.sidious.planner.Planner#requestPlan(dk.deepthought.sidious.goalhandler.Goal)
149      */
150     public void requestPlan(Goal goal) {
151         if (goal == null) {
152             throw new IllegalArgumentException("null not valid goal");
153         }
154         graphFactoryQueue.enqueue(goal);
155     }
156 
157     /**
158      * Returns the singleton instance.
159      
160      @return the singleton instance
161      */
162     public static Planner getInstance() {
163         return INSTANCE;
164     }
165 
166 }