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