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