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