    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}