    001package org.cpsolver.exam.model;
    002
    003/**
    004 * Representation of an examination period. Examination timetabling model
    005 * contains a list of non-overlapping examination periods. Each period has a
    006 * day, starting time and a length (in minutes) defined. Each exam is to be
    007 * assigned to one period that is available for the exam and that is of the same
    008 * of greater length than the exam. <br>
    009 * <br>
    010 * A penalty weight ({@link ExamPeriod#getPenalty()}) can be assigned to each
    011 * period. It is used to penalize unpopular examination times (e.g., evening or
    012 * last-day). <br>
    013 * <br>
    014 * A list of periods is to be defined using
    015 * {@link ExamModel#addPeriod(Long, String, String, int, int)}, inserting
    016 * periods in the order of increasing days and times. <br>
    017 * <br>
    018 *
    019 * @version ExamTT 1.3 (Examination Timetabling)<br>
    020 *          Copyright (C) 2007 - 2014 Tomáš Müller<br>
    021 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
    022 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
    023 * <br>
    024 *          This library is free software; you can redistribute it and/or modify
    025 *          it under the terms of the GNU Lesser General Public License as
    026 *          published by the Free Software Foundation; either version 3 of the
    027 *          License, or (at your option) any later version. <br>
    028 * <br>
    029 *          This library is distributed in the hope that it will be useful, but
    030 *          WITHOUT ANY WARRANTY; without even the implied warranty of
    031 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    032 *          Lesser General Public License for more details. <br>
    033 * <br>
    034 *          You should have received a copy of the GNU Lesser General Public
    035 *          License along with this library; if not see
    036 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
    037 */
    038public class ExamPeriod implements Comparable<ExamPeriod> {
    039    private int iIndex = -1;
    040    private Long iId = null;
    041    private String iTimeStr;
    042    private String iDayStr;
    043    private int iLength;
    044    private int iDay, iTime;
    045    private int iPenalty;
    046    private Integer iStart = null;
    047    private ExamPeriod iPrev, iNext;
    048
    049    /**
    050     * Constructor
    051     *
    052     * @param id
    053     *            period unique identifier
    054     * @param day
    055     *            day (e.g., 07/12/10)
    056     * @param time
    057     *            (e.g., 8:00am-10:00am)
    058     * @param length
    059     *            length of period in minutes
    060     * @param penalty
    061     *            penalization of using this period
    062     */
    063    public ExamPeriod(Long id, String day, String time, int length, int penalty) {
    064        iId = id;
    065        iDayStr = day;
    066        iTimeStr = time;
    067        iLength = length;
    068        iPenalty = penalty;
    069    }
    070
    071    /** Period unique identifier
    072     * @return period unique id
    073     **/
    074    public Long getId() {
    075        return iId;
    076    }
    077
    078    /** Period unique identifier
    079     * @param id period unique id
    080     **/
    081    public void setId(Long id) {
    082        iId = id;
    083    }
    084
    085    /**
    086     * Day string, e.g., 07/12/10
    087     * @return day of the period
    088     */
    089    public String getDayStr() {
    090        return iDayStr;
    091    }
    092
    093    /**
    094     * Day index
    095     *
    096     * @return index of the day within all days that are used for examination
    097     */
    098    public int getDay() {
    099        return iDay;
    100    }
    101
    102    /**
    103     * Time string, e.g., 8:00am-10:00am
    104     * @return time of the period
    105     */
    106    public String getTimeStr() {
    107        return iTimeStr;
    108    }
    109
    110    /**
    111     * Time index
    112     *
    113     * @return index of the time within all time that are used for examination
    114     *         on the same day
    115     */
    116    public int getTime() {
    117        return iTime;
    118    }
    119
    120    /**
    121     * Length of period in minutes
    122     *
    123     * @return period length
    124     */
    125    public int getLength() {
    126        return iLength;
    127    }
    128
    129    /**
    130     * Period index
    131     *
    132     * @return index of the period within all examination periods
    133     */
    134    public int getIndex() {
    135        return iIndex;
    136    }
    137
    138    /**
    139     * Period weight to be used to penalize unpopular periods
    140     *
    141     * @return period weight
    142     */
    143    public int getPenalty() {
    144        return iPenalty;
    145    }
    146
    147    /**
    148     * Previous period
    149     *
    150     * @return period with index equal to index-1, null if this is the first
    151     *         period
    152     */
    153    public ExamPeriod prev() {
    154        return iPrev;
    155    }
    156
    157    /**
    158     * Next period
    159     *
    160     * @return period with index equal to index+1, null if this is the last
    161     *         period
    162     */
    163    public ExamPeriod next() {
    164        return iNext;
    165    }
    166
    167    /**
    168     * Set priod indexes (only to be used by
    169     * {@link ExamModel#addPeriod(Long, String, String, int, int)})
    170     *
    171     * @param index
    172     *            period index
    173     * @param day
    174     *            day index
    175     * @param time
    176     *            time index
    177     */
    178    public void setIndex(int index, int day, int time) {
    179        iIndex = index;
    180        iDay = day;
    181        iTime = time;
    182    }
    183
    184    /**
    185     * Set previous period (only to be used by
    186     * {@link ExamModel#addPeriod(Long, String, String, int, int)})
    187     *
    188     * @param prev
    189     *            previous period
    190     */
    191    public void setPrev(ExamPeriod prev) {
    192        iPrev = prev;
    193    }
    194
    195    /**
    196     * Set next period (only to be used by
    197     * {@link ExamModel#addPeriod(Long, String, String, int, int)})
    198     *
    199     * @param next
    200     *            next period
    201     */
    202    public void setNext(ExamPeriod next) {
    203        iNext = next;
    204    }
    205
    206    /**
    207     * String representation
    208     *
    209     * @return day string time string
    210     */
    211    @Override
    212    public String toString() {
    213        return getDayStr() + " " + getTimeStr();
    214    }
    215
    216    /**
    217     * String representation for debuging purposes
    218     *
    219     * @return day string time string (idx: index, day: day index, time: time
    220     *         index, weight: period penalty, prev: previous period, next: next
    221     *         period)
    222     */
    223    public String toDebugString() {
    224        return getDayStr() + " " + getTimeStr() + " (idx:" + getIndex() + ", day:" + getDay() + ", time:" + getTime()
    225                + ", penalty:" + getPenalty()
    226                + (prev() == null ? "" : ", prev:" + prev().getDayStr() + " " + prev().getTimeStr() + ")")
    227                + (next() == null ? "" : ", next:" + next().getDayStr() + " " + next().getTimeStr() + ")");
    228    }
    229
    230    @Override
    231    public int hashCode() {
    232        return iIndex;
    233    }
    234
    235    @Override
    236    public boolean equals(Object o) {
    237        if (o == null || !(o instanceof ExamPeriod))
    238            return false;
    239        return getIndex() == ((ExamPeriod) o).getIndex();
    240    }
    241
    242    @Override
    243    public int compareTo(ExamPeriod p) {
    244        return Double.compare(getIndex(), p.getIndex());
    245    }
    246
    247    public Integer getStartTime() { return iStart; }
    248    public void setStartTime(Integer startTime) { iStart = startTime; }
    249
    250    /**
    251     * Check if this period overlaps with the given period
    252     * @param p other period
    253     * @return true if the two periods overlap in time (considering period lengths)
    254     */
    255    public boolean hasIntersection(ExamPeriod p) {
    256        if (getIndex() == p.getIndex() || getStartTime() == null || p.getStartTime() == null) return false;
    257        return getDay() == p.getDay() && (getStartTime() + getLength() > p.getStartTime()) && (p.getStartTime() + p.getLength() > getStartTime());
    258    }
    259
    260    /**
    261     * Check if the first exam assigned to this period overlaps with the second exam assigned in the given period period
    262     * @param x1 exam of this period
    263     * @param x2 the other exam (of the period p)
    264     * @param p other period
    265     * @return true if the two periods overlap in time (considering examination lengths)
    266     */
    267    public boolean hasIntersection(Exam x1, Exam x2, ExamPeriod p) {
    268        if (getIndex() == p.getIndex() || getStartTime() == null || p.getStartTime() == null) return false;
    269        return getDay() == p.getDay() && (getStartTime() + x1.getLength() > p.getStartTime()) && (p.getStartTime() + x2.getLength() > getStartTime());
    270    }
    271}