001    package net.sf.cpsolver.studentsct.constraint;
002    
003    import java.util.Enumeration;
004    import java.util.Set;
005    import java.util.Vector;
006    
007    import net.sf.cpsolver.ifs.model.Constraint;
008    import net.sf.cpsolver.ifs.model.Value;
009    import net.sf.cpsolver.ifs.util.ToolBox;
010    import net.sf.cpsolver.studentsct.model.CourseRequest;
011    import net.sf.cpsolver.studentsct.model.Enrollment;
012    import net.sf.cpsolver.studentsct.model.Student;
013    
014    /**
015     * Abstract reservation constraint. This constraint allow some section, courses, and other 
016     * parts to be reserved to particular group of students. A reservation can be unlimited 
017     * (any number of students of that particular group can attend a course, section, etc.) or 
018     * with a limit (only given number of seats is reserved to the students of the particular
019     * group). 
020     * 
021     * <br><br>
022     * 
023     * @version
024     * StudentSct 1.1 (Student Sectioning)<br>
025     * Copyright (C) 2007 Tomáš Müller<br>
026     * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
027     * Lazenska 391, 76314 Zlin, Czech Republic<br>
028     * <br>
029     * This library is free software; you can redistribute it and/or
030     * modify it under the terms of the GNU Lesser General Public
031     * License as published by the Free Software Foundation; either
032     * version 2.1 of the License, or (at your option) any later version.
033     * <br><br>
034     * This library is distributed in the hope that it will be useful,
035     * but WITHOUT ANY WARRANTY; without even the implied warranty of
036     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
037     * Lesser General Public License for more details.
038     * <br><br>
039     * You should have received a copy of the GNU Lesser General Public
040     * License along with this library; if not, write to the Free Software
041     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
042     */
043    public abstract class Reservation extends Constraint {
044        /** Student cannot be enrolled */
045        public static int CAN_ENROLL_NO = 0;
046        /** Student can be enrolled */
047        public static int CAN_ENROLL_YES = 1;
048        /** Student can be enrolled, however, some other student has to dropped out of the section, course, etc. */
049        public static int CAN_ENROLL_INSTEAD = 2;
050    
051        /** 
052         * Check, whether a student can be enrolled into the given section, course, etc.
053         * @param student given student
054         * @return {@link Reservation#CAN_ENROLL_YES}, {@link Reservation#CAN_ENROLL_NO}, or {@link Reservation#CAN_ENROLL_INSTEAD} 
055         */ 
056        public abstract int canEnroll(Student student);
057        
058        /**
059         * Check whether the given student can be enrolled instead of another student
060         * @param student student that is to be enrolled in the particular course, section, etc.
061         * @param insteadOfStudent student, that is currently enrolled, which is going to be 
062         *  bumped out of the course, section, etc. in order to enroll given studen
063         * @return true, if the move is permitted 
064         */
065        public abstract boolean canEnrollInstead(Student student, Student insteadOfStudent);
066        
067        /** 
068         * Check whether the reservation is applicable to the given enrollment. 
069         * This means that the given enrollment contains the particular section, course, etc. 
070         * @param enrollment enrollment of a student that is being considered
071         * @return true, if the reservation applies to the enrollment
072         */ 
073        public abstract boolean isApplicable(Enrollment enrollment);
074        
075        /** 
076         * Implementation of the constraint primitives.
077         * See {@link Constraint#computeConflicts(Value, Set)} for more details.
078         */
079        public void computeConflicts(Value value, Set conflicts) {
080            Enrollment enrollment = (Enrollment)value;
081            
082            if (!isApplicable(enrollment)) return; 
083            
084            int ce = canEnroll(enrollment.getStudent());
085            
086            if (ce==CAN_ENROLL_YES) return;
087            
088            if (ce==CAN_ENROLL_NO) {
089                // Unable to bump out some other student
090                conflicts.add(enrollment);
091                return;
092            }
093            
094            // Try other bump out some other student
095            Vector conflictEnrollments = null;
096            double conflictValue = 0;
097            for (Enumeration e=assignedVariables().elements();e.hasMoreElements();) {
098                CourseRequest request = (CourseRequest) e.nextElement();
099                if (canEnrollInstead(enrollment.getStudent(),request.getStudent())) {
100                    if (conflictEnrollments==null || conflictValue>enrollment.toDouble()) {
101                        if (conflictEnrollments==null)
102                            conflictEnrollments = new Vector();
103                        else
104                            conflictEnrollments.clear();
105                        conflictEnrollments.add(request.getAssignment());
106                        conflictValue = request.getAssignment().toDouble();
107                    }
108                }
109            }
110            if (conflictEnrollments!=null && !conflictEnrollments.isEmpty()) {
111                conflicts.add(ToolBox.random(conflictEnrollments));
112                return;
113            }
114    
115            // Unable to bump out some other student
116            conflicts.add(enrollment);
117        }
118        
119        /** 
120         * Implementation of the constraint primitives.
121         * See {@link Constraint#inConflict(Value)} for more details.
122         */
123        public boolean inConflict(Value value) {
124            Enrollment enrollment = (Enrollment)value;
125            
126            if (!isApplicable(enrollment)) return false;
127    
128            return canEnroll(enrollment.getStudent())!=CAN_ENROLL_YES;
129        }
130        
131    }