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    }