001    package net.sf.cpsolver.exam.model;
002    
003    import java.util.HashSet;
004    import java.util.Iterator;
005    import java.util.Set;
006    import java.util.Vector;
007    
008    import net.sf.cpsolver.ifs.model.Constraint;
009    import net.sf.cpsolver.ifs.model.Value;
010    
011    /**
012     * An instructor. 
013     * <br><br>
014     * 
015     * @version
016     * ExamTT 1.1 (Examination Timetabling)<br>
017     * Copyright (C) 2008 Tomáš Müller<br>
018     * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
019     * Lazenska 391, 76314 Zlin, Czech Republic<br>
020     * <br>
021     * This library is free software; you can redistribute it and/or
022     * modify it under the terms of the GNU Lesser General Public
023     * License as published by the Free Software Foundation; either
024     * version 2.1 of the License, or (at your option) any later version.
025     * <br><br>
026     * This library is distributed in the hope that it will be useful,
027     * but WITHOUT ANY WARRANTY; without even the implied warranty of
028     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
029     * Lesser General Public License for more details.
030     * <br><br>
031     * You should have received a copy of the GNU Lesser General Public
032     * License along with this library; if not, write to the Free Software
033     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
034     */
035    public class ExamInstructor extends Constraint {
036        private HashSet[] iTable;
037        private HashSet[] iDayTable;
038        private String iName;
039        private boolean iAllowDirectConflicts = true;
040        private Vector iOwners = new Vector();
041        private boolean[] iAvailable = null;
042    
043        public ExamInstructor(ExamModel model, long id, String name) {
044            super();
045            iAllowDirectConflicts = model.getProperties().getPropertyBoolean("Instructor.AllowDirectConflicts", iAllowDirectConflicts);
046            iAssignedVariables = null;
047            iId = id;
048            iName = name;
049            iTable = new HashSet[model.getNrPeriods()];
050            for (int i=0;i<iTable.length;i++) iTable[i]=new HashSet();
051            iDayTable = new HashSet[model.getNrDays()];
052            for (int i=0;i<iDayTable.length;i++) iDayTable[i]=new HashSet();
053        }
054        
055        /**
056         * True when direct instructor conflicts are not allowed. 
057         */
058        public boolean isAllowDirectConflicts() {
059            return iAllowDirectConflicts;
060        }
061        
062        /**
063         * Set to true when direct instructor conflicts are not allowed. 
064         */
065        public void setAllowDirectConflicts(boolean allowDirectConflicts) {
066            iAllowDirectConflicts = allowDirectConflicts;
067        }
068        
069        /**
070         * Exam(s) enrolled by the instructor that are scheduled in the given period
071         */
072        public Set getExams(ExamPeriod period) { return iTable[period.getIndex()]; }
073        /**
074         * Exam(s) enrolled by the instructor that are scheduled in the given day
075         */
076        public Set getExamsADay(ExamPeriod period) { return iDayTable[period.getDay()]; }
077        /**
078         * Exam(s) enrolled by the instructor that are scheduled in the given day
079         */
080        public Set getExamsADay(int day) { return iDayTable[day]; }
081        
082        /**
083         * Compute conflicts between the given assignment of an exam and all the current assignments (of this instructor).
084         * Only not-allowed conflicts (see {@link ExamInstructor#isAllowDirectConflicts()}) are considered. 
085         */
086        public void computeConflicts(Value value, Set conflicts) {
087            if (isAllowDirectConflicts()) return;
088            ExamPlacement p = (ExamPlacement)value;
089            for (Iterator i=iTable[p.getPeriod().getIndex()].iterator();i.hasNext();) {
090                Exam exam = (Exam)i.next();
091                conflicts.add(exam.getAssignment());
092            }
093        }
094        
095        /**
096         * Check whether there is a conflict between the given assignment of an exam and all the current assignments (of this instructor).
097         * Only not-allowed conflicts (see {@link ExamInstructor#isAllowDirectConflicts()}) are considered. 
098         */
099        public boolean inConflict(Value value) {
100            if (isAllowDirectConflicts()) return false;
101            ExamPlacement p = (ExamPlacement)value;
102            return !iTable[p.getPeriod().getIndex()].isEmpty();
103        }
104        
105        /**
106         * True if the given exams can conflict (see {@link ExamInstructor#isAllowDirectConflicts()}), 
107         * or if they are placed at different periods.
108         */
109        public boolean isConsistent(Value value1, Value value2) {
110            if (isAllowDirectConflicts()) return true;
111            ExamPlacement p1 = (ExamPlacement)value1;
112            ExamPlacement p2 = (ExamPlacement)value2;
113            return (p1.getPeriod()!=p2.getPeriod());
114        }
115        
116        /**
117         * An exam was assigned, update instructor assignment table
118         */
119        public void afterAssigned(long iteration, Value value) {
120            ExamPlacement p = (ExamPlacement)value;
121            iTable[p.getPeriod().getIndex()].add(value.variable());
122            iDayTable[p.getPeriod().getDay()].add(value.variable());
123        }
124        
125        /**
126         * An exam was unassigned, update instructor assignment table
127         */
128        public void afterUnassigned(long iteration, Value value) {
129            ExamPlacement p = (ExamPlacement)value;
130            iTable[p.getPeriod().getIndex()].remove(value.variable());
131            iDayTable[p.getPeriod().getDay()].remove(value.variable());
132        }
133        
134        /**
135         * Compare two instructors for equality
136         */
137        public boolean equals(Object o) {
138            if (o==null || !(o instanceof ExamInstructor)) return false;
139            ExamInstructor s = (ExamInstructor)o;
140            return getId()==s.getId();
141        }
142        
143        /**
144         * Hash code
145         */
146        public int hashCode() {
147            return (int)(getId() ^ (getId() >>> 32));
148        }
149        
150        /**
151         * Instructor name
152         */
153        public String getName() {
154            return hasName()?iName:String.valueOf(getId());
155        }
156    
157        /**
158         * Instructor name
159         */
160        public boolean hasName() {
161            return (iName!=null && iName.length()>0);
162        }
163        
164        /**
165         * Instructor name
166         */
167        public String toString() {
168            return getName();
169        }
170        
171        /**
172         * Compare two instructors (by instructor ids)
173         */
174        public int compareTo(Object o) {
175            return toString().compareTo(o.toString());
176        }
177        
178        /**
179         * Courses and/or sections that this instructor is enrolled to
180         * @return list of {@link ExamOwner} 
181         */
182        public Vector getOwners() {
183            return iOwners;
184        }
185        
186        public boolean isHard() {
187            return !isAllowDirectConflicts();
188        }
189        
190        /**
191         * True if the student is available (for examination timetabling) during the given period
192         * @param period a period
193         * @return true if a student can attend an exam at the given period, false if otherwise
194         */
195        public boolean isAvailable(ExamPeriod period) { 
196            return (iAvailable==null?true:iAvailable[period.getIndex()]); 
197        }
198        
199        /**
200         * Set whether the student is available (for examination timetabling) during the given period
201         * @param period a period
202         * @param available true if a student can attend an exam at the given period, false if otherwise
203         */
204        public void setAvailable(int period, boolean available) {
205            if (iAvailable==null) {
206                iAvailable = new boolean[iTable.length];
207                for (int i=0;i<iTable.length;i++) iAvailable[i]=true;
208            }
209            iAvailable[period]=available; 
210        }
211    }