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 * Group restriction. Students are matched based on their academic area.
016 * If classifications and/or majors are included, student must match on them as well.  
017 * <br>
018 * <br>
019 * 
020 * @author  Tomáš Müller
021 * @version StudentSct 1.3 (Student Sectioning)<br>
022 *          Copyright (C) 2007 - 2020 Tomáš Müller<br>
023 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
024 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
025 * <br>
026 *          This library is free software; you can redistribute it and/or modify
027 *          it under the terms of the GNU Lesser General Public License as
028 *          published by the Free Software Foundation; either version 3 of the
029 *          License, or (at your option) any later version. <br>
030 * <br>
031 *          This library is distributed in the hope that it will be useful, but
032 *          WITHOUT ANY WARRANTY; without even the implied warranty of
033 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
034 *          Lesser General Public License for more details. <br>
035 * <br>
036 *          You should have received a copy of the GNU Lesser General Public
037 *          License along with this library; if not see
038 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
039 */
040public class CurriculumRestriction extends Restriction {
041    private Set<String> iAcadAreas = new HashSet<String>();
042    private Set<String> iClassifications = new HashSet<String>();
043    private Set<String> iMajors = new HashSet<String>();
044    private Set<String> iMinors = new HashSet<String>();
045    private Map<String, Set<String>> iConcentrations = null;
046    
047    /**
048     * Constructor
049     * @param id restriction unique id
050     * @param offering instructional offering on which the restriction is set
051     * @param acadAreas one or more academic areas
052     * @param classifications zero or more classifications (classifications must match if not empty)
053     * @param majors zero or more majors (majors must match if not empty)
054     * @param minors zero or more majors (minors must match if not empty)
055     */
056    public CurriculumRestriction(long id, Offering offering, Collection<String> acadAreas, Collection<String> classifications, Collection<String> majors, Collection<String> minors) {
057        super(id, offering);
058        if (acadAreas != null)
059            iAcadAreas.addAll(acadAreas);
060        if (classifications != null)
061            iClassifications.addAll(classifications);
062        if (majors != null)
063            iMajors.addAll(majors);
064        if (minors != null)
065            iMinors.addAll(minors);
066    }
067    
068    /**
069     * Constructor
070     * @param id restriction unique id
071     * @param offering instructional offering on which the restriction 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     */
076    public CurriculumRestriction(long id, Offering offering, Collection<String> acadAreas, Collection<String> classifications, Collection<String> majors) {
077        super(id, offering);
078        if (acadAreas != null)
079            iAcadAreas.addAll(acadAreas);
080        if (classifications != null)
081            iClassifications.addAll(classifications);
082        if (majors != null)
083            iMajors.addAll(majors);
084    }
085    
086    /**
087     * Constructor
088     * @param id restriction unique id
089     * @param offering instructional offering on which the restriction is set
090     * @param acadArea academic area
091     * @param classifications zero or more classifications (classifications must match if not empty)
092     * @param majors zero or more majors (majors must match if not empty)
093     */
094    @Deprecated
095    public CurriculumRestriction(long id, Offering offering, String acadArea, Collection<String> classifications, Collection<String> majors) {
096        super(id, offering);
097        iAcadAreas.add(acadArea);
098        if (classifications != null)
099            iClassifications.addAll(classifications);
100        if (majors != null)
101            iMajors.addAll(majors);
102    }
103
104    /**
105     * Academic areas
106     * @return selected academic areas
107     */
108    public Set<String> getAcademicAreas() {
109        return iAcadAreas;
110    }
111    
112    /**
113     * Academic area
114     * @return selected academic area
115     */
116    @Deprecated
117    public String getAcademicArea() {
118        if (getAcademicAreas().isEmpty()) return "";
119        return getAcademicAreas().iterator().next();
120    }
121    
122    /**
123     * Majors
124     * @return selected majors
125     */
126    public Set<String> getMajors() {
127        return iMajors;
128    }
129    
130    /**
131     * Minors
132     * @return selected minors
133     */
134    public Set<String> getMinors() {
135        return iMinors;
136    }
137    
138    /**
139     * Academic classifications
140     * @return selected academic classifications
141     */
142    public Set<String> getClassifications() {
143        return iClassifications;
144    }
145    
146    /** Concentrations for major */
147    public Set<String> getConcentrations(String major) {
148        return (iConcentrations == null ? null : iConcentrations.get(major));
149    }
150    
151    /** Add concentration for major */
152    public void addConcentration(String major, String concentration) {
153        if (iConcentrations == null) iConcentrations = new HashMap<String, Set<String>>();
154        Set<String> concentrations = iConcentrations.get(major);
155        if (concentrations == null) {
156            concentrations = new HashSet<String>();
157            iConcentrations.put(major, concentrations);
158        }
159        concentrations.add(concentration);
160    }
161
162    /**
163     * Check the area, classifications and majors
164     */
165    @Override
166    public boolean isApplicable(Student student, Course course) {
167        if (!getMajors().isEmpty() || getMinors().isEmpty())
168            for (AreaClassificationMajor acm: student.getAreaClassificationMajors())
169                if (getAcademicAreas().contains(acm.getArea()) &&
170                    (getClassifications().isEmpty() || getClassifications().contains(acm.getClassification())) &&
171                    (getMajors().isEmpty() || getMajors().contains(acm.getMajor()))) {
172                    Set<String> conc = getConcentrations(acm.getMajor());
173                    if (conc != null && !conc.isEmpty()) {
174                        return acm.getConcentration() != null && conc.contains(acm.getConcentration());
175                    } else {
176                        return true;
177                    }
178                }
179        if (!getMinors().isEmpty())
180            for (AreaClassificationMajor acm: student.getAreaClassificationMinors())
181                if (getAcademicAreas().contains(acm.getArea()) &&
182                    (getClassifications().isEmpty() || getClassifications().contains(acm.getClassification())) &&
183                    (getMinors().contains(acm.getMajor())))
184                        return true;
185        return false;
186    }
187}