001    package net.sf.cpsolver.studentsct.model;
002    
003    import java.util.BitSet;
004    import java.util.HashSet;
005    import java.util.Set;
006    import java.util.StringTokenizer;
007    
008    import net.sf.cpsolver.coursett.model.TimeLocation;
009    
010    /**
011     * Student choice. Students have a choice of availabe time (but not room) and
012     * instructor(s).
013     * 
014     * Choices of subparts that have the same instrutional type are also merged
015     * together. For instance, a student have a choice of a time/instructor of a
016     * Lecture and of a Recitation.
017     * 
018     * <br>
019     * <br>
020     * 
021     * @version StudentSct 1.2 (Student Sectioning)<br>
022     *          Copyright (C) 2007 - 2010 Tomas Muller<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     */
040    public class Choice {
041        private Offering iOffering = null;
042        private String iInstructionalType = null;
043        private TimeLocation iTime = null;
044        private String iInstructorIds = null;
045        private String iInstructorNames = null;
046        private int iHashCode;
047    
048        /**
049         * Constructor
050         * 
051         * @param offering
052         *            instructional offering to which the choice belongs
053         * @param instructionalType
054         *            instructional type to which the choice belongs (e.g., Lecture,
055         *            Recitation or Laboratory)
056         * @param time
057         *            time assignment
058         * @param instructorIds
059         *            instructor(s) id
060         * @param instructorNames
061         *            instructor(s) name
062         */
063        public Choice(Offering offering, String instructionalType, TimeLocation time, String instructorIds,
064                String instructorNames) {
065            iOffering = offering;
066            iInstructionalType = instructionalType;
067            iTime = time;
068            iInstructorIds = instructorIds;
069            iInstructorNames = instructorNames;
070            iHashCode = getId().hashCode();
071        }
072    
073        /**
074         * Constructor
075         * 
076         * @param offering
077         *            instructional offering to which the choice belongs
078         * @param choiceId
079         *            choice id is in format instructionalType|time|instructorIds
080         *            where time is of format dayCode:startSlot:length:datePatternId
081         */
082        public Choice(Offering offering, String choiceId) {
083            iOffering = offering;
084            iInstructionalType = choiceId.substring(0, choiceId.indexOf('|'));
085            choiceId = choiceId.substring(choiceId.indexOf('|') + 1);
086            String timeId = null;
087            if (choiceId.indexOf('|') < 0) {
088                timeId = choiceId;
089            } else {
090                timeId = choiceId.substring(0, choiceId.indexOf('|'));
091                iInstructorIds = choiceId.substring(choiceId.indexOf('|') + 1);
092            }
093            if (timeId != null && timeId.length() > 0) {
094                StringTokenizer s = new StringTokenizer(timeId, ":");
095                int dayCode = Integer.parseInt(s.nextToken());
096                int startSlot = Integer.parseInt(s.nextToken());
097                int length = Integer.parseInt(s.nextToken());
098                Long datePatternId = (s.hasMoreElements() ? Long.valueOf(s.nextToken()) : null);
099                iTime = new TimeLocation(dayCode, startSlot, length, 0, 0, datePatternId, "N/A", new BitSet(), 0);
100            }
101            iHashCode = getId().hashCode();
102        }
103    
104        /** Instructional offering to which this choice belongs */
105        public Offering getOffering() {
106            return iOffering;
107        }
108    
109        /**
110         * Instructional type (e.g., Lecture, Recitation or Laboratory) to which
111         * this choice belongs
112         */
113        public String getInstructionalType() {
114            return iInstructionalType;
115        }
116    
117        /** Time location of the choice */
118        public TimeLocation getTime() {
119            return iTime;
120        }
121    
122        /**
123         * Instructor(s) id of the choice, can be null if the section has no
124         * instructor assigned
125         */
126        public String getInstructorIds() {
127            return iInstructorIds;
128        }
129    
130        /**
131         * Instructor(s) name of the choice, can be null if the section has no
132         * instructor assigned
133         */
134        public String getInstructorNames() {
135            return iInstructorNames;
136        }
137        
138        /**
139         * Set instructor(s) id and name of the choice, can be null if the section has no
140         * instructor assigned
141         */
142        public void setInstructor(String instructorIds, String instructorNames) {
143            iInstructorIds = instructorIds;
144            iInstructorNames = instructorNames;
145        }
146    
147        /**
148         * Choice id combined from instructionalType, time and instructorIds in the
149         * following format: instructionalType|time|instructorIds where time is of
150         * format dayCode:startSlot:length:datePatternId
151         */
152        public String getId() {
153            String ret = getInstructionalType() + "|";
154            if (getTime() != null)
155                ret += getTime().getDayCode() + ":" + getTime().getStartSlot() + ":" + getTime().getLength()
156                        + (getTime().getDatePatternId() == null ? "" : ":" + getTime().getDatePatternId());
157            if (getInstructorIds() != null)
158                ret += "|" + getInstructorIds();
159            return ret;
160        }
161    
162        /** Compare two choices, based on {@link Choice#getId()} */
163        @Override
164        public boolean equals(Object o) {
165            if (o == null || !(o instanceof Choice))
166                return false;
167            return ((Choice) o).getId().equals(getId());
168        }
169    
170        /** Choice hash id, based on {@link Choice#getId()} */
171        @Override
172        public int hashCode() {
173            return iHashCode;
174        }
175    
176        /**
177         * List of sections of the instructional offering which represent this
178         * choice. Note that there can be multiple sections with the same choice
179         * (e.g., only if the room location differs).
180         */
181        public Set<Section> getSections() {
182            Set<Section> sections = new HashSet<Section>();
183            for (Config config : getOffering().getConfigs()) {
184                for (Subpart subpart : config.getSubparts()) {
185                    if (!subpart.getInstructionalType().equals(getInstructionalType()))
186                        continue;
187                    for (Section section : subpart.getSections()) {
188                        if (section.getChoice().equals(this))
189                            sections.add(section);
190                    }
191                }
192            }
193            return sections;
194        }
195    
196        /**
197         * List of parent sections of sections of the instructional offering which
198         * represent this choice. Note that there can be multiple sections with the
199         * same choice (e.g., only if the room location differs).
200         */
201        public Set<Section> getParentSections() {
202            Set<Section> parentSections = new HashSet<Section>();
203            for (Config config : getOffering().getConfigs()) {
204                for (Subpart subpart : config.getSubparts()) {
205                    if (!subpart.getInstructionalType().equals(getInstructionalType()))
206                        continue;
207                    if (subpart.getParent() == null)
208                        continue;
209                    for (Section section : subpart.getSections()) {
210                        if (section.getChoice().equals(this) && section.getParent() != null)
211                            parentSections.add(section.getParent());
212                    }
213                }
214            }
215            return parentSections;
216        }
217    
218        /**
219         * Choice name: name of the appropriate subpart + long name of time +
220         * instructor(s) name
221         */
222        public String getName() {
223            return (getOffering().getSubparts(getInstructionalType()).iterator().next()).getName()
224                    + " "
225                    + (getTime() == null ? "" : getTime().getLongName())
226                    + (getInstructorIds() == null ? "" : getInstructorNames() != null ? " " + getInstructorNames() : " "
227                            + getInstructorIds());
228        }
229    
230        @Override
231        public String toString() {
232            return getName();
233        }
234    }