001package net.sf.cpsolver.studentsct.model; 002 003import java.util.BitSet; 004import java.util.HashSet; 005import java.util.Set; 006import java.util.StringTokenizer; 007 008import 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 Tomáš Müller<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 */ 040public 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}