001package org.cpsolver.studentsct.model; 002 003import java.util.ArrayList; 004import java.util.HashSet; 005import java.util.List; 006import java.util.Set; 007 008import org.cpsolver.studentsct.reservation.Reservation; 009 010 011/** 012 * Representation of a scheduling subpart. Each scheduling subpart contains id, 013 * instructional type, name, instructional offering configuration, and a list of 014 * sections. Optionally, parent-child relation between subparts can be defined. <br> 015 * <br> 016 * 017 * @version StudentSct 1.3 (Student Sectioning)<br> 018 * Copyright (C) 2007 - 2014 Tomas Muller<br> 019 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 020 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 021 * <br> 022 * This library is free software; you can redistribute it and/or modify 023 * it under the terms of the GNU Lesser General Public License as 024 * published by the Free Software Foundation; either version 3 of the 025 * License, or (at your option) any later version. <br> 026 * <br> 027 * This library is distributed in the hope that it will be useful, but 028 * WITHOUT ANY WARRANTY; without even the implied warranty of 029 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 030 * Lesser General Public License for more details. <br> 031 * <br> 032 * You should have received a copy of the GNU Lesser General Public 033 * License along with this library; if not see 034 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 035 */ 036public class Subpart implements Comparable<Subpart> { 037 private long iId = -1; 038 private String iInstructionalType = null; 039 private String iName = null; 040 private List<Section> iSections = new ArrayList<Section>(); 041 private Config iConfig = null; 042 private Subpart iParent = null; 043 private boolean iAllowOverlap = false; 044 private String iCredit = null; 045 046 /** 047 * Constructor 048 * 049 * @param id 050 * scheduling subpart unique id 051 * @param itype 052 * instructional type 053 * @param name 054 * subpart name 055 * @param config 056 * instructional offering configuration to which this subpart 057 * belongs 058 * @param parent 059 * parent subpart, if parent-child relation is defined between 060 * subparts 061 */ 062 public Subpart(long id, String itype, String name, Config config, Subpart parent) { 063 iId = id; 064 iInstructionalType = itype; 065 iName = name; 066 iConfig = config; 067 iParent = parent; 068 iConfig.getSubparts().add(this); 069 } 070 071 /** Subpart id 072 * @return scheduling subpart unique id 073 **/ 074 public long getId() { 075 return iId; 076 } 077 078 /** Instructional type, e.g., Lecture, Recitation or Laboratory 079 * @return instructional type 080 **/ 081 public String getInstructionalType() { 082 return iInstructionalType; 083 } 084 085 /** Subpart name 086 * @return scheduling subpart name 087 **/ 088 public String getName() { 089 return iName; 090 } 091 092 /** Instructional offering configuration to which this subpart belongs 093 * @return instructional offering configuration 094 **/ 095 public Config getConfig() { 096 return iConfig; 097 } 098 099 /** List of sections 100 * @return classes of this scheduling supart 101 **/ 102 public List<Section> getSections() { 103 return iSections; 104 } 105 106 /** Parent subpart, if parent-child relation is defined between subparts 107 * @return parent scheduling subpart 108 **/ 109 public Subpart getParent() { 110 return iParent; 111 } 112 113 @Override 114 public String toString() { 115 return getName(); 116 } 117 118 /** 119 * True, if this subpart is parent (or parent of a parent etc.) of the given 120 * subpart 121 * @param subpart parent scheduling subpart 122 * @return true if parent (even indirect) 123 */ 124 public boolean isParentOf(Subpart subpart) { 125 if (subpart.getParent() == null) 126 return false; 127 if (subpart.getParent().equals(this)) 128 return true; 129 return isParentOf(subpart.getParent()); 130 } 131 132 /** 133 * Compare two subparts: put parents first, use ids if there is no 134 * parent-child relation 135 */ 136 @Override 137 public int compareTo(Subpart s) { 138 if (isParentOf(s)) 139 return -1; 140 if (s.isParentOf(this)) 141 return 1; 142 int cmp = getInstructionalType().compareTo(s.getInstructionalType()); 143 if (cmp != 0) 144 return cmp; 145 return Double.compare(getId(), s.getId()); 146 } 147 148 /** List of available choices of the sections of this subpart. 149 * @return set of available choices 150 **/ 151 public Set<Choice> getChoices() { 152 Set<Choice> choices = new HashSet<Choice>(); 153 for (Section section : getSections()) { 154 choices.add(section.getChoice()); 155 } 156 return choices; 157 } 158 159 /** Minimal penalty from {@link Section#getPenalty()} 160 * @return minimal penalty 161 **/ 162 public double getMinPenalty() { 163 double min = Double.MAX_VALUE; 164 for (Section section : getSections()) { 165 min = Math.min(min, section.getPenalty()); 166 } 167 return (min == Double.MAX_VALUE ? 0.0 : min); 168 } 169 170 /** Maximal penalty from {@link Section#getPenalty()} 171 * @return maximal penalty 172 **/ 173 public double getMaxPenalty() { 174 double max = Double.MIN_VALUE; 175 for (Section section : getSections()) { 176 max = Math.max(max, section.getPenalty()); 177 } 178 return (max == Double.MIN_VALUE ? 0.0 : max); 179 } 180 181 /** Return children subparts 182 * @return children scheduling subparts 183 **/ 184 public List<Subpart> getChildren() { 185 List<Subpart> ret = new ArrayList<Subpart>(getConfig().getSubparts().size()); 186 for (Subpart s : getConfig().getSubparts()) { 187 if (this.equals(s.getParent())) 188 ret.add(s); 189 } 190 return ret; 191 } 192 193 /** Return true if overlaps are allowed, but the number of overlapping slots should be minimized. 194 * @return true if overlaps of classes of this scheduling subpart are allowed 195 **/ 196 public boolean isAllowOverlap() { 197 return iAllowOverlap; 198 } 199 200 /** Set to true if overlaps are allowed, but the number of overlapping slots should be minimized (defaults to false). 201 * @param allowOverlap are overlaps of classes of this scheduling subpart allowed 202 **/ 203 public void setAllowOverlap(boolean allowOverlap) { 204 iAllowOverlap = allowOverlap; 205 } 206 207 /** 208 * Get reservations that require sections of this subpart 209 * @return reservations that require a class of this scheduling subpart 210 */ 211 public synchronized List<Reservation> getSectionReservations() { 212 if (iSectionReservations == null) { 213 iSectionReservations = new ArrayList<Reservation>(); 214 for (Reservation r: getConfig().getOffering().getReservations()) { 215 if (r.getSections(this) != null) 216 iSectionReservations.add(r); 217 } 218 } 219 return iSectionReservations; 220 } 221 private List<Reservation> iSectionReservations = null; 222 223 /** 224 * Clear reservation information that was cached on this subpart or below 225 */ 226 public synchronized void clearReservationCache() { 227 for (Section s: getSections()) 228 s.clearReservationCache(); 229 iSectionReservations = null; 230 } 231 232 /** 233 * Sum of the section limits (unlimited, if one or more sections are unlimited) 234 * @return total class limit 235 */ 236 public int getLimit() { 237 if (iLimit == null) 238 iLimit = getLimitNoCache(); 239 return iLimit; 240 } 241 private int getLimitNoCache() { 242 int limit = 0; 243 for (Section section: getSections()) { 244 if (section.getLimit() < 0) return -1; 245 limit += section.getLimit(); 246 } 247 return limit; 248 } 249 private Integer iLimit = null; 250 251 @Override 252 public boolean equals(Object o) { 253 if (o == null || !(o instanceof Subpart)) return false; 254 return getId() == ((Subpart)o).getId(); 255 } 256 257 @Override 258 public int hashCode() { 259 return (int) (iId ^ (iId >>> 32)); 260 } 261 262 /** 263 * Set credit (Online Student Scheduling only) 264 * @param credit scheduling subpart credit 265 */ 266 public void setCredit(String credit) { iCredit = credit; } 267 268 /** 269 * Get credit (Online Student Scheduling only) 270 * @return scheduling subpart credit 271 */ 272 public String getCredit() { return iCredit; } 273}