001    package aima.gui.applications.search.map;
002    
003    import java.text.DecimalFormat;
004    import java.util.List;
005    
006    import aima.basic.Agent;
007    import aima.gui.framework.AgentAppController;
008    import aima.search.framework.SearchFactory;
009    import aima.search.map.AdaptableHeuristicFunction;
010    import aima.search.map.DynAttributeNames;
011    import aima.search.map.Scenario;
012    
013    /**
014     * Provides a useful base class for agent application controller implementations
015     * in the context of route planning agent application development. To get it
016     * ready to work, all you need to do is, to provide implementations for the four
017     * abstract methods. See {@link RoutePlanningAgentAppDemo} for an example.
018     * 
019     * @author R. Lunde
020     */
021    public abstract class AbstractMapAgentController extends AgentAppController {
022            /** A scenario. */
023            protected Scenario scenario;
024            /**
025             * Some location names. For route planning problems, only one location
026             * should be specified.
027             */
028            protected List<String> destinations;
029            /** Search method to be used. */
030            protected aima.search.framework.Search search;
031            /** Heuristic function to be used when performing informed search. */
032            protected AdaptableHeuristicFunction heuristic;
033    
034            /** Clears the model's tour history. */
035            @Override
036            public void clearAgent() {
037                    ((MapAgentModel) model).clearTourHistory();
038                    frame.modelChanged();
039            }
040    
041            /**
042             * Template method, which performs necessary preparations for running the
043             * agent. The behavior is strongly influenced by the primitive operations
044             * {@link #selectScenarioAndDest(int, int)}, {@link #prepareModel()} and
045             * {@link #createHeuristic(int)}.
046             */
047            @Override
048            public void prepareAgent() {
049                    MapAgentFrame.SelectionState state = frame.getSelection();
050                    selectScenarioAndDest(state.getValue(MapAgentFrame.SCENARIO_SEL), state
051                                    .getValue(MapAgentFrame.DESTINATION_SEL));
052                    prepareModel();
053                    search = SearchFactory.getInstance().createSearch(
054                                    state.getValue(MapAgentFrame.SEARCH_SEL),
055                                    state.getValue(MapAgentFrame.SEARCH_MODE_SEL));
056                    heuristic = createHeuristic(state.getValue(MapAgentFrame.HEURISTIC_SEL));
057                    scenario.getEnv().registerView(model);
058            }
059    
060            /**
061             * Template method, which calls {@link #startAgent()} and then updates the
062             * status bar of the frame.
063             */
064            @Override
065            public void runAgent() {
066                    startAgent();
067                    List agents = scenario.getEnv().getAgents();
068                    if (agents.size() == 1) {
069                            Agent agent = (Agent) agents.get(0);
070                            String status = (String) agent
071                                            .getAttribute(DynAttributeNames.AGENT_STATUS);
072                            Double travelDistance = (Double) agent
073                                            .getAttribute(DynAttributeNames.AGENT_TRAVEL_DISTANCE);
074                            StringBuffer statusMsg = new StringBuffer();
075                            if (status != null)
076                                    statusMsg.append("Agent status: " + status);
077                            else
078                                    statusMsg.append("Task completed");
079                            if (travelDistance != null) {
080                                    DecimalFormat f = new DecimalFormat("#0.0");
081                                    statusMsg.append("; travel distance: " + f.format(travelDistance));
082                            }
083                            statusMsg.append(".");
084                            frame.setStatus(statusMsg.toString());
085                    }
086            }
087    
088            // ///////////////////////////////////////////////////////////////
089            // abstract methods
090    
091            /**
092             * Primitive operation, responsible for assigning values to attributes
093             * {@link #scenario} and {@link #destinations}.
094             */
095            abstract protected void selectScenarioAndDest(int scenarioIdx, int destIdx);
096    
097            /**
098             * Primitive operation, responsible for preparing the model. Scenario and
099             * destinations are already selected when this method is called.
100             */
101            abstract protected void prepareModel();
102    
103            /**
104             * Factory method, responsible for creating a heuristic function.
105             */
106            abstract protected AdaptableHeuristicFunction createHeuristic(int heuIdx);
107    
108            /**
109             * Primitive operation, responsible for creating and starting the agent.
110             * Scenario, destinations are selected before as well as search method and
111             * search heuristic.
112             */
113            protected abstract void startAgent();
114    
115    }