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 * @author  Tomáš Müller
021 * @version StudentSct 1.3 (Student Sectioning)<br>
022 *          Copyright (C) 2007 - 2014 Tomáš Müller<br>
023 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
024 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
025 * <br>
026 *          This library is free software; you can redistribute it and/or modify
027 *          it under the terms of the GNU Lesser General Public License as
028 *          published by the Free Software Foundation; either version 3 of the
029 *          License, or (at your option) any later version. <br>
030 * <br>
031 *          This library is distributed in the hope that it will be useful, but
032 *          WITHOUT ANY WARRANTY; without even the implied warranty of
033 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
034 *          Lesser General Public License for more details. <br>
035 * <br>
036 *          You should have received a copy of the GNU Lesser General Public
037 *          License along with this library; if not see
038 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
039 */
040public class FreeTimeRequest extends Request implements SctAssignment {
041    private TimeLocation iTime = null;
042
043    /**
044     * Constructor
045     * 
046     * @param id
047     *            request unique id
048     * @param priority
049     *            request priority
050     * @param alternative
051     *            true if the request is alternative (alternative request can be
052     *            assigned instead of a non-alternative course requests, if it
053     *            is left unassigned)
054     * @param student
055     *            appropriate student
056     * @param time
057     *            appropriate time location that is requested to be free
058     */
059    public FreeTimeRequest(long id, int priority, boolean alternative, Student student, TimeLocation time) {
060        super(id, priority, alternative, student);
061        iTime = time;
062    }
063
064    /** Return requested time to be free */
065    @Override
066    public TimeLocation getTime() {
067        return iTime;
068    }
069
070    /** Assignment API: free time request has no rooms */
071    @Override
072    public int getNrRooms() {
073        return 0;
074    }
075
076    /** Assignment API: free time request has no rooms */
077    @Override
078    public List<RoomLocation> getRooms() {
079        return new ArrayList<RoomLocation>(0);
080    }
081
082    /**
083     * True, if this assignment is overlapping in time and space with the given
084     * assignment.
085     */
086    @Override
087    public boolean isOverlapping(SctAssignment assignment) {
088        if (isAllowOverlap() || assignment.isAllowOverlap()) return false;
089        if (getTime() == null || assignment.getTime() == null)
090            return false;
091        if (assignment instanceof FreeTimeRequest)
092            return false;
093        return getTime().hasIntersection(assignment.getTime());
094    }
095
096    /**
097     * True, if this assignment is overlapping in time and space with the given
098     * set of assignments.
099     */
100    @Override
101    public boolean isOverlapping(Set<? extends SctAssignment> assignments) {
102        if (isAllowOverlap())
103            return false;
104        if (getTime() == null)
105            return false;
106        for (SctAssignment assignment : assignments) {
107            if (assignment.isAllowOverlap())
108                continue;
109            if (assignment.getTime() == null)
110                continue;
111            if (assignment instanceof FreeTimeRequest)
112                return false;
113            if (getTime().hasIntersection(assignment.getTime()))
114                return true;
115        }
116        return false;
117    }
118
119    /** Create enrollment of this request 
120     * @return created enrollment
121     **/
122    public Enrollment createEnrollment() {
123        HashSet<SctAssignment> assignments = new HashSet<SctAssignment>();
124        assignments.add(this);
125        return new Enrollment(this, 0, null, assignments, null);
126    }
127
128    /**
129     * Create all possible enrollments of this request -- there is only one
130     * possible enrollment: {@link FreeTimeRequest#createEnrollment()}
131     */
132    @Override
133    public List<Enrollment> computeEnrollments(Assignment<Request, Enrollment> assignment) {
134        List<Enrollment> enrollments = new ArrayList<Enrollment>(1);
135        enrollments.add(createEnrollment());
136        return enrollments;
137    }
138
139    /** Enrollment with this assignment was assigned to a {@link Request}. */
140    @Override
141    public void assigned(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
142        ((FreeTimeRequestContext)getContext(assignment)).assigned(assignment, enrollment);
143    }
144
145    /** Enrollment with this assignment was unassigned from a {@link Request}. */
146    @Override
147    public void unassigned(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
148        ((FreeTimeRequestContext)getContext(assignment)).unassigned(assignment, enrollment);
149    }
150
151    /** Return the list of assigned enrollments that contains this assignment. */
152    @Override
153    public Set<Enrollment> getEnrollments(Assignment<Request, Enrollment> assignment) {
154        return ((FreeTimeRequestContext)getContext(assignment)).getEnrollments();
155    }
156
157    /**
158     * Request name: A for alternative, 1 + priority, Free Time, long name of
159     * requested time
160     */
161    @Override
162    public String getName() {
163        return (isAlternative() ? "A" : "") + (1 + getPriority() + (isAlternative() ? -getStudent().nrRequests() : 0))
164                + ". Free Time " + getTime().getDayHeader() + " " + getTime().getStartTimeHeader(true) + " - " + getTime().getEndTimeHeader(true);
165    }
166
167    @Override
168    public String toString() {
169        return getName();
170    }
171
172    /** Estimated bound for this request */
173    @Override
174    public double getBound() {
175        return - getWeight() * ((StudentSectioningModel)getModel()).getStudentWeights().getBound(this);
176    }
177
178    /** Free time request generally allow overlaps. */
179    @Override
180    public boolean isAllowOverlap() {
181        return (getModel() == null ? true : ((StudentSectioningModel)getModel()).getStudentWeights().isFreeTimeAllowOverlaps());
182    }
183    
184    /** Sections first, then by {@link FreeTimeRequest#getId()} */
185    @Override
186    public int compareById(SctAssignment a) {
187        if (a instanceof FreeTimeRequest) {
188            return Long.valueOf(getId()).compareTo(((FreeTimeRequest)a).getId());
189        } else {
190            return 1;
191        }
192    }
193    
194    @Override
195    public int hashCode() {
196        return super.hashCode() ^ getTime().hashCode();
197    }
198
199    
200    @Override
201    public boolean equals(Object o) {
202        return super.equals(o) && (o instanceof FreeTimeRequest) && getTime().equals(((FreeTimeRequest)o).getTime());
203    }
204    
205    public class FreeTimeRequestContext extends RequestContext {
206        private HashSet<Enrollment> iEnrollments = new HashSet<Enrollment>();
207
208        public FreeTimeRequestContext(Assignment<Request, Enrollment> assignment) {
209            super(assignment);
210            Enrollment enrollment = assignment.getValue(FreeTimeRequest.this);
211            if (enrollment != null)
212                assigned(assignment, enrollment);
213        }
214
215        /** Enrollment with this assignment was assigned to a {@link Request}. 
216         * @param assignment current assignment
217         * @param enrollment assigned enrollment
218         **/
219        public void assigned(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
220            iEnrollments.add(enrollment);
221        }
222
223        /** Enrollment with this assignment was unassigned from a {@link Request}.
224         * @param assignment current assignment
225         * @param enrollment unassigned enrollment
226         */
227        public void unassigned(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
228            iEnrollments.remove(enrollment);
229        }
230        
231        /** Return the list of assigned enrollments that contains this assignment. 
232         * @return current enrollments
233         **/
234        public Set<Enrollment> getEnrollments() {
235            return iEnrollments;
236        }
237        
238    }
239    
240    @Override
241    public RequestContext createAssignmentContext(Assignment<Request, Enrollment> assignment) {
242        return new FreeTimeRequestContext(assignment);
243    }
244
245    @Override
246    public float getMinCredit() {
247        return 0;
248    }
249
250    @Override
251    public RequestPriority getRequestPriority() {
252        return RequestPriority.Normal;
253    }
254}