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}