001package org.cpsolver.studentsct.model; 002 003import java.util.BitSet; 004import java.util.HashSet; 005import java.util.Set; 006import java.util.StringTokenizer; 007 008import org.cpsolver.coursett.model.TimeLocation; 009 010 011/** 012 * Student choice. Students have a choice of availabe time (but not room) and 013 * instructor(s). 014 * 015 * Choices of subparts that have the same instrutional type are also merged 016 * together. For instance, a student have a choice of a time/instructor of a 017 * Lecture and of a Recitation. 018 * 019 * <br> 020 * <br> 021 * 022 * @version StudentSct 1.3 (Student Sectioning)<br> 023 * Copyright (C) 2007 - 2014 Tomas Muller<br> 024 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 025 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 026 * <br> 027 * This library is free software; you can redistribute it and/or modify 028 * it under the terms of the GNU Lesser General Public License as 029 * published by the Free Software Foundation; either version 3 of the 030 * License, or (at your option) any later version. <br> 031 * <br> 032 * This library is distributed in the hope that it will be useful, but 033 * WITHOUT ANY WARRANTY; without even the implied warranty of 034 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 035 * Lesser General Public License for more details. <br> 036 * <br> 037 * You should have received a copy of the GNU Lesser General Public 038 * License along with this library; if not see 039 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 040 */ 041public class Choice { 042 private Offering iOffering = null; 043 private String iInstructionalType = null; 044 private TimeLocation iTime = null; 045 private String iInstructorIds = null; 046 private String iInstructorNames = null; 047 private int iHashCode; 048 049 /** 050 * Constructor 051 * 052 * @param offering 053 * instructional offering to which the choice belongs 054 * @param instructionalType 055 * instructional type to which the choice belongs (e.g., Lecture, 056 * Recitation or Laboratory) 057 * @param time 058 * time assignment 059 * @param instructorIds 060 * instructor(s) id 061 * @param instructorNames 062 * instructor(s) name 063 */ 064 public Choice(Offering offering, String instructionalType, TimeLocation time, String instructorIds, 065 String instructorNames) { 066 iOffering = offering; 067 iInstructionalType = instructionalType; 068 iTime = time; 069 iInstructorIds = instructorIds; 070 iInstructorNames = instructorNames; 071 iHashCode = getId().hashCode(); 072 } 073 074 /** 075 * Constructor 076 * 077 * @param offering 078 * instructional offering to which the choice belongs 079 * @param choiceId 080 * choice id is in format instructionalType|time|instructorIds 081 * where time is of format dayCode:startSlot:length:datePatternId 082 */ 083 public Choice(Offering offering, String choiceId) { 084 iOffering = offering; 085 iInstructionalType = choiceId.substring(0, choiceId.indexOf('|')); 086 choiceId = choiceId.substring(choiceId.indexOf('|') + 1); 087 String timeId = null; 088 if (choiceId.indexOf('|') < 0) { 089 timeId = choiceId; 090 } else { 091 timeId = choiceId.substring(0, choiceId.indexOf('|')); 092 iInstructorIds = choiceId.substring(choiceId.indexOf('|') + 1); 093 } 094 if (timeId != null && timeId.length() > 0) { 095 StringTokenizer s = new StringTokenizer(timeId, ":"); 096 int dayCode = Integer.parseInt(s.nextToken()); 097 int startSlot = Integer.parseInt(s.nextToken()); 098 int length = Integer.parseInt(s.nextToken()); 099 Long datePatternId = (s.hasMoreElements() ? Long.valueOf(s.nextToken()) : null); 100 iTime = new TimeLocation(dayCode, startSlot, length, 0, 0, datePatternId, "N/A", new BitSet(), 0); 101 } 102 iHashCode = getId().hashCode(); 103 } 104 105 /** Instructional offering to which this choice belongs 106 * @return instructional offering 107 **/ 108 public Offering getOffering() { 109 return iOffering; 110 } 111 112 /** 113 * Instructional type (e.g., Lecture, Recitation or Laboratory) to which 114 * this choice belongs 115 * @return instructional type 116 */ 117 public String getInstructionalType() { 118 return iInstructionalType; 119 } 120 121 /** Time location of the choice 122 * @return selected time 123 **/ 124 public TimeLocation getTime() { 125 return iTime; 126 } 127 128 /** 129 * Return true if the given choice has the same instructional type and time 130 * return true if the two choices have the same ime 131 */ 132 public boolean sameTime(Choice choice) { 133 return getInstructionalType().equals(choice.getInstructionalType()) && 134 (getTime() == null ? choice.getTime() == null : getTime().equals(choice.getTime())); 135 } 136 137 /** 138 * Instructor(s) id of the choice, can be null if the section has no 139 * instructor assigned 140 * @return selected instructors 141 */ 142 public String getInstructorIds() { 143 return iInstructorIds; 144 } 145 146 /** 147 * Instructor(s) name of the choice, can be null if the section has no 148 * instructor assigned 149 * @return selected instructors 150 */ 151 public String getInstructorNames() { 152 return iInstructorNames; 153 } 154 155 /** 156 * Set instructor(s) id and name of the choice, can be null if the section has no 157 * instructor assigned 158 * @param instructorIds selected instructor ids 159 * @param instructorNames selected instructor names 160 */ 161 public void setInstructor(String instructorIds, String instructorNames) { 162 iInstructorIds = instructorIds; 163 iInstructorNames = instructorNames; 164 } 165 166 /** 167 * Choice id combined from instructionalType, time and instructorIds in the 168 * following format: instructionalType|time|instructorIds where time is of 169 * format dayCode:startSlot:length:datePatternId 170 * @return choice id 171 */ 172 public String getId() { 173 String ret = getInstructionalType() + "|"; 174 if (getTime() != null) 175 ret += getTime().getDayCode() + ":" + getTime().getStartSlot() + ":" + getTime().getLength() 176 + (getTime().getDatePatternId() == null ? "" : ":" + getTime().getDatePatternId()); 177 if (getInstructorIds() != null) 178 ret += "|" + getInstructorIds(); 179 return ret; 180 } 181 182 /** Compare two choices, based on {@link Choice#getId()} */ 183 @Override 184 public boolean equals(Object o) { 185 if (o == null || !(o instanceof Choice)) 186 return false; 187 return ((Choice) o).getId().equals(getId()); 188 } 189 190 /** Choice hash id, based on {@link Choice#getId()} */ 191 @Override 192 public int hashCode() { 193 return iHashCode; 194 } 195 196 /** 197 * List of sections of the instructional offering which represent this 198 * choice. Note that there can be multiple sections with the same choice 199 * (e.g., only if the room location differs). 200 * @return set of sections for matching this choice 201 */ 202 public Set<Section> getSections() { 203 Set<Section> sections = new HashSet<Section>(); 204 for (Config config : getOffering().getConfigs()) { 205 for (Subpart subpart : config.getSubparts()) { 206 if (!subpart.getInstructionalType().equals(getInstructionalType())) 207 continue; 208 for (Section section : subpart.getSections()) { 209 if (section.getChoice().equals(this)) 210 sections.add(section); 211 } 212 } 213 } 214 return sections; 215 } 216 217 /** 218 * List of parent sections of sections of the instructional offering which 219 * represent this choice. Note that there can be multiple sections with the 220 * same choice (e.g., only if the room location differs). 221 * @return set of parent sections 222 */ 223 public Set<Section> getParentSections() { 224 Set<Section> parentSections = new HashSet<Section>(); 225 for (Config config : getOffering().getConfigs()) { 226 for (Subpart subpart : config.getSubparts()) { 227 if (!subpart.getInstructionalType().equals(getInstructionalType())) 228 continue; 229 if (subpart.getParent() == null) 230 continue; 231 for (Section section : subpart.getSections()) { 232 if (section.getChoice().equals(this) && section.getParent() != null) 233 parentSections.add(section.getParent()); 234 } 235 } 236 } 237 return parentSections; 238 } 239 240 /** 241 * Choice name: name of the appropriate subpart + long name of time + 242 * instructor(s) name 243 * @return choice name 244 */ 245 public String getName() { 246 return (getOffering().getSubparts(getInstructionalType()).iterator().next()).getName() 247 + " " 248 + (getTime() == null ? "" : getTime().getLongName(true)) 249 + (getInstructorIds() == null ? "" : getInstructorNames() != null ? " " + getInstructorNames() : " " 250 + getInstructorIds()); 251 } 252 253 @Override 254 public String toString() { 255 return getName(); 256 } 257}