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 * Instructor(s) id of the choice, can be null if the section has no 130 * instructor assigned 131 * @return selected instructors 132 */ 133 public String getInstructorIds() { 134 return iInstructorIds; 135 } 136 137 /** 138 * Instructor(s) name of the choice, can be null if the section has no 139 * instructor assigned 140 * @return selected instructors 141 */ 142 public String getInstructorNames() { 143 return iInstructorNames; 144 } 145 146 /** 147 * Set instructor(s) id and name of the choice, can be null if the section has no 148 * instructor assigned 149 * @param instructorIds selected instructor ids 150 * @param instructorNames selected instructor names 151 */ 152 public void setInstructor(String instructorIds, String instructorNames) { 153 iInstructorIds = instructorIds; 154 iInstructorNames = instructorNames; 155 } 156 157 /** 158 * Choice id combined from instructionalType, time and instructorIds in the 159 * following format: instructionalType|time|instructorIds where time is of 160 * format dayCode:startSlot:length:datePatternId 161 * @return choice id 162 */ 163 public String getId() { 164 String ret = getInstructionalType() + "|"; 165 if (getTime() != null) 166 ret += getTime().getDayCode() + ":" + getTime().getStartSlot() + ":" + getTime().getLength() 167 + (getTime().getDatePatternId() == null ? "" : ":" + getTime().getDatePatternId()); 168 if (getInstructorIds() != null) 169 ret += "|" + getInstructorIds(); 170 return ret; 171 } 172 173 /** Compare two choices, based on {@link Choice#getId()} */ 174 @Override 175 public boolean equals(Object o) { 176 if (o == null || !(o instanceof Choice)) 177 return false; 178 return ((Choice) o).getId().equals(getId()); 179 } 180 181 /** Choice hash id, based on {@link Choice#getId()} */ 182 @Override 183 public int hashCode() { 184 return iHashCode; 185 } 186 187 /** 188 * List of sections of the instructional offering which represent this 189 * choice. Note that there can be multiple sections with the same choice 190 * (e.g., only if the room location differs). 191 * @return set of sections for matching this choice 192 */ 193 public Set<Section> getSections() { 194 Set<Section> sections = new HashSet<Section>(); 195 for (Config config : getOffering().getConfigs()) { 196 for (Subpart subpart : config.getSubparts()) { 197 if (!subpart.getInstructionalType().equals(getInstructionalType())) 198 continue; 199 for (Section section : subpart.getSections()) { 200 if (section.getChoice().equals(this)) 201 sections.add(section); 202 } 203 } 204 } 205 return sections; 206 } 207 208 /** 209 * List of parent sections of sections of the instructional offering which 210 * represent this choice. Note that there can be multiple sections with the 211 * same choice (e.g., only if the room location differs). 212 * @return set of parent sections 213 */ 214 public Set<Section> getParentSections() { 215 Set<Section> parentSections = new HashSet<Section>(); 216 for (Config config : getOffering().getConfigs()) { 217 for (Subpart subpart : config.getSubparts()) { 218 if (!subpart.getInstructionalType().equals(getInstructionalType())) 219 continue; 220 if (subpart.getParent() == null) 221 continue; 222 for (Section section : subpart.getSections()) { 223 if (section.getChoice().equals(this) && section.getParent() != null) 224 parentSections.add(section.getParent()); 225 } 226 } 227 } 228 return parentSections; 229 } 230 231 /** 232 * Choice name: name of the appropriate subpart + long name of time + 233 * instructor(s) name 234 * @return choice name 235 */ 236 public String getName() { 237 return (getOffering().getSubparts(getInstructionalType()).iterator().next()).getName() 238 + " " 239 + (getTime() == null ? "" : getTime().getLongName(true)) 240 + (getInstructorIds() == null ? "" : getInstructorNames() != null ? " " + getInstructorNames() : " " 241 + getInstructorIds()); 242 } 243 244 @Override 245 public String toString() { 246 return getName(); 247 } 248}