001package org.cpsolver.studentsct.reservation; 002 003import java.util.HashMap; 004import java.util.HashSet; 005import java.util.Map; 006import java.util.Set; 007 008import org.cpsolver.studentsct.model.Config; 009import org.cpsolver.studentsct.model.Course; 010import org.cpsolver.studentsct.model.CourseRequest; 011import org.cpsolver.studentsct.model.Enrollment; 012import org.cpsolver.studentsct.model.Offering; 013import org.cpsolver.studentsct.model.Request; 014import org.cpsolver.studentsct.model.Section; 015import org.cpsolver.studentsct.model.Student; 016import org.cpsolver.studentsct.model.Subpart; 017 018 019 020/** 021 * Abstract restriction. Restrictions are like reservations, that must be used 022 * and that do not reserve any space. Except, there can be more than one restriction 023 * on an offering and the student must meet at least one that applies to her/him. 024 * 025 * <br> 026 * <br> 027 * 028 * @author Tomáš Müller 029 * @version StudentSct 1.3 (Student Sectioning)<br> 030 * Copyright (C) 2007 - 2020 Tomáš Müller<br> 031 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 032 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 033 * <br> 034 * This library is free software; you can redistribute it and/or modify 035 * it under the terms of the GNU Lesser General Public License as 036 * published by the Free Software Foundation; either version 3 of the 037 * License, or (at your option) any later version. <br> 038 * <br> 039 * This library is distributed in the hope that it will be useful, but 040 * WITHOUT ANY WARRANTY; without even the implied warranty of 041 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 042 * Lesser General Public License for more details. <br> 043 * <br> 044 * You should have received a copy of the GNU Lesser General Public 045 * License along with this library; if not see 046 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 047 */ 048public abstract class Restriction { 049 /** Restriction unique id */ 050 private long iId = 0; 051 052 /** Instructional offering on which the restriction is set, required */ 053 private Offering iOffering; 054 055 /** One or more configurations, if applicable */ 056 private Set<Config> iConfigs = new HashSet<Config>(); 057 058 /** One or more sections, if applicable */ 059 private Map<Subpart, Set<Section>> iSections = new HashMap<Subpart, Set<Section>>(); 060 061 /** 062 * Constructor 063 * @param id restriction unique id 064 * @param offering instructional offering on which the restriction is set 065 */ 066 public Restriction(long id, Offering offering) { 067 iId = id; 068 iOffering = offering; 069 iOffering.getRestrictions().add(this); 070 iOffering.clearRestrictionCache(); 071 } 072 073 /** 074 * Restriction id 075 * @return restriction unique id 076 */ 077 public long getId() { return iId; } 078 079 /** 080 * Returns true if the student is applicable for the restriction 081 * @param student a student 082 * @param course a course 083 * @return true if student can use the restriction to get into the course / configuration / section 084 */ 085 public abstract boolean isApplicable(Student student, Course course); 086 087 @Deprecated 088 public boolean isApplicable(Student student) { 089 if (isApplicable(student, null)) return true; 090 for (Request r: student.getRequests()) { 091 if (r instanceof CourseRequest) { 092 for (Course course: ((CourseRequest) r).getCourses()) { 093 if (course.getOffering().equals(getOffering()) && isApplicable(student, course)) 094 return true; 095 } 096 } 097 } 098 return false; 099 } 100 101 /** 102 * Instructional offering on which the restriction is set. 103 * @return instructional offering 104 */ 105 public Offering getOffering() { return iOffering; } 106 107 /** 108 * One or more configurations on which the restriction is set. 109 * @return instructional offering configurations 110 */ 111 public Set<Config> getConfigs() { return iConfigs; } 112 113 /** 114 * Add a configuration (of the offering {@link Restriction#getOffering()}) to this restriction 115 * @param config instructional offering configuration 116 */ 117 public void addConfig(Config config) { 118 iConfigs.add(config); 119 } 120 121 /** 122 * One or more sections on which the restriction is set. 123 * @return class class restrictions 124 */ 125 public Map<Subpart, Set<Section>> getSections() { return iSections; } 126 127 /** 128 * One or more sections on which the restriction is set (optional). 129 * @param subpart scheduling subpart 130 * @return class restrictions for the given scheduling subpart 131 */ 132 public Set<Section> getSections(Subpart subpart) { 133 return iSections.get(subpart); 134 } 135 136 /** 137 * Add a section (of the offering {@link Restriction#getOffering()}) to this restriction. 138 * This will also add all parent sections and the appropriate configuration to the offering. 139 * @param section a class restriction 140 */ 141 public void addSection(Section section) { 142 addConfig(section.getSubpart().getConfig()); 143 while (section != null) { 144 Set<Section> sections = iSections.get(section.getSubpart()); 145 if (sections == null) { 146 sections = new HashSet<Section>(); 147 iSections.put(section.getSubpart(), sections); 148 } 149 sections.add(section); 150 section = section.getParent(); 151 } 152 } 153 154 /** 155 * Return true if the given enrollment meets the restriction. 156 * @param enrollment given enrollment 157 * @return true if the given enrollment meets the restriction 158 */ 159 public boolean isIncluded(Enrollment enrollment) { 160 // Free time request are never included 161 if (enrollment.getConfig() == null) return false; 162 163 // Check the offering 164 if (!iOffering.equals(enrollment.getConfig().getOffering())) return false; 165 166 // no restrictions -> not included 167 if (iConfigs.isEmpty() && iSections.isEmpty()) return false; 168 169 // If there are configurations, check the configuration 170 if (!iConfigs.isEmpty() && !iConfigs.contains(enrollment.getConfig())) return false; 171 172 // Check all the sections of the enrollment 173 for (Section section: enrollment.getSections()) { 174 Set<Section> sections = iSections.get(section.getSubpart()); 175 if (sections != null && !sections.contains(section)) 176 return false; 177 } 178 return true; 179 } 180 181 public boolean isIncluded(Config config) { 182 // Check the offering 183 if (!iOffering.equals(config.getOffering())) return false; 184 185 // no restrictions -> not included 186 if (iConfigs.isEmpty() && iSections.isEmpty()) return false; 187 188 // if there are configurations, check the configuration 189 if (!iConfigs.isEmpty() && !iConfigs.contains(config)) return false; 190 return true; 191 } 192 193 public boolean isIncluded(Section section) { 194 // Check the offering 195 if (!iOffering.equals(section.getSubpart().getConfig().getOffering())) return false; 196 197 // no restrictions -> not included 198 if (iConfigs.isEmpty() && iSections.isEmpty()) return false; 199 200 // if there are configurations, check the configuration 201 if (!iConfigs.isEmpty() && !iConfigs.contains(section.getSubpart().getConfig())) return false; 202 203 // check the given section 204 Set<Section> sections = iSections.get(section.getSubpart()); 205 if (sections != null && !sections.contains(section)) 206 return false; 207 208 return true; 209 } 210}