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