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