001package org.cpsolver.studentsct.model;
002
003import java.util.HashSet;
004import java.util.List;
005import java.util.Set;
006
007import org.cpsolver.coursett.model.RoomLocation;
008import org.cpsolver.coursett.model.TimeLocation;
009import org.cpsolver.ifs.assignment.Assignment;
010
011/**
012 * Representation of an unavailability. This is typically used when the student is
013 * also an instructor and he/she is teaching during some time (and hence not available
014 * for attending classes as a student). An unavailability can be marked as can overlap
015 * in time, in which case the time overlap is allowed but the overlapping time is to
016 * be minimized.<br>
017 * <br>
018 * 
019 * @version StudentSct 1.3 (Student Sectioning)<br>
020 *          Copyright (C) 2007 - 2016 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 Unavailability implements SctAssignment {
039    private Section iSection;
040    private Student iStudent;
041    private boolean iAllowOverlap;
042    private boolean iTeachingAssignment = true;
043    private Long iCourseId;
044    
045    /**
046     * Constructor
047     * @param student student
048     * @param section section that the student is teaching
049     * @param canOverlap true if student can have classes during the time, but the overlapping time should be minimized
050     */
051    public Unavailability(Student student, Section section, boolean canOverlap) {
052        iStudent = student;
053        iSection = section;
054        iAllowOverlap = canOverlap;
055        iStudent.getUnavailabilities().add(this);
056        iSection.getUnavailabilities().add(this);
057    }
058    
059    /**
060     * Student
061     */
062    public Student getStudent() { return iStudent; }
063    
064    /**
065     * Section
066     */
067    public Section getSection() { return iSection; }
068    
069    /**
070     * Optional course id (within the course of {@link Unavailability#getSection()}
071     */
072    public Long getCourseId() { return iCourseId; }
073    
074    /**
075     * Optional course id (within the course of {@link Unavailability#getSection()}
076     */
077    public void setCourseId(Long courseId) { iCourseId = courseId; }
078    
079    /**
080     * Is this a teaching assignment
081     */
082    public boolean isTeachingAssignment() { return iTeachingAssignment; }
083    
084    /**
085     * Is this a teaching assignment, defaults to true
086     */
087    public void setTeachingAssignment(boolean ta) { iTeachingAssignment = ta; }
088    
089    /**
090     * Course name taken from the {@link Unavailability#getSection()} and optional {@link Unavailability#getCourseId()}.
091     * Name of the controlling course is used when no course id is set.
092     */
093    public String getCourseName() {
094        if (getSection().getSubpart() == null) return "";
095        Offering offering = getSection().getSubpart().getConfig().getOffering();
096        if (getCourseId() != null)
097            for (Course course: offering.getCourses())
098                if (course.getId() == getCourseId())
099                    return course.getName();
100        return offering.getName();
101    }
102    
103    /**
104     * Section name using {@link Section#getName(long)} when the optional course id is provided, 
105     * using {@link Section#getName()} otherwise. 
106     */
107    public String getSectionName() {
108        if (getSection().getSubpart() == null) return getSection().getName();
109        if (getCourseId() != null)
110            return getSection().getSubpart().getName() + " " + getSection().getName(getCourseId());
111        return getSection().getSubpart().getName() + " " +getSection().getName();
112    }
113    
114    @Override
115    public long getId() {
116        return getSection().getId();
117    }
118    
119    @Override
120    public TimeLocation getTime() { return getSection().getTime(); }
121    
122    /**
123     * Can student have classes during this unavailability? The overlapping time should be minimized in this case
124     * (like with lower priority free time requests).
125     */
126    @Override
127    public boolean isAllowOverlap() { return iAllowOverlap; }
128
129    @Override
130    public List<RoomLocation> getRooms() {
131        return getSection().getRooms();
132    }
133
134    @Override
135    public int getNrRooms() {
136        return getSection().getNrRooms();
137    }
138
139    @Override
140    public boolean isOverlapping(SctAssignment assignment) {
141        if (isAllowOverlap() || assignment.isAllowOverlap()) return false;
142        if (getTime() == null || assignment.getTime() == null) return false;
143        if (assignment instanceof Section && getTime().hasIntersection(assignment.getTime())) return true;
144        return false;
145    }
146
147    @Override
148    public boolean isOverlapping(Set<? extends SctAssignment> assignments) {
149        if (isAllowOverlap()) return false;
150        if (getTime() == null) return false;
151        for (SctAssignment assignment : assignments) {
152            if (assignment.isAllowOverlap()) continue;
153            if (assignment.getTime() == null) continue;
154            if (assignment instanceof Section && getTime().hasIntersection(assignment.getTime())) return true;
155        }
156        return false;
157    }
158
159    @Override
160    public void assigned(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
161    }
162
163    @Override
164    public void unassigned(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
165    }
166
167    /**
168     * Not used, always null
169     */
170    @Override
171    public Set<Enrollment> getEnrollments(Assignment<Request, Enrollment> assignment) {
172        return null;
173    }
174
175    @Override
176    public int compareById(SctAssignment a) {
177        if (a instanceof Unavailability) {
178            return Long.valueOf(getId()).compareTo(((Unavailability)a).getId());
179        } else {
180            return 1;
181        }
182    }
183    
184    /**
185     * Create dummy enrollment of this unavailability 
186     * @return created enrollment (warning: the returned enrollment has no request)
187     **/
188    public Enrollment createEnrollment() {
189        HashSet<SctAssignment> assignments = new HashSet<SctAssignment>();
190        assignments.add(this);
191        return new Enrollment(null, 0, null, assignments, null);
192    }
193    
194    @Override
195    public boolean equals(Object o) {
196        if (o == null || !(o instanceof Unavailability)) return false;
197        return getId() == ((Unavailability)o).getId();
198    }
199    
200    @Override
201    public int hashCode() {
202        return (int) (getId() ^ (getId() >>> 32));
203    }
204}