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 }