001    package net.sf.cpsolver.studentsct;
002    
003    import java.util.Collection;
004    import java.util.Enumeration;
005    import java.util.Iterator;
006    import java.util.Set;
007    import java.util.Vector;
008    
009    import net.sf.cpsolver.ifs.model.Model;
010    import net.sf.cpsolver.ifs.model.Neighbour;
011    import net.sf.cpsolver.ifs.solution.Solution;
012    import net.sf.cpsolver.ifs.util.DataProperties;
013    import net.sf.cpsolver.studentsct.constraint.SectionLimit;
014    import net.sf.cpsolver.studentsct.constraint.StudentConflict;
015    import net.sf.cpsolver.studentsct.heuristics.selection.BranchBoundSelection;
016    import net.sf.cpsolver.studentsct.model.Choice;
017    import net.sf.cpsolver.studentsct.model.Course;
018    import net.sf.cpsolver.studentsct.model.CourseRequest;
019    import net.sf.cpsolver.studentsct.model.Enrollment;
020    import net.sf.cpsolver.studentsct.model.Request;
021    import net.sf.cpsolver.studentsct.model.Student;
022    
023    /**
024     * Online student sectioning test (using {@link BranchBoundSelection} selection).
025     * This class is used by the online student sectioning mock-up page.
026     * <br><br>
027     * Usage:
028     * <code>
029     * StudentSctBBTest test = new StudentSctBBTest(student); //student already has all his/her requests defined<br>
030     * Solution sectioningSolution = test.getSolution(); //solution contains only one student (the given one) with his/her schedule<br>
031     * Vector sectioningMessages = test.getMessages(); //sectioning messages (to be printed in the GUI).
032     * </code>
033     * 
034     * <br><br>
035     * 
036     * @version
037     * StudentSct 1.1 (Student Sectioning)<br>
038     * Copyright (C) 2007 Tomáš Müller<br>
039     * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
040     * Lazenska 391, 76314 Zlin, Czech Republic<br>
041     * <br>
042     * This library is free software; you can redistribute it and/or
043     * modify it under the terms of the GNU Lesser General Public
044     * License as published by the Free Software Foundation; either
045     * version 2.1 of the License, or (at your option) any later version.
046     * <br><br>
047     * This library is distributed in the hope that it will be useful,
048     * but WITHOUT ANY WARRANTY; without even the implied warranty of
049     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
050     * Lesser General Public License for more details.
051     * <br><br>
052     * You should have received a copy of the GNU Lesser General Public
053     * License along with this library; if not, write to the Free Software
054     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
055     */
056    public class StudentSctBBTest extends Model {
057        private Student iStudent = null;
058        private Solution iSolution = null;
059        private long iTime;
060        private boolean iTimeoutReached = false;
061        
062        /**
063         * Constructor 
064         * @param student a student to be sectioned
065         */
066        public StudentSctBBTest(Student student) {
067            iStudent = student;
068            StudentConflict conflict = new StudentConflict();
069            for (Enumeration e=iStudent.getRequests().elements();e.hasMoreElements();) {
070                Request request = (Request)e.nextElement();
071                conflict.addVariable(request);
072                addVariable(request);
073            }
074            addGlobalConstraint(new SectionLimit(new DataProperties()));
075            addConstraint(conflict);
076        }
077        
078        /** Return the given student */
079        public Student getStudent() {
080            return iStudent;
081        }
082        
083        /** Compute and return the sectioning solution. It contains only the given student with his/her schedule */
084        public Solution getSolution() {
085            if (iSolution==null) {
086                iSolution = new Solution(this);
087                BranchBoundSelection.Selection selection = new BranchBoundSelection(new DataProperties()).getSelection(getStudent()); 
088                Neighbour neighbour = selection.select();
089                if (neighbour!=null)
090                    neighbour.assign(0);
091                iTime = selection.getTime();
092                iTimeoutReached = selection.isTimeoutReached();
093            }
094            return iSolution;
095        }
096        
097        /** Return a list of messages ({@link Message} objects) from the sectioning of the given student */ 
098        public Vector getMessages() {
099            Vector ret = new Vector();
100            ret.add(new Message(Message.sMsgLevelInfo,null,"<li>Solution found in "+iTime+" ms."));
101            if (iTimeoutReached)
102                ret.add(new Message(Message.sMsgLevelInfo,null,"<li>Time out reached, solution optimality can not be guaranteed."));
103            for (Enumeration e=getStudent().getRequests().elements();e.hasMoreElements();) {
104                Request request = (Request)e.nextElement();
105                if (!request.isAlternative() && request.getAssignment()==null) {
106                    ret.add(new Message(Message.sMsgLevelWarn,request,"<li>Unable to enroll to "+request+", "+(request instanceof CourseRequest?((CourseRequest)request).getCourses().size()==1?"course is":"courses are":"time is")+" not available."));
107                    Collection values = (request instanceof CourseRequest ? (Collection)((CourseRequest)request).getAvaiableEnrollmentsSkipSameTime() : request.computeEnrollments());
108                    for (Iterator f=values.iterator();f.hasNext();) {
109                        Enrollment enrollment = (Enrollment)f.next();
110                        Set conf = conflictValues(enrollment);
111                        if (conf!=null && !conf.isEmpty()) {
112                            Enrollment conflict = (Enrollment)conf.iterator().next();
113                            if (conflict.equals(enrollment))
114                                ret.add(new Message(Message.sMsgLevelInfo,request,"<ul>Assignment of "+enrollment.getName().replaceAll("\n", "<br>&nbsp;&nbsp;&nbsp;&nbsp;")+"<br> is not available."));
115                            else
116                                ret.add(new Message(Message.sMsgLevelInfo,request,"<ul>Assignment of "+enrollment.getName().replaceAll("\n", "<br>&nbsp;&nbsp;&nbsp;&nbsp;")+"<br> conflicts with "+conflict.getName().replaceAll("\n", "<br>&nbsp;&nbsp;&nbsp;&nbsp;")+"</ul>"));
117                        }
118                    }
119                }
120                if (request instanceof CourseRequest && request.getAssignment()!=null) {
121                    CourseRequest courseRequest = (CourseRequest)request;
122                    Enrollment enrollment = (Enrollment)request.getAssignment();
123                    Vector selectedEnrollments = courseRequest.getSelectedEnrollments(false);
124                    if (selectedEnrollments!=null && !selectedEnrollments.isEmpty() && !selectedEnrollments.contains(enrollment)) {
125                        Course course = ((Choice)courseRequest.getSelectedChoices().iterator().next()).getOffering().getCourse(getStudent());
126                        Enrollment selected = (Enrollment)selectedEnrollments.firstElement();
127                        Set conf = conflictValues(selected);
128                        if (conf!=null && !conf.isEmpty()) {
129                            ret.add(new Message(Message.sMsgLevelWarn,request,"<li>Unable to enroll selected enrollment for "+course.getName()+", seleted "+(courseRequest.getSelectedChoices().size()==1?"class is":"classes are")+" conflicting with other choices."));
130                            Enrollment conflict = (Enrollment)conf.iterator().next();
131                            if (conflict.equals(selected))
132                                ret.add(new Message(Message.sMsgLevelInfo,request,"<ul>Assignment of "+selected.getName().replaceAll("\n", "<br>&nbsp;&nbsp;&nbsp;&nbsp;")+"<br> is not available."));
133                            else
134                                ret.add(new Message(Message.sMsgLevelInfo,request,"<ul>Assignment of "+selected.getName().replaceAll("\n", "<br>&nbsp;&nbsp;&nbsp;&nbsp;")+"<br> conflicts with "+conflict.getName().replaceAll("\n", "<br>&nbsp;&nbsp;&nbsp;&nbsp;")+"</ul>"));
135                        } else {
136                            ret.add(new Message(Message.sMsgLevelWarn,request,"<li>Unable to enroll selected enrollment for "+course.getName()+"."));
137                        }
138                    }
139                }
140            }
141            return ret;
142        }
143        
144        /** Sectioning message */
145        public static class Message {
146            /** Message levels */
147            public static String[] sMsgLevels = { "INFO", "WARN", "ERROR" };
148            /** Info message level */
149            public static int sMsgLevelInfo = 0;
150            /** Warning message level */
151            public static int sMsgLevelWarn = 1;
152            /** Error message level */
153            public static int sMsgLevelError = 2;
154            
155            private int iLevel; 
156            private Request iRequest;
157            private String iMessage;
158            
159            /**
160             * Constructor
161             * @param level message level (one of {@link StudentSctBBTest.Message#sMsgLevelInfo}, {@link StudentSctBBTest.Message#sMsgLevelWarn}, and {@link StudentSctBBTest.Message#sMsgLevelError}) 
162             * @param request related course / free time request
163             * @param message a message
164             */
165            public Message(int level, Request request, String message) {
166                iLevel = level;
167                iRequest = request;
168                iMessage = message;
169            }
170            
171            /** Message level (one of {@link StudentSctBBTest.Message#sMsgLevelInfo}, {@link StudentSctBBTest.Message#sMsgLevelWarn}, and {@link StudentSctBBTest.Message#sMsgLevelError}) */
172            public int getLevel() {
173                return iLevel;
174            }
175            
176            /** Message level as string */
177            public String getLevelString() {
178                return sMsgLevels[iLevel];
179            }
180            
181            /** Related course / free time request */
182            public Request getRequest() {
183                return iRequest;
184            }
185            
186            /** Message */
187            public String getMessage() {
188                return iMessage;
189            }
190            
191            /** String representation (message level: message) */
192            public String toString() {
193                return getLevelString()+":"+getMessage();
194            }
195        }
196    }