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<LinkedSections> iLinkedSections = new ArrayList<LinkedSections>(); 049 private String iStatus = null; 050 private Long iEmailTimeStamp = null; 051 052 /** 053 * Constructor 054 * 055 * @param id 056 * student unique id 057 */ 058 public Student(long id) { 059 iId = id; 060 } 061 062 /** 063 * Constructor 064 * 065 * @param id 066 * student unique id 067 * @param dummy 068 * dummy flag 069 */ 070 public Student(long id, boolean dummy) { 071 iId = id; 072 iDummy = dummy; 073 } 074 075 /** Student unique id 076 * @return student unique id 077 **/ 078 public long getId() { 079 return iId; 080 } 081 082 /** Set student unique id 083 * @param id student unique id 084 **/ 085 public void setId(long id) { 086 iId = id; 087 } 088 089 /** Student's course and free time requests 090 * @return student requests 091 **/ 092 public List<Request> getRequests() { 093 return iRequests; 094 } 095 096 /** Number of requests (alternative requests are ignored) 097 * @return number of non alternative student requests 098 **/ 099 public int nrRequests() { 100 int ret = 0; 101 for (Request r : getRequests()) { 102 if (!r.isAlternative()) 103 ret++; 104 } 105 return ret; 106 } 107 108 /** Number of alternative requests 109 * @return number of alternative student requests 110 **/ 111 public int nrAlternativeRequests() { 112 int ret = 0; 113 for (Request r : getRequests()) { 114 if (r.isAlternative()) 115 ret++; 116 } 117 return ret; 118 } 119 120 /** 121 * True if the given request can be assigned to the student. A request 122 * cannot be assigned to a student when the student already has the desired 123 * number of requests assigned (i.e., number of non-alternative course 124 * requests). 125 * @param assignment current assignment 126 * @param request given request of this student 127 * @return true if the given request can be assigned 128 **/ 129 public boolean canAssign(Assignment<Request, Enrollment> assignment, Request request) { 130 if (request.isAssigned(assignment)) 131 return true; 132 int alt = 0; 133 boolean found = false; 134 for (Request r : getRequests()) { 135 if (r.equals(request)) 136 found = true; 137 boolean assigned = (r.isAssigned(assignment) || r.equals(request)); 138 boolean course = (r instanceof CourseRequest); 139 boolean waitlist = (course && ((CourseRequest) r).isWaitlist()); 140 if (r.isAlternative()) { 141 if (assigned || (!found && waitlist)) 142 alt--; 143 } else { 144 if (course && !waitlist && !assigned) 145 alt++; 146 } 147 } 148 return (alt >= 0); 149 } 150 151 /** 152 * True if the student has assigned the desired number of requests (i.e., 153 * number of non-alternative course requests). 154 * @param assignment current assignment 155 * @return true if this student has a complete schedule 156 */ 157 public boolean isComplete(Assignment<Request, Enrollment> assignment) { 158 int nrRequests = 0; 159 int nrAssignedRequests = 0; 160 for (Request r : getRequests()) { 161 if (!(r instanceof CourseRequest)) 162 continue; // ignore free times 163 if (!r.isAlternative()) 164 nrRequests++; 165 if (r.isAssigned(assignment)) 166 nrAssignedRequests++; 167 } 168 return nrAssignedRequests == nrRequests; 169 } 170 171 /** Number of assigned COURSE requests 172 * @param assignment current assignment 173 * @return number of assigned course requests 174 **/ 175 public int nrAssignedRequests(Assignment<Request, Enrollment> assignment) { 176 int nrAssignedRequests = 0; 177 for (Request r : getRequests()) { 178 if (!(r instanceof CourseRequest)) 179 continue; // ignore free times 180 if (r.isAssigned(assignment)) 181 nrAssignedRequests++; 182 } 183 return nrAssignedRequests; 184 } 185 186 @Override 187 public String toString() { 188 return (isDummy() ? "D" : "") + "S[" + getId() + "]"; 189 } 190 191 /** 192 * Student's dummy flag. Dummy students have lower value and generally 193 * should not block "real" students from getting requested courses. 194 * @return true if projected student 195 */ 196 public boolean isDummy() { 197 return iDummy; 198 } 199 200 /** 201 * Set student's dummy flag. Dummy students have lower value and generally 202 * should not block "real" students from getting requested courses. 203 * @param dummy projected student 204 */ 205 public void setDummy(boolean dummy) { 206 iDummy = dummy; 207 } 208 209 /** 210 * List of academic area - classification codes ({@link AcademicAreaCode}) 211 * for the given student 212 * @return list of academic area abbreviation & classification code pairs 213 */ 214 public List<AcademicAreaCode> getAcademicAreaClasiffications() { 215 return iAcadAreaClassifs; 216 } 217 218 /** 219 * List of major codes ({@link AcademicAreaCode}) for the given student 220 * @return list of academic area abbreviation & major code pairs 221 */ 222 public List<AcademicAreaCode> getMajors() { 223 return iMajors; 224 } 225 226 /** 227 * List of major codes ({@link AcademicAreaCode}) for the given student 228 * @return list of academic area abbreviation & minor code pairs 229 */ 230 public List<AcademicAreaCode> getMinors() { 231 return iMinors; 232 } 233 234 /** 235 * Compare two students for equality. Two students are considered equal if 236 * they have the same id. 237 */ 238 @Override 239 public boolean equals(Object object) { 240 if (object == null || !(object instanceof Student)) 241 return false; 242 return getId() == ((Student) object).getId() && isDummy() == ((Student) object).isDummy(); 243 } 244 245 /** 246 * Hash code (base only on student id) 247 */ 248 @Override 249 public int hashCode() { 250 return (int) (iId ^ (iId >>> 32)); 251 } 252 253 /** 254 * Count number of free time slots overlapping with the given enrollment 255 * @param enrollment given enrollment 256 * @return number of slots overlapping with a free time request 257 */ 258 public int countFreeTimeOverlaps(Enrollment enrollment) { 259 if (!enrollment.isCourseRequest()) return 0; 260 int ret = 0; 261 for (Section section: enrollment.getSections()) { 262 TimeLocation time = section.getTime(); 263 if (time != null) 264 ret += countFreeTimeOverlaps(time); 265 } 266 return ret; 267 } 268 269 /** 270 * Count number of free time slots overlapping with the given time 271 * @param time given time 272 * @return number of time slots overlapping with a free time request 273 */ 274 public int countFreeTimeOverlaps(TimeLocation time) { 275 int ret = 0; 276 for (Request r: iRequests) { 277 if (r instanceof FreeTimeRequest) { 278 TimeLocation freeTime = ((FreeTimeRequest)r).getTime(); 279 if (time.hasIntersection(freeTime)) 280 ret += freeTime.nrSharedHours(time) * freeTime.nrSharedDays(time); 281 } 282 } 283 return ret; 284 } 285 286 /** 287 * Get student external id 288 * @return student external unique id 289 */ 290 public String getExternalId() { return iExternalId; } 291 /** 292 * Set student external id 293 * @param externalId a free time request 294 */ 295 public void setExternalId(String externalId) { iExternalId = externalId; } 296 297 /** 298 * Get student name 299 * @return student name 300 */ 301 public String getName() { return iName; } 302 /** 303 * Set student name 304 * @param name student name 305 */ 306 public void setName(String name) { iName = name; } 307 308 /** 309 * Linked sections of this student 310 * @return linked sections of this student 311 */ 312 public List<LinkedSections> getLinkedSections() { return iLinkedSections; } 313 314 /** 315 * Get student status (online sectioning only) 316 * @return student sectioning status 317 */ 318 public String getStatus() { return iStatus; } 319 /** 320 * Set student status 321 * @param status student sectioning status 322 */ 323 public void setStatus(String status) { iStatus = status; } 324 325 /** 326 * Get last email time stamp (online sectioning only) 327 * @return student email time stamp 328 */ 329 public Long getEmailTimeStamp() { return iEmailTimeStamp; } 330 /** 331 * Set last email time stamp 332 * @param emailTimeStamp student email time stamp 333 */ 334 public void setEmailTimeStamp(Long emailTimeStamp) { iEmailTimeStamp = emailTimeStamp; } 335 336 @Override 337 public int compareTo(Student s) { 338 // real students first 339 if (isDummy()) { 340 if (!s.isDummy()) return 1; 341 } else if (s.isDummy()) return -1; 342 // then id 343 return new Long(getId()).compareTo(s.getId()); 344 } 345}