    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}