    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}