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 * @author  Tomáš Müller
021 * @version CourseTT 1.3 (University Course Timetabling)<br>
022 *          Copyright (C) 2006 - 2014 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 */
040
041public class Configuration {
042    private Long iConfigId = null;
043    private Long iOfferingId = null;
044    private HashMap<Long, Set<Lecture>> iTopLectures = new HashMap<Long, Set<Lecture>>();
045    private List<Configuration> iAltConfigurations = null;
046    private int iLimit = -1;
047    private Set<Long> iSubpartIds = null;
048
049    public Configuration(Long offeringId, Long configId, int limit) {
050        iOfferingId = offeringId;
051        iConfigId = configId;
052        iLimit = limit;
053    }
054
055    public Long getOfferingId() {
056        return iOfferingId;
057    }
058
059    public Long getConfigId() {
060        return iConfigId;
061    }
062
063    public void addTopLecture(Lecture lecture) {
064        Set<Lecture> lectures = iTopLectures.get(lecture.getSchedulingSubpartId());
065        if (lectures == null) {
066            lectures = new HashSet<Lecture>();
067            iTopLectures.put(lecture.getSchedulingSubpartId(), lectures);
068        }
069        lectures.add(lecture);
070        iSubpartIds = null;
071    }
072    
073    public Map<Long, Set<Lecture>> getTopLectures() {
074        return iTopLectures;
075    }
076
077    public Set<Long> getTopSubpartIds() {
078        return iTopLectures.keySet();
079    }
080
081    public Set<Lecture> getTopLectures(Long subpartId) {
082        return iTopLectures.get(subpartId);
083    }
084
085    public void setAltConfigurations(List<Configuration> altConfigurations) {
086        iAltConfigurations = altConfigurations;
087    }
088
089    public void addAltConfiguration(Configuration configuration) {
090        if (iAltConfigurations == null)
091            iAltConfigurations = new ArrayList<Configuration>();
092        iAltConfigurations.add(configuration);
093    }
094
095    public List<Configuration> getAltConfigurations() {
096        return iAltConfigurations;
097    }
098
099    public Set<Student> students() {
100        Set<Student> students = new HashSet<Student>();
101        for (Set<Lecture> lectures: iTopLectures.values()) {
102            for (Lecture l : lectures) {
103                students.addAll(l.students());
104            }
105        }
106        return students;
107    }
108
109    public boolean hasConflict(Assignment<Lecture, Placement> assignment, Student student) {
110        for (Lecture lecture : student.getLectures()) {
111            Placement placement = assignment.getValue(lecture);
112            if (placement == null || !this.equals(lecture.getConfiguration()))
113                continue;
114            if (student.countConflictPlacements(placement) > 0)
115                return true;
116            for (Lecture x : student.getLectures()) {
117                if (assignment.getValue(x) == null || x.equals(lecture))
118                    continue;
119                JenrlConstraint jenrl = lecture.jenrlConstraint(x);
120                if (jenrl != null && jenrl.isInConflict(assignment))
121                    return true;
122            }
123        }
124        return false;
125    }
126
127    public int getLimit() {
128        if (iLimit < 0) {
129            double totalWeight = 0.0;
130            for (Student s : students()) {
131                totalWeight += s.getOfferingWeight(getOfferingId());
132            }
133            iLimit = (int) Math.round(totalWeight);
134        }
135        return iLimit;
136    }
137
138    @Override
139    public int hashCode() {
140        return getConfigId().hashCode();
141    }
142
143    @Override
144    public boolean equals(Object o) {
145        if (o == null || !(o instanceof Configuration))
146            return false;
147        return getConfigId().equals(((Configuration) o).getConfigId());
148    }
149    
150    public Set<Long> getSubpartIds() {
151        if (iSubpartIds == null) {
152            Set<Long> subparts = new HashSet<Long>();
153            Queue<Lecture> queue = new LinkedList<Lecture>();
154            for (Map.Entry<Long, Set<Lecture>> e: getTopLectures().entrySet()) {
155                subparts.add(e.getKey());
156                queue.addAll(e.getValue());
157            }
158            Lecture lecture = null;
159            while ((lecture = queue.poll()) != null) {
160                if (lecture.getChildren() != null)
161                    for (Map.Entry<Long, List<Lecture>> e: lecture.getChildren().entrySet()) {
162                        subparts.add(e.getKey());
163                        queue.addAll(e.getValue());
164                    }
165            }
166            iSubpartIds = subparts;
167        }
168        return iSubpartIds;
169    }
170    
171    public int countSubparts() {
172        return getSubpartIds().size();
173    }
174}