001package org.cpsolver.studentsct.model; 002 003import java.util.ArrayList; 004import java.util.List; 005 006import org.cpsolver.coursett.model.TimeLocation; 007import org.cpsolver.ifs.assignment.Assignment; 008import org.cpsolver.studentsct.constraint.LinkedSections; 009 010 011 012/** 013 * Representation of a student. Each student contains id, and a list of 014 * requests. <br> 015 * <br> 016 * Last-like semester students are mark as dummy. Dummy students have lower 017 * value and generally should not block "real" students from getting requested 018 * courses. <br> 019 * <br> 020 * 021 * @version StudentSct 1.3 (Student Sectioning)<br> 022 * Copyright (C) 2007 - 2014 Tomas Muller<br> 023 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 024 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 025 * <br> 026 * This library is free software; you can redistribute it and/or modify 027 * it under the terms of the GNU Lesser General Public License as 028 * published by the Free Software Foundation; either version 3 of the 029 * License, or (at your option) any later version. <br> 030 * <br> 031 * This library is distributed in the hope that it will be useful, but 032 * WITHOUT ANY WARRANTY; without even the implied warranty of 033 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 034 * Lesser General Public License for more details. <br> 035 * <br> 036 * You should have received a copy of the GNU Lesser General Public 037 * License along with this library; if not see 038 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 039 */ 040public class Student implements Comparable<Student> { 041 private long iId; 042 private String iExternalId = null, iName = null; 043 private boolean iDummy = false; 044 private List<Request> iRequests = new ArrayList<Request>(); 045 private List<AcademicAreaCode> iAcadAreaClassifs = new ArrayList<AcademicAreaCode>(); 046 private List<AcademicAreaCode> iMajors = new ArrayList<AcademicAreaCode>(); 047 private List<AcademicAreaCode> iMinors = new ArrayList<AcademicAreaCode>(); 048 private List<AreaClassificationMajor> iACM = new ArrayList<AreaClassificationMajor>(); 049 private List<LinkedSections> iLinkedSections = new ArrayList<LinkedSections>(); 050 private String iStatus = null; 051 private Long iEmailTimeStamp = null; 052 private List<Unavailability> iUnavailabilities = new ArrayList<Unavailability>(); 053 private boolean iNeedShortDistances = false; 054 private boolean iAllowDisabled = false; 055 056 /** 057 * Constructor 058 * 059 * @param id 060 * student unique id 061 */ 062 public Student(long id) { 063 iId = id; 064 } 065 066 /** 067 * Constructor 068 * 069 * @param id 070 * student unique id 071 * @param dummy 072 * dummy flag 073 */ 074 public Student(long id, boolean dummy) { 075 iId = id; 076 iDummy = dummy; 077 } 078 079 /** Student unique id 080 * @return student unique id 081 **/ 082 public long getId() { 083 return iId; 084 } 085 086 /** Set student unique id 087 * @param id student unique id 088 **/ 089 public void setId(long id) { 090 iId = id; 091 } 092 093 /** Student's course and free time requests 094 * @return student requests 095 **/ 096 public List<Request> getRequests() { 097 return iRequests; 098 } 099 100 /** Number of requests (alternative requests are ignored) 101 * @return number of non alternative student requests 102 **/ 103 public int nrRequests() { 104 int ret = 0; 105 for (Request r : getRequests()) { 106 if (!r.isAlternative()) 107 ret++; 108 } 109 return ret; 110 } 111 112 /** Number of alternative requests 113 * @return number of alternative student requests 114 **/ 115 public int nrAlternativeRequests() { 116 int ret = 0; 117 for (Request r : getRequests()) { 118 if (r.isAlternative()) 119 ret++; 120 } 121 return ret; 122 } 123 124 /** 125 * True if the given request can be assigned to the student. A request 126 * cannot be assigned to a student when the student already has the desired 127 * number of requests assigned (i.e., number of non-alternative course 128 * requests). 129 * @param assignment current assignment 130 * @param request given request of this student 131 * @return true if the given request can be assigned 132 **/ 133 public boolean canAssign(Assignment<Request, Enrollment> assignment, Request request) { 134 if (request.isAssigned(assignment)) 135 return true; 136 int alt = 0; 137 boolean found = false; 138 for (Request r : getRequests()) { 139 if (r.equals(request)) 140 found = true; 141 boolean assigned = (r.isAssigned(assignment) || r.equals(request)); 142 boolean course = (r instanceof CourseRequest); 143 boolean waitlist = (course && ((CourseRequest) r).isWaitlist()); 144 if (r.isAlternative()) { 145 if (assigned || (!found && waitlist)) 146 alt--; 147 } else { 148 if (course && !waitlist && !assigned) 149 alt++; 150 } 151 } 152 return (alt >= 0); 153 } 154 155 /** 156 * True if the student has assigned the desired number of requests (i.e., 157 * number of non-alternative course requests). 158 * @param assignment current assignment 159 * @return true if this student has a complete schedule 160 */ 161 public boolean isComplete(Assignment<Request, Enrollment> assignment) { 162 int nrRequests = 0; 163 int nrAssignedRequests = 0; 164 for (Request r : getRequests()) { 165 if (!(r instanceof CourseRequest)) 166 continue; // ignore free times 167 if (!r.isAlternative()) 168 nrRequests++; 169 if (r.isAssigned(assignment)) 170 nrAssignedRequests++; 171 } 172 return nrAssignedRequests == nrRequests; 173 } 174 175 /** Number of assigned COURSE requests 176 * @param assignment current assignment 177 * @return number of assigned course requests 178 **/ 179 public int nrAssignedRequests(Assignment<Request, Enrollment> assignment) { 180 int nrAssignedRequests = 0; 181 for (Request r : getRequests()) { 182 if (!(r instanceof CourseRequest)) 183 continue; // ignore free times 184 if (r.isAssigned(assignment)) 185 nrAssignedRequests++; 186 } 187 return nrAssignedRequests; 188 } 189 190 @Override 191 public String toString() { 192 return (isDummy() ? "D" : "") + "S[" + getId() + "]"; 193 } 194 195 /** 196 * Student's dummy flag. Dummy students have lower value and generally 197 * should not block "real" students from getting requested courses. 198 * @return true if projected student 199 */ 200 public boolean isDummy() { 201 return iDummy; 202 } 203 204 /** 205 * Set student's dummy flag. Dummy students have lower value and generally 206 * should not block "real" students from getting requested courses. 207 * @param dummy projected student 208 */ 209 public void setDummy(boolean dummy) { 210 iDummy = dummy; 211 } 212 213 /** 214 * List of academic area - classification codes ({@link AcademicAreaCode}) 215 * for the given student 216 * @return list of academic area abbreviation & classification code pairs 217 */ 218 public List<AcademicAreaCode> getAcademicAreaClasiffications() { 219 return iAcadAreaClassifs; 220 } 221 222 /** 223 * List of major codes ({@link AcademicAreaCode}) for the given student 224 * @return list of academic area abbreviation & major code pairs 225 */ 226 public List<AcademicAreaCode> getMajors() { 227 return iMajors; 228 } 229 230 /** 231 * List of major codes ({@link AcademicAreaCode}) for the given student 232 * @return list of academic area abbreviation & minor code pairs 233 */ 234 public List<AcademicAreaCode> getMinors() { 235 return iMinors; 236 } 237 238 /** 239 * List of academic area, classification, and major codes ({@link AreaClassificationMajor}) for the given student 240 * @return list of academic area, classification, and major codes 241 */ 242 public List<AreaClassificationMajor> getAreaClassificationMajors() { 243 return iACM; 244 } 245 246 /** 247 * Compare two students for equality. Two students are considered equal if 248 * they have the same id. 249 */ 250 @Override 251 public boolean equals(Object object) { 252 if (object == null || !(object instanceof Student)) 253 return false; 254 return getId() == ((Student) object).getId() && isDummy() == ((Student) object).isDummy(); 255 } 256 257 /** 258 * Hash code (base only on student id) 259 */ 260 @Override 261 public int hashCode() { 262 return (int) (iId ^ (iId >>> 32)); 263 } 264 265 /** 266 * Count number of free time slots overlapping with the given enrollment 267 * @param enrollment given enrollment 268 * @return number of slots overlapping with a free time request 269 */ 270 public int countFreeTimeOverlaps(Enrollment enrollment) { 271 if (!enrollment.isCourseRequest()) return 0; 272 int ret = 0; 273 for (Section section: enrollment.getSections()) { 274 TimeLocation time = section.getTime(); 275 if (time != null) 276 ret += countFreeTimeOverlaps(time); 277 } 278 return ret; 279 } 280 281 /** 282 * Count number of free time slots overlapping with the given time 283 * @param time given time 284 * @return number of time slots overlapping with a free time request 285 */ 286 public int countFreeTimeOverlaps(TimeLocation time) { 287 int ret = 0; 288 for (Request r: iRequests) { 289 if (r instanceof FreeTimeRequest) { 290 TimeLocation freeTime = ((FreeTimeRequest)r).getTime(); 291 if (time.hasIntersection(freeTime)) 292 ret += freeTime.nrSharedHours(time) * freeTime.nrSharedDays(time); 293 } 294 } 295 return ret; 296 } 297 298 /** 299 * Get student external id 300 * @return student external unique id 301 */ 302 public String getExternalId() { return iExternalId; } 303 /** 304 * Set student external id 305 * @param externalId student external id 306 */ 307 public void setExternalId(String externalId) { iExternalId = externalId; } 308 309 /** 310 * Get student name 311 * @return student name 312 */ 313 public String getName() { return iName; } 314 /** 315 * Set student name 316 * @param name student name 317 */ 318 public void setName(String name) { iName = name; } 319 320 /** 321 * Linked sections of this student 322 * @return linked sections of this student 323 */ 324 public List<LinkedSections> getLinkedSections() { return iLinkedSections; } 325 326 /** 327 * Get student status (online sectioning only) 328 * @return student sectioning status 329 */ 330 public String getStatus() { return iStatus; } 331 /** 332 * Set student status 333 * @param status student sectioning status 334 */ 335 public void setStatus(String status) { iStatus = status; } 336 337 /** 338 * Get last email time stamp (online sectioning only) 339 * @return student email time stamp 340 */ 341 public Long getEmailTimeStamp() { return iEmailTimeStamp; } 342 /** 343 * Set last email time stamp 344 * @param emailTimeStamp student email time stamp 345 */ 346 public void setEmailTimeStamp(Long emailTimeStamp) { iEmailTimeStamp = emailTimeStamp; } 347 348 @Override 349 public int compareTo(Student s) { 350 // real students first 351 if (isDummy()) { 352 if (!s.isDummy()) return 1; 353 } else if (s.isDummy()) return -1; 354 // then id 355 return new Long(getId()).compareTo(s.getId()); 356 } 357 358 /** 359 * List of student unavailabilities 360 * @return student unavailabilities 361 */ 362 public List<Unavailability> getUnavailabilities() { return iUnavailabilities; } 363 364 /** 365 * Check if student is available during the given section 366 * @param section given section 367 * @return true, if available (the section cannot overlap and there is no overlapping unavailability that cannot overlap) 368 */ 369 public boolean isAvailable(Section section) { 370 if (section.isAllowOverlap() || section.getTime() == null) return true; 371 for (Unavailability unavailability: getUnavailabilities()) 372 if (unavailability.isOverlapping(section)) return false; 373 return true; 374 } 375 376 /** 377 * Check if student is available during the given enrollment 378 * @param enrollment given enrollment 379 * @return true, if available 380 */ 381 public boolean isAvailable(Enrollment enrollment) { 382 if (enrollment != null && enrollment.isCourseRequest() && !enrollment.isAllowOverlap()) 383 for (Section section: enrollment.getSections()) 384 if (!isAvailable(section)) return false; 385 return true; 386 } 387 388 /** 389 * Return true if the student needs short distances. A different distance conflict checking is employed for such students. 390 * @return true if the student needs short distances 391 */ 392 public boolean isNeedShortDistances() { 393 return iNeedShortDistances; 394 } 395 396 /** 397 * Set true if the student needs short distances. A different distance conflict checking is employed for such students. 398 * @param needShortDistances true if the student needs short distances (default is false) 399 */ 400 public void setNeedShortDistances(boolean needShortDistances) { 401 iNeedShortDistances = needShortDistances; 402 } 403 404 /** 405 * True if student can be enrolled in disabled sections, regardless if his/her reservations 406 * @return does this student allow for disabled sections 407 */ 408 public boolean isAllowDisabled() { 409 return iAllowDisabled; 410 } 411 412 /** 413 * Set to true if student can be enrolled in disabled sections, regardless if his/her reservations 414 * @param allowDisabled does this student allow for disabled sections 415 */ 416 public void setAllowDisabled(boolean allowDisabled) { 417 iAllowDisabled = allowDisabled; 418 } 419}