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.Collection;
029    import java.util.HashSet;
030    
031    import se.liu.ida.critiquer.activities.Activity;
032    import se.liu.ida.critiquer.activities.ActivityConsistencyCheck;
033    import se.liu.ida.critiquer.activities.ActivityUtils;
034    import se.liu.ida.critiquer.activities.parameters.AgentParameter;
035    import se.liu.ida.critiquer.activities.parameters.Commander;
036    import se.liu.ida.critiquer.activities.parameters.Parameter;
037    import se.liu.ida.critiquer.gui.View;
038    import se.liu.ida.critiquer.mics.Comparer;
039    import se.liu.ida.critiquer.mics.ReferenceHolder;
040    import se.liu.ida.critiquer.mics.Utils;
041    import se.liu.ida.critiquer.resources.Agent;
042    
043    /**
044     * 
045     * Checks whether or not an agent can be added to a commander, depending on if
046     * there are any other activities the agent is engaged in.
047     * 
048     * @author olale
049     * 
050     */
051    public class AgentMutex extends StandardConstraint implements ActivityConsistencyCheck,TextCritic {
052    
053            private static AgentMutex singleton = null;
054    
055            /**
056         * 
057         * 
058         */
059            public AgentMutex() {
060                    super();
061    
062                    /**
063             * Ensure that there is only one instance created through
064             * ConstraintFactory.createSingletonVisualConstraint
065             */
066                    assert (singleton == null);
067                    Activity.addStaticConsistencyChecker(this);
068                    singleton = this;
069            }
070    
071            /**
072         * 
073         */
074            private static final long serialVersionUID = 1L;
075    
076            private String                  information       = "";
077    
078            private boolean overlapsAny(Activity activity, ArrayList<Activity> activities) {
079                    assert (!activities.contains(activity));
080                    information="";
081                    for (Activity otherActivity : activities) {
082                            if (ActivityUtils.overlap(activity, otherActivity)) {
083                                    HashSet<Agent> agentsInActivity = ActivityUtils.getAgentsInActivity(activity);
084                                    agentsInActivity.retainAll(ActivityUtils.getAgentsInActivity(otherActivity));
085                                    information = "";
086                                    for (Agent agent : agentsInActivity) {
087                                            
088                                            information += "\n"+agent + " is already committed to activity "
089                                            + otherActivity
090                                            + " at the same time so it cannot perform "
091                                            + activity;
092                                    }
093                                    return true;
094                            }
095                    }
096                    return false;
097            }
098    
099            
100            /**
101         * 
102         * Checks if the currently selected set of agents is consistent with respect
103         * to when the activities they are supposed to be used in take place in
104         * time.
105         * 
106         * @see se.liu.ida.critiquer.activities.ActivityConsistencyCheck#paramValueCheck(se.liu.ida.critiquer.activities.Activity,
107         *      se.liu.ida.critiquer.activities.parameters.Parameter<T>, T)
108         */
109            @SuppressWarnings("unchecked")
110            public <T> boolean paramValueCheck(Activity a, Parameter<T> p, T newValue) {
111                    setConsistent(checkParameter(a, p, newValue));
112                    return isConsistent();
113            }
114    
115            /**
116         * The activity parameter is null here since we are called from an
117         * AgentParameter which is not directly connected to an activity. However,
118         * we can use the <code>Commander</code> of the
119         * <code>AgentParameter</code> <i>p</i> to retrieve a list of activities
120         * for which the current selection of agents is about to be selected.
121         * If there is an overlap in time between any of them and the other
122         * activities to which these agents are already assigned, the check fails.
123         * 
124         * @param <T>
125         *            type of parameter value.
126         * @param a
127         *            Activity that fired this event or null if this was a parameter
128         *            not directly connected to an activity. It is of little
129         *            interest here since we use the activities available through
130         *            the <code>Commander</code>
131         * @param p
132         *            The parameter that caused this event.
133         * @param newValue
134         *            The new value that we are supposed to check.
135         * @return
136         */
137            protected <T> boolean checkParameter(Activity a, Parameter<T> p, T newValue) {
138                    if (p instanceof AgentParameter) {
139                            AgentParameter agentParam = (AgentParameter) p;
140                            Commander myCommander = agentParam.getCommander();
141                            ArrayList<Activity> myActivities = (ArrayList<Activity>) myCommander.getAllActivities().clone();
142                            HashSet<Agent> agents = (HashSet<Agent>) newValue;
143                            ArrayList<Activity> otherActivities = new ArrayList<Activity>();
144                            for (Agent agent : agents) {
145                                     otherActivities.addAll(agent.getActivitiesForAgent());
146                            }
147                            otherActivities.removeAll(myActivities);
148                            while (!myActivities.isEmpty() && !otherActivities.isEmpty()) {
149                                    Activity activity = myActivities.remove(0);
150                                    if (overlapsAny(activity, otherActivities)) {
151                                            return false;
152                                    }
153                            }
154                    }
155                    return true;
156            }
157    
158            /**
159         * 
160         * Critiquing method that reacts to an agent being used at the same time by
161         * two different commanders
162         * 
163         * @see se.liu.ida.critiquer.activities.AbstractParamChangedListener#paramChanged(se.liu.ida.critiquer.activities.Activity,
164         *      se.liu.ida.critiquer.activities.parameters.Parameter)
165         */
166            @Override
167            public <T> void paramChanged(Activity activity, Parameter<T> p) {
168                    setConsistent(checkParameter(activity, p, null));
169            }
170    
171            /*
172         * (non-Javadoc)
173         * 
174         * @see se.liu.ida.critiquer.activities.ActivityConsistencyCheck#childOfCheck(se.liu.ida.critiquer.activities.Activity,
175         *      se.liu.ida.critiquer.activities.Activity)
176         */
177            public boolean childOfCheck(Activity parentActivity, Activity Child) {
178                    // TODO Auto-generated method stub
179                    return true;
180            }
181    
182            /*
183         * (non-Javadoc)
184         * 
185         * @see se.liu.ida.critiquer.activities.ActivityConsistencyCheck#orderingCheck(se.liu.ida.critiquer.activities.Activity,
186         *      se.liu.ida.critiquer.activities.Activity)
187         */
188            public boolean orderingCheck(Activity beforeActivity, Activity AfterActivity) {
189                    // TODO Auto-generated method stub
190                    return true;
191            }
192    
193            /*
194         * (non-Javadoc)
195         * 
196         * @see se.liu.ida.critiquer.constraints.SingletonConstraint#getDescription()
197         */
198            public String getDescription() {
199                    return "Make sure agents cannot be employed by more than one commander at the same time";
200            }
201    
202            /*
203         * (non-Javadoc)
204         * 
205         * @see se.liu.ida.critiquer.gui.ViewRenderingListener#viewUpdated(se.liu.ida.critiquer.gui.View,
206         *      java.awt.Graphics2D)
207         */
208            public void viewUpdated(View v, Graphics2D g2) {
209                    // TODO Auto-generated method stub
210    
211            }
212    
213            /**
214             * Returns the textual information that should be presented by this critic
215             * @see se.liu.ida.critiquer.constraints.TextCritic#getText()
216             */
217            public String getText() {
218                    return information;
219            }
220    
221    }