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 * @author  Tomáš Müller
020 * @version StudentSct 1.3 (Student Sectioning)<br>
021 *          Copyright (C) 2007 - 2016 Tomáš Müller<br>
022 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
023 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
024 * <br>
025 *          This library is free software; you can redistribute it and/or modify
026 *          it under the terms of the GNU Lesser General Public License as
027 *          published by the Free Software Foundation; either version 3 of the
028 *          License, or (at your option) any later version. <br>
029 * <br>
030 *          This library is distributed in the hope that it will be useful, but
031 *          WITHOUT ANY WARRANTY; without even the implied warranty of
032 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
033 *          Lesser General Public License for more details. <br>
034 * <br>
035 *          You should have received a copy of the GNU Lesser General Public
036 *          License along with this library; if not see
037 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
038 */
039public class Unavailability implements SctAssignment {
040    private Section iSection;
041    private Student iStudent;
042    private boolean iAllowOverlap;
043    private boolean iTeachingAssignment = true;
044    private Long iCourseId;
045    
046    /**
047     * Constructor
048     * @param student student
049     * @param section section that the student is teaching
050     * @param canOverlap true if student can have classes during the time, but the overlapping time should be minimized
051     */
052    public Unavailability(Student student, Section section, boolean canOverlap) {
053        iStudent = student;
054        iSection = section;
055        iAllowOverlap = canOverlap;
056        iStudent.getUnavailabilities().add(this);
057        iSection.getUnavailabilities().add(this);
058    }
059    
060    /**
061     * Student
062     */
063    public Student getStudent() { return iStudent; }
064    
065    /**
066     * Section
067     */
068    public Section getSection() { return iSection; }
069    
070    /**
071     * Optional course id (within the course of {@link Unavailability#getSection()}
072     */
073    public Long getCourseId() { return iCourseId; }
074    
075    /**
076     * Optional course id (within the course of {@link Unavailability#getSection()}
077     */
078    public void setCourseId(Long courseId) { iCourseId = courseId; }
079    
080    /**
081     * Is this a teaching assignment
082     */
083    public boolean isTeachingAssignment() { return iTeachingAssignment; }
084    
085    /**
086     * Is this a teaching assignment, defaults to true
087     */
088    public void setTeachingAssignment(boolean ta) { iTeachingAssignment = ta; }
089    
090    /**
091     * Course name taken from the {@link Unavailability#getSection()} and optional {@link Unavailability#getCourseId()}.
092     * Name of the controlling course is used when no course id is set.
093     */
094    public String getCourseName() {
095        if (getSection().getSubpart() == null) return "";
096        Offering offering = getSection().getSubpart().getConfig().getOffering();
097        if (getCourseId() != null)
098            for (Course course: offering.getCourses())
099                if (course.getId() == getCourseId())
100                    return course.getName();
101        return offering.getName();
102    }
103    
104    /**
105     * Section name using {@link Section#getName(long)} when the optional course id is provided, 
106     * using {@link Section#getName()} otherwise. 
107     */
108    public String getSectionName() {
109        if (getSection().getSubpart() == null) return getSection().getName();
110        if (getCourseId() != null)
111            return getSection().getSubpart().getName() + " " + getSection().getName(getCourseId());
112        return getSection().getSubpart().getName() + " " +getSection().getName();
113    }
114    
115    @Override
116    public long getId() {
117        return getSection().getId();
118    }
119    
120    @Override
121    public TimeLocation getTime() { return getSection().getTime(); }
122    
123    /**
124     * Can student have classes during this unavailability? The overlapping time should be minimized in this case
125     * (like with lower priority free time requests).
126     */
127    @Override
128    public boolean isAllowOverlap() { return iAllowOverlap; }
129
130    @Override
131    public List<RoomLocation> getRooms() {
132        return getSection().getRooms();
133    }
134
135    @Override
136    public int getNrRooms() {
137        return getSection().getNrRooms();
138    }
139
140    @Override
141    public boolean isOverlapping(SctAssignment assignment) {
142        if (isAllowOverlap() || assignment.isAllowOverlap()) return false;
143        if (getTime() == null || assignment.getTime() == null) return false;
144        if (assignment instanceof Section && getTime().hasIntersection(assignment.getTime())) return true;
145        return false;
146    }
147
148    @Override
149    public boolean isOverlapping(Set<? extends SctAssignment> assignments) {
150        if (isAllowOverlap()) return false;
151        if (getTime() == null) return false;
152        for (SctAssignment assignment : assignments) {
153            if (assignment.isAllowOverlap()) continue;
154            if (assignment.getTime() == null) continue;
155            if (assignment instanceof Section && getTime().hasIntersection(assignment.getTime())) return true;
156        }
157        return false;
158    }
159
160    @Override
161    public void assigned(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
162    }
163
164    @Override
165    public void unassigned(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
166    }
167
168    /**
169     * Not used, always null
170     */
171    @Override
172    public Set<Enrollment> getEnrollments(Assignment<Request, Enrollment> assignment) {
173        return null;
174    }
175
176    @Override
177    public int compareById(SctAssignment a) {
178        if (a instanceof Unavailability) {
179            return Long.valueOf(getId()).compareTo(((Unavailability)a).getId());
180        } else {
181            return 1;
182        }
183    }
184    
185    /**
186     * Create dummy enrollment of this unavailability 
187     * @return created enrollment (warning: the returned enrollment has no request)
188     **/
189    public Enrollment createEnrollment() {
190        HashSet<SctAssignment> assignments = new HashSet<SctAssignment>();
191        assignments.add(this);
192        return new Enrollment(null, 0, null, assignments, null);
193    }
194    
195    @Override
196    public boolean equals(Object o) {
197        if (o == null || !(o instanceof Unavailability)) return false;
198        return getId() == ((Unavailability)o).getId();
199    }
200    
201    @Override
202    public int hashCode() {
203        return (int) (getId() ^ (getId() >>> 32));
204    }
205
206    @Override
207    public String toString() {
208        if (getSection().getSubpart() == null) return getSection().getName();
209        return getCourseName() + " " + getSectionName();
210    }
211}