001package org.cpsolver.studentsct.reservation; 002 003import java.util.Collection; 004import java.util.HashMap; 005import java.util.HashSet; 006import java.util.Map; 007import java.util.Set; 008 009import org.cpsolver.studentsct.model.AreaClassificationMajor; 010import org.cpsolver.studentsct.model.Offering; 011import org.cpsolver.studentsct.model.Student; 012 013 014/** 015 * Curriculum reservation. Students are matched based on their academic area. 016 * If classifications and/or majors are included, student must match on them as well. 017 * 018 * <br> 019 * <br> 020 * 021 * @author Tomáš Müller 022 * @version StudentSct 1.3 (Student Sectioning)<br> 023 * Copyright (C) 2007 - 2014 Tomáš Müller<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 CurriculumReservation extends Reservation { 042 private double iLimit; 043 private Set<String> iAcadAreas = new HashSet<String>(); 044 private Set<String> iClassifications = new HashSet<String>(); 045 private Set<String> iMajors = new HashSet<String>(); 046 private Set<String> iMinors = new HashSet<String>(); 047 private Map<String, Set<String>> iConcentrations = null; 048 049 /** 050 * Reservation priority (lower than individual and group reservations) 051 */ 052 public static final int DEFAULT_PRIORITY = 500; 053 /** 054 * Curriculum reservation does not need to be used 055 */ 056 public static final boolean DEFAULT_MUST_BE_USED = false; 057 /** 058 * Curriculum reservations can not assign over the limit. 059 */ 060 public static final boolean DEFAULT_CAN_ASSIGN_OVER_LIMIT = false; 061 /** 062 * Overlaps are not allowed for curriculum reservations. 063 */ 064 public static final boolean DEFAULT_ALLOW_OVERLAP = false; 065 066 /** 067 * Constructor 068 * @param id unique id 069 * @param limit reservation limit (-1 for unlimited) 070 * @param offering instructional offering on which the reservation is set 071 * @param acadAreas one or more academic areas 072 * @param classifications zero or more classifications (classifications must match if not empty) 073 * @param majors zero or more majors (majors must match if not empty) 074 * @param minors zero or more majors (minors must match if not empty) 075 */ 076 public CurriculumReservation(long id, double limit, Offering offering, Collection<String> acadAreas, Collection<String> classifications, Collection<String> majors, Collection<String> minors) { 077 super(id, offering, DEFAULT_PRIORITY, DEFAULT_MUST_BE_USED, DEFAULT_CAN_ASSIGN_OVER_LIMIT, DEFAULT_ALLOW_OVERLAP); 078 iLimit = limit; 079 if (acadAreas != null) 080 iAcadAreas.addAll(acadAreas); 081 if (classifications != null) 082 iClassifications.addAll(classifications); 083 if (majors != null) 084 iMajors.addAll(majors); 085 if (minors != null) 086 iMinors.addAll(minors); 087 } 088 089 /** 090 * Constructor 091 * @param id unique id 092 * @param limit reservation limit (-1 for unlimited) 093 * @param offering instructional offering on which the reservation is set 094 * @param acadArea academic area 095 * @param classifications zero or more classifications (classifications must match if not empty) 096 * @param majors zero or more majors (majors must match if not empty) 097 */ 098 @Deprecated 099 public CurriculumReservation(long id, double limit, Offering offering, String acadArea, Collection<String> classifications, Collection<String> majors) { 100 super(id, offering, DEFAULT_PRIORITY, DEFAULT_MUST_BE_USED, DEFAULT_CAN_ASSIGN_OVER_LIMIT, DEFAULT_ALLOW_OVERLAP); 101 iLimit = limit; 102 iAcadAreas.add(acadArea); 103 if (classifications != null) 104 iClassifications.addAll(classifications); 105 if (majors != null) 106 iMajors.addAll(majors); 107 } 108 109 /** 110 * Constructor 111 * @param id unique id 112 * @param limit reservation limit (-1 for unlimited) 113 * @param offering instructional offering on which the reservation is set 114 * @param acadAreas one or more academic areas 115 * @param classifications zero or more classifications (classifications must match if not empty) 116 * @param majors zero or more majors (majors must match if not empty) 117 * @param minors zero or more majors (minors must match if not empty) 118 * @param priority reservation priority 119 * @param mustBeUsed must this reservation be used 120 * @param canAssignOverLimit can assign over class / configuration / course limit 121 * @param allowOverlap does this reservation allow for overlaps 122 */ 123 protected CurriculumReservation(long id, double limit, Offering offering, Collection<String> acadAreas, Collection<String> classifications, Collection<String> majors, Collection<String> minors, 124 int priority, boolean mustBeUsed, boolean canAssignOverLimit, boolean allowOverlap) { 125 super(id, offering, priority, mustBeUsed, canAssignOverLimit, allowOverlap); 126 iLimit = limit; 127 if (acadAreas != null) 128 iAcadAreas.addAll(acadAreas); 129 if (classifications != null) 130 iClassifications.addAll(classifications); 131 if (majors != null) 132 iMajors.addAll(majors); 133 if (minors != null) 134 iMinors.addAll(minors); 135 } 136 137 /** 138 * Constructor 139 * @param id unique id 140 * @param limit reservation limit (-1 for unlimited) 141 * @param offering instructional offering on which the reservation is set 142 * @param acadArea academic area 143 * @param classifications zero or more classifications (classifications must match if not empty) 144 * @param majors zero or more majors (majors must match if not empty) 145 * @param priority reservation priority 146 * @param mustBeUsed must this reservation be used 147 * @param canAssignOverLimit can assign over class / configuration / course limit 148 * @param allowOverlap does this reservation allow for overlaps 149 */ 150 @Deprecated 151 protected CurriculumReservation(long id, double limit, Offering offering, String acadArea, Collection<String> classifications, Collection<String> majors, 152 int priority, boolean mustBeUsed, boolean canAssignOverLimit, boolean allowOverlap) { 153 super(id, offering, priority, mustBeUsed, canAssignOverLimit, allowOverlap); 154 iLimit = limit; 155 iAcadAreas.add(acadArea); 156 if (classifications != null) 157 iClassifications.addAll(classifications); 158 if (majors != null) 159 iMajors.addAll(majors); 160 } 161 162 /** 163 * Reservation limit (-1 for unlimited) 164 */ 165 @Override 166 public double getReservationLimit() { 167 return iLimit; 168 } 169 170 /** 171 * Set reservation limit (-1 for unlimited) 172 * @param limit reservation limit, -1 for unlimited 173 */ 174 public void setReservationLimit(double limit) { 175 iLimit = limit; 176 } 177 178 179 /** 180 * Academic areas 181 * @return selected academic areas 182 */ 183 public Set<String> getAcademicAreas() { 184 return iAcadAreas; 185 } 186 187 /** 188 * Academic area 189 * @return selected academic area 190 */ 191 @Deprecated 192 public String getAcademicArea() { 193 if (getAcademicAreas().isEmpty()) return ""; 194 return getAcademicAreas().iterator().next(); 195 } 196 197 /** 198 * Majors 199 * @return selected majors 200 */ 201 public Set<String> getMajors() { 202 return iMajors; 203 } 204 205 /** 206 * Minors 207 * @return selected minors 208 */ 209 public Set<String> getMinors() { 210 return iMinors; 211 } 212 213 /** 214 * Academic classifications 215 * @return selected academic classifications 216 */ 217 public Set<String> getClassifications() { 218 return iClassifications; 219 } 220 221 /** Concentrations for major */ 222 public Set<String> getConcentrations(String major) { 223 return (iConcentrations == null ? null : iConcentrations.get(major)); 224 } 225 226 /** Add concentration for major */ 227 public void addConcentration(String major, String concentration) { 228 if (iConcentrations == null) iConcentrations = new HashMap<String, Set<String>>(); 229 Set<String> concentrations = iConcentrations.get(major); 230 if (concentrations == null) { 231 concentrations = new HashSet<String>(); 232 iConcentrations.put(major, concentrations); 233 } 234 concentrations.add(concentration); 235 } 236 237 /** 238 * Check the area, classifications and majors 239 */ 240 @Override 241 public boolean isApplicable(Student student) { 242 if (!getMajors().isEmpty() || getMinors().isEmpty()) 243 for (AreaClassificationMajor acm: student.getAreaClassificationMajors()) 244 if (getAcademicAreas().contains(acm.getArea()) && 245 (getClassifications().isEmpty() || getClassifications().contains(acm.getClassification())) && 246 (getMajors().isEmpty() || getMajors().contains(acm.getMajor()))) { 247 Set<String> conc = getConcentrations(acm.getMajor()); 248 if (conc != null && !conc.isEmpty()) { 249 return acm.getConcentration() != null && conc.contains(acm.getConcentration()); 250 } else { 251 return true; 252 } 253 } 254 if (!getMinors().isEmpty()) 255 for (AreaClassificationMajor acm: student.getAreaClassificationMinors()) 256 if (getAcademicAreas().contains(acm.getArea()) && 257 (getClassifications().isEmpty() || getClassifications().contains(acm.getClassification())) && 258 (getMinors().contains(acm.getMajor()))) 259 return true; 260 return false; 261 } 262 263 264}