001package org.cpsolver.coursett.model;
002
003import java.util.ArrayList;
004import java.util.HashSet;
005import java.util.LinkedList;
006import java.util.HashMap;
007import java.util.List;
008import java.util.Map;
009import java.util.Queue;
010import java.util.Set;
011
012import org.cpsolver.coursett.constraint.JenrlConstraint;
013import org.cpsolver.ifs.assignment.Assignment;
014
015
016/**
017 * Configuration. Each course can have multiple configurations. A student needs
018 * to be enrolled into classes of one of the configurations.
019 * 
020 * @version CourseTT 1.3 (University Course Timetabling)<br>
021 *          Copyright (C) 2006 - 2014 Tomáš Müller<br>
022 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
023 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
024 * <br>
025 *          This library is free software; you can redistribute it and/or modify
026 *          it under the terms of the GNU Lesser General Public License as
027 *          published by the Free Software Foundation; either version 3 of the
028 *          License, or (at your option) any later version. <br>
029 * <br>
030 *          This library is distributed in the hope that it will be useful, but
031 *          WITHOUT ANY WARRANTY; without even the implied warranty of
032 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
033 *          Lesser General Public License for more details. <br>
034 * <br>
035 *          You should have received a copy of the GNU Lesser General Public
036 *          License along with this library; if not see
037 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
038 */
039
040public class Configuration {
041    private Long iConfigId = null;
042    private Long iOfferingId = null;
043    private HashMap<Long, Set<Lecture>> iTopLectures = new HashMap<Long, Set<Lecture>>();
044    private List<Configuration> iAltConfigurations = null;
045    private int iLimit = -1;
046    private Set<Long> iSubpartIds = null;
047
048    public Configuration(Long offeringId, Long configId, int limit) {
049        iOfferingId = offeringId;
050        iConfigId = configId;
051        iLimit = limit;
052    }
053
054    public Long getOfferingId() {
055        return iOfferingId;
056    }
057
058    public Long getConfigId() {
059        return iConfigId;
060    }
061
062    public void addTopLecture(Lecture lecture) {
063        Set<Lecture> lectures = iTopLectures.get(lecture.getSchedulingSubpartId());
064        if (lectures == null) {
065            lectures = new HashSet<Lecture>();
066            iTopLectures.put(lecture.getSchedulingSubpartId(), lectures);
067        }
068        lectures.add(lecture);
069        iSubpartIds = null;
070    }
071    
072    public Map<Long, Set<Lecture>> getTopLectures() {
073        return iTopLectures;
074    }
075
076    public Set<Long> getTopSubpartIds() {
077        return iTopLectures.keySet();
078    }
079
080    public Set<Lecture> getTopLectures(Long subpartId) {
081        return iTopLectures.get(subpartId);
082    }
083
084    public void setAltConfigurations(List<Configuration> altConfigurations) {
085        iAltConfigurations = altConfigurations;
086    }
087
088    public void addAltConfiguration(Configuration configuration) {
089        if (iAltConfigurations == null)
090            iAltConfigurations = new ArrayList<Configuration>();
091        iAltConfigurations.add(configuration);
092    }
093
094    public List<Configuration> getAltConfigurations() {
095        return iAltConfigurations;
096    }
097
098    public Set<Student> students() {
099        Set<Student> students = new HashSet<Student>();
100        for (Set<Lecture> lectures: iTopLectures.values()) {
101            for (Lecture l : lectures) {
102                students.addAll(l.students());
103            }
104        }
105        return students;
106    }
107
108    public boolean hasConflict(Assignment<Lecture, Placement> assignment, Student student) {
109        for (Lecture lecture : student.getLectures()) {
110            Placement placement = assignment.getValue(lecture);
111            if (placement == null || !this.equals(lecture.getConfiguration()))
112                continue;
113            if (student.countConflictPlacements(placement) > 0)
114                return true;
115            for (Lecture x : student.getLectures()) {
116                if (assignment.getValue(x) == null || x.equals(lecture))
117                    continue;
118                JenrlConstraint jenrl = lecture.jenrlConstraint(x);
119                if (jenrl != null && jenrl.isInConflict(assignment))
120                    return true;
121            }
122        }
123        return false;
124    }
125
126    public int getLimit() {
127        if (iLimit < 0) {
128            double totalWeight = 0.0;
129            for (Student s : students()) {
130                totalWeight += s.getOfferingWeight(getOfferingId());
131            }
132            iLimit = (int) Math.round(totalWeight);
133        }
134        return iLimit;
135    }
136
137    @Override
138    public int hashCode() {
139        return getConfigId().hashCode();
140    }
141
142    @Override
143    public boolean equals(Object o) {
144        if (o == null || !(o instanceof Configuration))
145            return false;
146        return getConfigId().equals(((Configuration) o).getConfigId());
147    }
148    
149    public Set<Long> getSubpartIds() {
150        if (iSubpartIds == null) {
151            Set<Long> subparts = new HashSet<Long>();
152            Queue<Lecture> queue = new LinkedList<Lecture>();
153            for (Map.Entry<Long, Set<Lecture>> e: getTopLectures().entrySet()) {
154                subparts.add(e.getKey());
155                queue.addAll(e.getValue());
156            }
157            Lecture lecture = null;
158            while ((lecture = queue.poll()) != null) {
159                if (lecture.getChildren() != null)
160                    for (Map.Entry<Long, List<Lecture>> e: lecture.getChildren().entrySet()) {
161                        subparts.add(e.getKey());
162                        queue.addAll(e.getValue());
163                    }
164            }
165            iSubpartIds = subparts;
166        }
167        return iSubpartIds;
168    }
169    
170    public int countSubparts() {
171        return getSubpartIds().size();
172    }
173}