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