001 package net.sf.cpsolver.studentsct.model;
002
003 import java.util.ArrayList;
004 import java.util.List;
005
006 import net.sf.cpsolver.coursett.model.TimeLocation;
007 import 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 Tomas Muller<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 */
038 public 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 }