001    /**
002     * planningtool - A Planning Tool with Critiquing Support.
003     * 
004     * Copyright (C) 2006 olale
005    
006     * This program is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU General Public License
008     * as published by the Free Software Foundation; either version 2
009     * of the License, or (at your option) any later version.
010    
011     * This program is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014     * GNU General Public License for more details.
015    
016     * You should have received a copy of the GNU General Public License
017     * along with this program; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
019    
020     * Contact information: 
021     * E-mail: olale@ida.liu.se
022     *         olale@lysator.liu.se
023     */
024    package se.liu.ida.critiquer.constraints;
025    
026    import java.awt.Graphics2D;
027    import java.util.ArrayList;
028    import java.util.Calendar;
029    import java.util.HashMap;
030    import java.util.HashSet;
031    import java.util.Set;
032    import java.util.Map.Entry;
033    
034    import javax.swing.JComponent;
035    
036    import org.jfree.chart.ChartFactory;
037    import org.jfree.chart.ChartPanel;
038    import org.jfree.chart.JFreeChart;
039    import org.jfree.chart.plot.PlotOrientation;
040    import org.jfree.data.category.DefaultCategoryDataset;
041    
042    import se.liu.ida.critiquer.activities.Activity;
043    import se.liu.ida.critiquer.activities.ActivityUtils;
044    import se.liu.ida.critiquer.activities.parameters.Parameter;
045    import se.liu.ida.critiquer.activities.parameters.TimeParameter;
046    import se.liu.ida.critiquer.gui.TimeView;
047    import se.liu.ida.critiquer.gui.View;
048    import se.liu.ida.critiquer.mics.ReferenceHolder;
049    import se.liu.ida.critiquer.resources.Agent;
050    
051    /**
052     * 
053     * <p>
054     * A critic that is supposed to display information on resource usage depending
055     * on which resources are used at the current time in the time view
056     * </p>
057     * <p>
058     * For each activity that is created, a constraint map is maintained that holds
059     * eq constraints for the activity start and end times so that their values
060     * reflect those of the mission time. The map also contains IfOnlyIf constraints
061     * that forces an integer variable agentUsage to 1 if the current time in the
062     * time view is within the mission time and 0 otherwise.
063     * </p>
064     * <p>
065     * There is finally a total sum of the resource usage which is the sum of all
066     * agentUsage variables for all activities.
067     * </p>
068     * <p>
069     * It's really a shame that constraints cannot force variables to assume values
070     * if they already have other values without raising ContradictionException. As
071     * it stands right now we have to remove and add <code>eq</code> constraints
072     * to achieve the same effect
073     * </p>
074     * 
075     * @author olale
076     * 
077     */
078    
079    public class ResourceUsageCritic extends StandardConstraint implements GUIComponentCritic {
080    
081    
082            /**
083         * 
084         */
085            private static final long                                                serialVersionUID               = 1L;
086    
087            public static final int                                            MAX_USAGE                       = 1000;
088    
089            private String                                                                  activities                        = "All activities";
090    
091            
092            private DefaultCategoryDataset                                  dataset                          = new DefaultCategoryDataset();
093    
094            private JFreeChart                                                              chart                              = ChartFactory.createBarChart("Resource usage",
095                                                                                                                                                                              "Resource type",
096                                                                                                                                                                              "Usage",
097                                                                                                                                                                              dataset,
098                                                                                                                                                                              PlotOrientation.VERTICAL,
099                                                                                                                                                                              true,
100                                                                                                                                                                              false,
101                                                                                                                                                                              false);
102    
103            private ChartPanel                                                              panel                              = new ChartPanel(chart);
104            private HashMap<String,Integer> usageMap = new HashMap<String, Integer>();
105            
106            ResourceUsageCritic() {
107                    usageMap.put("All", 0);
108                    updateDataSet();
109            }
110    
111            /**
112         * The current time has changed, so modify the barchart dataset
113         * 
114         */
115            private void updateDataSet() {
116                    for (Entry<String, Integer> entry : usageMap.entrySet()) {
117                            dataset.setValue(entry.getValue(), entry.getKey(), activities);
118                    }
119            }
120    
121            /**
122         * This view is only applicable to the time view
123         * 
124         */
125            @Override
126            protected void initApplicableViews() {
127                    applicableViews.add(TimeView.class);
128            }
129    
130            private boolean isActivityActive(Activity activity) {
131                    boolean active=false;
132                    Calendar currentTime = ReferenceHolder.timeView.getCurrentTime();
133                    TimeParameter startParam = ActivityUtils.getStartTimeParameter(activity);
134                    TimeParameter endParam = ActivityUtils.getEndTimeParameter(activity);
135                    if (startParam.hasValue() && endParam.hasValue()) {
136                            active = (!startParam.getValue().after(currentTime)) && (!endParam.getValue().before(currentTime));
137                    }
138                    return active;
139            }
140    
141    
142            public String getDescription() {
143                    return "Displays information on resource usage";
144            }
145    
146            /**
147         * 
148         * We only need set the currentTime through changing the currentTime
149         * <code>eq</code> constraint since the updating is already done by the
150         * ChartPanel component
151         * 
152         */
153            public void viewUpdated(View v, Graphics2D g2) {
154                    if (v instanceof TimeView) {
155                            TimeView timeView = (TimeView) v;
156                            ArrayList<Activity> activityList = timeView.getEvaluationActivities();
157                            Set<String> usageKeys = usageMap.keySet();
158                            for (String key : usageKeys) {
159                                    usageMap.put(key,0);
160                            }
161                            
162                            for (Activity activity : activityList) {
163                                    if (isActivityActive(activity)) {
164                                            HashSet<Agent> agents = ActivityUtils.getAgentsInActivity(activity);
165                                            for (Agent agent : agents) {
166                                                    String agentType = agent.getClass().getSimpleName();
167                                                    if (usageMap.containsKey(agentType)) {
168                                                            usageMap.put(agentType, usageMap.get(agentType)+1);
169                                                    } else {
170                                                            usageMap.put(agentType,1);
171                                                    }
172                                            }
173                                            usageMap.put("All",usageMap.get("All")+agents.size());  
174                                    }       
175                            }
176                            
177                            updateDataSet();
178                    }
179            }
180    
181            @Override
182            public <T> void paramChanged(Activity activity, Parameter<T> p) {
183                    // TODO Auto-generated method stub
184                    
185            }
186    
187            /**
188             * Return the chart panel
189             * @see se.liu.ida.critiquer.constraints.GUIComponentCritic#getComponent()
190             */
191            public JComponent getComponent() {
192                    return panel;
193            }
194    }