001package org.cpsolver.studentsct.model;
002
003import java.util.ArrayList;
004import java.util.HashSet;
005import java.util.List;
006import java.util.Set;
007
008import org.cpsolver.coursett.model.RoomLocation;
009import org.cpsolver.coursett.model.TimeLocation;
010import org.cpsolver.ifs.assignment.Assignment;
011import org.cpsolver.studentsct.StudentSectioningModel;
012
013
014
015/**
016 * Representation of a request of a student for free time. This class directly
017 * implements {@link SctAssignment} API, with the appropriate free time. <br>
018 * <br>
019 * 
020 * @version StudentSct 1.3 (Student Sectioning)<br>
021 *          Copyright (C) 2007 - 2014 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 FreeTimeRequest extends Request implements SctAssignment {
040    private TimeLocation iTime = null;
041
042    /**
043     * Constructor
044     * 
045     * @param id
046     *            request unique id
047     * @param priority
048     *            request priority
049     * @param alternative
050     *            true if the request is alternative (alternative request can be
051     *            assigned instead of a non-alternative course requests, if it
052     *            is left unassigned)
053     * @param student
054     *            appropriate student
055     * @param time
056     *            appropriate time location that is requested to be free
057     */
058    public FreeTimeRequest(long id, int priority, boolean alternative, Student student, TimeLocation time) {
059        super(id, priority, alternative, student);
060        iTime = time;
061    }
062
063    /** Return requested time to be free */
064    @Override
065    public TimeLocation getTime() {
066        return iTime;
067    }
068
069    /** Assignment API: free time request has no rooms */
070    @Override
071    public int getNrRooms() {
072        return 0;
073    }
074
075    /** Assignment API: free time request has no rooms */
076    @Override
077    public List<RoomLocation> getRooms() {
078        return new ArrayList<RoomLocation>(0);
079    }
080
081    /**
082     * True, if this assignment is overlapping in time and space with the given
083     * assignment.
084     */
085    @Override
086    public boolean isOverlapping(SctAssignment assignment) {
087        if (isAllowOverlap() || assignment.isAllowOverlap()) return false;
088        if (getTime() == null || assignment.getTime() == null)
089            return false;
090        if (assignment instanceof FreeTimeRequest)
091            return false;
092        return getTime().hasIntersection(assignment.getTime());
093    }
094
095    /**
096     * True, if this assignment is overlapping in time and space with the given
097     * set of assignments.
098     */
099    @Override
100    public boolean isOverlapping(Set<? extends SctAssignment> assignments) {
101        if (isAllowOverlap())
102            return false;
103        if (getTime() == null)
104            return false;
105        for (SctAssignment assignment : assignments) {
106            if (assignment.isAllowOverlap())
107                continue;
108            if (assignment.getTime() == null)
109                continue;
110            if (assignment instanceof FreeTimeRequest)
111                return false;
112            if (getTime().hasIntersection(assignment.getTime()))
113                return true;
114        }
115        return false;
116    }
117
118    /** Create enrollment of this request 
119     * @return created enrollment
120     **/
121    public Enrollment createEnrollment() {
122        HashSet<SctAssignment> assignments = new HashSet<SctAssignment>();
123        assignments.add(this);
124        return new Enrollment(this, 0, null, assignments, null);
125    }
126
127    /**
128     * Create all possible enrollments of this request -- there is only one
129     * possible enrollment: {@link FreeTimeRequest#createEnrollment()}
130     */
131    @Override
132    public List<Enrollment> computeEnrollments(Assignment<Request, Enrollment> assignment) {
133        List<Enrollment> enrollments = new ArrayList<Enrollment>(1);
134        enrollments.add(createEnrollment());
135        return enrollments;
136    }
137
138    /** Enrollment with this assignment was assigned to a {@link Request}. */
139    @Override
140    public void assigned(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
141        ((FreeTimeRequestContext)getContext(assignment)).assigned(assignment, enrollment);
142    }
143
144    /** Enrollment with this assignment was unassigned from a {@link Request}. */
145    @Override
146    public void unassigned(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
147        ((FreeTimeRequestContext)getContext(assignment)).unassigned(assignment, enrollment);
148    }
149
150    /** Return the list of assigned enrollments that contains this assignment. */
151    @Override
152    public Set<Enrollment> getEnrollments(Assignment<Request, Enrollment> assignment) {
153        return ((FreeTimeRequestContext)getContext(assignment)).getEnrollments();
154    }
155
156    /**
157     * Request name: A for alternative, 1 + priority, Free Time, long name of
158     * requested time
159     */
160    @Override
161    public String getName() {
162        return (isAlternative() ? "A" : "") + (1 + getPriority() + (isAlternative() ? -getStudent().nrRequests() : 0))
163                + ". Free Time " + getTime().getDayHeader() + " " + getTime().getStartTimeHeader(true) + " - " + getTime().getEndTimeHeader(true);
164    }
165
166    @Override
167    public String toString() {
168        return getName();
169    }
170
171    /** Estimated bound for this request */
172    @Override
173    public double getBound() {
174        return - getWeight() * ((StudentSectioningModel)getModel()).getStudentWeights().getBound(this);
175    }
176
177    /** Free time request generally allow overlaps. */
178    @Override
179    public boolean isAllowOverlap() {
180        return (getModel() == null ? true : ((StudentSectioningModel)getModel()).getStudentWeights().isFreeTimeAllowOverlaps());
181    }
182    
183    /** Sections first, then by {@link FreeTimeRequest#getId()} */
184    @Override
185    public int compareById(SctAssignment a) {
186        if (a instanceof FreeTimeRequest) {
187            return new Long(getId()).compareTo(((FreeTimeRequest)a).getId());
188        } else {
189            return 1;
190        }
191    }
192    
193    @Override
194    public int hashCode() {
195        return super.hashCode() ^ getTime().hashCode();
196    }
197
198    
199    @Override
200    public boolean equals(Object o) {
201        return super.equals(o) && (o instanceof FreeTimeRequest) && getTime().equals(((FreeTimeRequest)o).getTime());
202    }
203    
204    public class FreeTimeRequestContext extends RequestContext {
205        private HashSet<Enrollment> iEnrollments = new HashSet<Enrollment>();
206
207        public FreeTimeRequestContext(Assignment<Request, Enrollment> assignment) {
208            super(assignment);
209            Enrollment enrollment = assignment.getValue(FreeTimeRequest.this);
210            if (enrollment != null)
211                assigned(assignment, enrollment);
212        }
213
214        /** Enrollment with this assignment was assigned to a {@link Request}. 
215         * @param assignment current assignment
216         * @param enrollment assigned enrollment
217         **/
218        public void assigned(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
219            iEnrollments.add(enrollment);
220        }
221
222        /** Enrollment with this assignment was unassigned from a {@link Request}.
223         * @param assignment current assignment
224         * @param enrollment unassigned enrollment
225         */
226        public void unassigned(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
227            iEnrollments.remove(enrollment);
228        }
229        
230        /** Return the list of assigned enrollments that contains this assignment. 
231         * @return current enrollments
232         **/
233        public Set<Enrollment> getEnrollments() {
234            return iEnrollments;
235        }
236        
237    }
238    
239    @Override
240    public RequestContext createAssignmentContext(Assignment<Request, Enrollment> assignment) {
241        return new FreeTimeRequestContext(assignment);
242    }
243
244    @Override
245    public float getMinCredit() {
246        return 0;
247    }
248
249    @Override
250    public RequestPriority getRequestPriority() {
251        return RequestPriority.Normal;
252    }
253}