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}