Java tutorial
/* * UniTime 3.2 - 3.5 (University Timetabling Application) * Copyright (C) 2008 - 2013, UniTime LLC, and individual contributors * as indicated by the @authors tag. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see <http://www.gnu.org/licenses/>. * */ package org.unitime.timetable.model; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.TreeSet; import org.cpsolver.coursett.model.TimeLocation; import org.hibernate.Query; import org.unitime.timetable.defaults.ApplicationProperty; import org.unitime.timetable.model.base.BaseTimePattern; import org.unitime.timetable.model.dao.TimePatternDAO; import org.unitime.timetable.security.UserContext; import org.unitime.timetable.security.rights.Right; import org.unitime.timetable.webutil.RequiredTimeTable; /** * @author Tomas Muller, Stephanie Schluttenhofer */ public class TimePattern extends BaseTimePattern implements Comparable<TimePattern> { private static final long serialVersionUID = 1L; public static final int sTypeStandard = 0; public static final int sTypeEvening = 1; public static final int sTypeSaturday = 2; public static final int sTypeMorning = 3; public static final int sTypeExtended = 4; public static final int sTypeExactTime = 5; public static final String[] sTypes = new String[] { "Standard", "Evening", "Saturday", "Morning", "Extended", "Exact Time" }; /** Request attribute name for available time patterns **/ public static String TIME_PATTERN_ATTR_NAME = "timePatternsList"; /*[CONSTRUCTOR MARKER BEGIN]*/ public TimePattern() { super(); } /** * Constructor for primary key */ public TimePattern(java.lang.Long uniqueId) { super(uniqueId); } /*[CONSTRUCTOR MARKER END]*/ public static List<TimePattern> findAll(Session session, Boolean visible) { return findAll(session.getUniqueId(), visible); } public static List<TimePattern> findAll(Long sessionId, Boolean visible) { String query = "from TimePattern tp " + "where tp.session.uniqueId=:sessionId"; if (visible != null) query += " and visible=:visible"; org.hibernate.Session hibSession = new TimePatternDAO().getSession(); Query q = hibSession.createQuery(query); q.setCacheable(true); q.setLong("sessionId", sessionId.longValue()); if (visible != null) q.setBoolean("visible", visible.booleanValue()); List<TimePattern> v = q.list(); Collections.sort(v); return v; } public static List<TimePattern> findApplicable(UserContext user, int minPerWeek, boolean includeExactTime, Department department) throws Exception { boolean includeExtended = user.getCurrentAuthority().hasRight(Right.ExtendedTimePatterns); return findByMinPerWeek(user.getCurrentAcademicSessionId(), false, includeExtended, includeExactTime, minPerWeek, (includeExtended ? null : department)); } public static List<TimePattern> findByMinPerWeek(Session session, boolean includeHidden, boolean includeExtended, boolean includeExactTime, int minPerWeek, Department department) { return findByMinPerWeek(session.getUniqueId(), includeHidden, includeExtended, includeExactTime, minPerWeek, department); } public static List<TimePattern> findByMinPerWeek(Long sessionId, boolean includeHidden, boolean includeExtended, boolean includeExactTime, int minPerWeek, Department department) { List<TimePattern> list = null; if (includeExactTime && department == null) { list = (List<TimePattern>) new TimePatternDAO().getSession() .createQuery( "select distinct p from TimePattern as p " + "where p.session.uniqueId=:sessionId and " + (!includeHidden ? "p.visible=true and " : "") + "(p.type=" + sTypeExactTime + " or ( p.type!=" + sTypeExactTime + " and " + (!includeExtended ? "p.type!=" + sTypeExtended + " and " : "") + "p.minPerMtg * p.nrMeetings = :minPerWeek ))") .setLong("sessionId", sessionId.longValue()).setInteger("minPerWeek", minPerWeek) .setCacheable(true).list(); } else { list = (List<TimePattern>) (new TimePatternDAO()).getSession() .createQuery("select distinct p from TimePattern as p " + "where p.session.uniqueId=:sessionId and " + "p.type!=" + sTypeExactTime + " and " + (!includeHidden ? "p.visible=true and " : "") + (!includeExtended ? "p.type!=" + sTypeExtended + " and " : "") + "p.minPerMtg * p.nrMeetings = :minPerWeek") .setLong("sessionId", sessionId.longValue()).setInteger("minPerWeek", minPerWeek) .setCacheable(true).list(); } if (!includeExtended && department != null) { for (Iterator i = department.getTimePatterns().iterator(); i.hasNext();) { TimePattern tp = (TimePattern) i.next(); if (tp.getMinPerMtg().intValue() * tp.getNrMeetings().intValue() != minPerWeek) continue; if (tp.getType().intValue() != sTypeExtended) continue; if (!includeHidden && !tp.isVisible().booleanValue()) continue; list.add(tp); } } if (includeExactTime && department != null) { for (Iterator i = department.getTimePatterns().iterator(); i.hasNext();) { TimePattern tp = (TimePattern) i.next(); if (tp.getType().intValue() != sTypeExactTime) continue; list.add(tp); break; } } Collections.sort(list); return list; } public static TimePattern findByName(Session session, String name) { return findByName(session.getUniqueId(), name); } public static TimePattern findByName(Long sessionId, String name) { List list = (new TimePatternDAO()).getSession() .createQuery("select distinct p from TimePattern as p " + "where p.session.uniqueId=:sessionId and " + "p.name=:name") .setLong("sessionId", sessionId.longValue()).setText("name", name).setCacheable(true).list(); if (list == null || list.isEmpty()) return null; return (TimePattern) list.get(0); } public static TimePattern findExactTime(Long sessionId) { List list = (new TimePatternDAO()).getSession() .createQuery("select distinct p from TimePattern as p " + "where p.session.uniqueId=:sessionId and " + "p.type=" + sTypeExactTime) .setLong("sessionId", sessionId.longValue()).setCacheable(true).list(); if (list == null || list.isEmpty()) return null; return (TimePattern) list.get(0); } /** * Returns time string only. The subclasses append the type */ public String toString() { return getName(); } public boolean equals(Object o) { if ((o == null) || !(o instanceof TimePattern)) return false; return getUniqueId().equals(((TimePattern) o).getUniqueId()); } public int compareTo(TimePattern t) { int cmp = getType().compareTo(t.getType()); if (cmp != 0) return cmp; cmp = -getNrMeetings().compareTo(t.getNrMeetings()); if (cmp != 0) return cmp; cmp = getMinPerMtg().compareTo(t.getMinPerMtg()); if (cmp != 0) return cmp; int nrComb = getTimes().size() * getDays().size(); int nrCombT = t.getTimes().size() * t.getDays().size(); cmp = Double.compare(nrComb, nrCombT); if (cmp != 0) return cmp; return getName().compareTo(t.getName()); } public TimePatternModel getTimePatternModel() { return getTimePatternModel(null, true); } public TimePatternModel getTimePatternModel(boolean allowHardPreferences) { return getTimePatternModel(null, allowHardPreferences); } public TimePatternModel getTimePatternModel(TimeLocation assignment, boolean allowHardPreferences) { return new TimePatternModel(this, assignment, allowHardPreferences); } public static Set findAllUsed(Session session) { return findAllUsed(session.getUniqueId()); } public static Set findAllUsed(Long sessionId) { TreeSet ret = new TreeSet((new TimePatternDAO()).getSession().createQuery( "select distinct tp from TimePref as p inner join p.timePattern as tp where tp.session.uniqueId=:sessionId") .setLong("sessionId", sessionId.longValue()).setCacheable(true).list()); ret.addAll((new TimePatternDAO()).getSession().createQuery( "select distinct tp from Assignment as a inner join a.timePattern as tp where tp.session.uniqueId=:sessionId") .setLong("sessionId", sessionId.longValue()).setCacheable(true).list()); return ret; } public boolean isEditable() { if (isTimePatternEditableInitialDataLoad() && getSession().getStatusType().isAllowRollForward()) { return (true); } else { return !findAllUsed(getSession()).contains(this); } } public static RequiredTimeTable getDefaultRequiredTimeTable() { return new RequiredTimeTable(new TimePatternModel()); } public RequiredTimeTable getRequiredTimeTable(boolean allowHardPreferences) { return getRequiredTimeTable(null, allowHardPreferences); } public RequiredTimeTable getRequiredTimeTable(TimeLocation assignment, boolean allowHardPreferences) { return new RequiredTimeTable(getTimePatternModel(assignment, allowHardPreferences)); } public Set getDepartments(Long sessionId) { TreeSet ret = new TreeSet(); for (Iterator i = getDepartments().iterator(); i.hasNext();) { Department d = (Department) i.next(); if (sessionId == null || d.getSession().getUniqueId().equals(sessionId)) ret.add(d); } return ret; } public Integer getBreakTime() { Integer breakTime = super.getBreakTime(); if (breakTime != null) return breakTime; if (getSlotsPerMtg() == null) return new Integer(10); if (getSlotsPerMtg().intValue() % 12 == 0) return new Integer(10); if (getSlotsPerMtg().intValue() > 6) return new Integer(15); if (getType().intValue() == sTypeExactTime) return new Integer(10); return new Integer(0); } public Object clone() { TimePattern newTimePattern = new TimePattern(); newTimePattern.setBreakTime(getBreakTime()); if (getDays() != null) { TimePatternDays origTpDays = null; TimePatternDays newTpDays = null; for (Iterator dIt = getDays().iterator(); dIt.hasNext();) { origTpDays = (TimePatternDays) dIt.next(); newTpDays = new TimePatternDays(); newTpDays.setDayCode(origTpDays.getDayCode()); newTimePattern.addTodays(newTpDays); } } newTimePattern.setMinPerMtg(getMinPerMtg()); newTimePattern.setName(getName()); newTimePattern.setNrMeetings(getNrMeetings()); newTimePattern.setSlotsPerMtg(getSlotsPerMtg()); if (getTimes() != null) { TimePatternTime origTpTime = null; TimePatternTime newTpTime = null; for (Iterator it = getTimes().iterator(); it.hasNext();) { origTpTime = (TimePatternTime) it.next(); newTpTime = new TimePatternTime(); newTpTime.setStartSlot(origTpTime.getStartSlot()); newTimePattern.addTotimes(newTpTime); } } newTimePattern.setSession(getSession()); newTimePattern.setType(getType()); newTimePattern.setVisible(isVisible()); return newTimePattern; } /** * Return true, if this time pattern contains the number of meetings and the number of minutes per meeting * are the same for both patterns. * @param other given pattern (the smaller one) * @param strongComparison if true, both patterns must have the same number of slots per meetings and break times * @return true if the given pattern is a potential match for the this pattern */ private boolean possibleMatch(TimePattern other, boolean strongComparison) { if (!getNrMeetings().equals(other.getNrMeetings())) return false; if (!getMinPerMtg().equals(other.getMinPerMtg())) return false; if (strongComparison && !getBreakTime().equals(other.getBreakTime())) return false; if (strongComparison && !getSlotsPerMtg().equals(other.getSlotsPerMtg())) return false; return (true); } /** * Return true, if this time pattern contains all times and days of the given time pattern * and also the number of meetings and the number of minutes per meeting are the same for both patterns. * @param other given pattern (the smaller one) * @param strongComparison if true, both patterns must have the same number of slots per meetings and break times * @return true if the given pattern can be mapped to this pattern */ public boolean contains(TimePattern other, boolean strongComparison) { if (!possibleMatch(other, strongComparison)) return false; return getDays().containsAll(other.getDays()) && getTimes().containsAll(other.getTimes()); } /** * Return true, if this time pattern contains the same times and days as the given time pattern * and also the number of meetings and the number of minutes per meeting are the same for both patterns. * @param other given pattern * @param strongComparison if true, both patterns must have the same number of slots per meetings and break times * @return true if the given pattern can be mapped to this pattern */ public boolean match(TimePattern other, boolean strongComparison) { if (!possibleMatch(other, strongComparison)) return false; return getDays().equals(other.getDays()) && getTimes().equals(other.getTimes()); } /** * Return best matching time pattern for the given time pattern * @param sessionId id of academic session from which the returned time pattern should be * @param pattern given time pattern (from different academic session) * @return */ public static TimePattern getMatchingTimePattern(Long sessionId, TimePattern pattern) { //if exact time -> return exact time if (pattern.getType() == sTypeExactTime) { return findExactTime(sessionId); } //consider all time patterns with the same number of meeting and number of minutes per meeting TreeSet list = new TreeSet((new TimePatternDAO()).getSession() .createQuery("select distinct p from TimePattern as p " + "where p.session.uniqueId=:sessionId and " + "p.minPerMtg = :minPerMtg and p.nrMeetings = :nrMeetings") .setLong("sessionId", sessionId.longValue()) .setInteger("minPerMtg", pattern.getMinPerMtg().intValue()) .setInteger("nrMeetings", pattern.getNrMeetings().intValue()).setCacheable(true).list()); //look for strongly matching pattern first (among visible patterns) for (Iterator i = list.iterator(); i.hasNext();) { TimePattern tp = (TimePattern) i.next(); if (tp.isVisible() && tp.match(pattern, true)) return tp; } //look for weakly matching pattern first (among visible patterns) for (Iterator i = list.iterator(); i.hasNext();) { TimePattern tp = (TimePattern) i.next(); if (tp.isVisible() && tp.match(pattern, false)) return tp; } //look for pattern that contains all the times and days (among visible patterns, same slotsPerMtg/breakTime as well) for (Iterator i = list.iterator(); i.hasNext();) { TimePattern tp = (TimePattern) i.next(); if (tp.isVisible() && tp.contains(pattern, true)) return tp; } //look for pattern that contains all the times and days (among visible patterns, slotsPerMtg/breakTime can differ) for (Iterator i = list.iterator(); i.hasNext();) { TimePattern tp = (TimePattern) i.next(); if (tp.isVisible() && tp.contains(pattern, false)) return tp; } //look for pattern that contains all the times and days (among hidden patterns, same slotsPerMtg/breakTime as well) for (Iterator i = list.iterator(); i.hasNext();) { TimePattern tp = (TimePattern) i.next(); if (!tp.isVisible() && tp.contains(pattern, true)) return tp; } //look for pattern that contains all the times and days (among hidden patterns, slotsPerMtg/breakTime can differ) for (Iterator i = list.iterator(); i.hasNext();) { TimePattern tp = (TimePattern) i.next(); if (!tp.isVisible() && tp.contains(pattern, false)) return tp; } return null; } /** * Return best matching time preference for the given time preference * @param sessionId id of academic session from which the returned time preference should be * @param timePref given time preference (from different academic session) * @return */ public static TimePref getMatchingTimePreference(Long sessionId, TimePref timePref) { TimePatternModel oldModel = timePref.getTimePatternModel(); TimePattern newTimePattern = getMatchingTimePattern(sessionId, timePref.getTimePattern()); if (newTimePattern == null) { if (oldModel.countPreferences(PreferenceLevel.sRequired) == 1) { newTimePattern = findExactTime(sessionId); if (newTimePattern == null) return null; TimePatternModel newModel = newTimePattern.getTimePatternModel(); for (int d = 0; d < oldModel.getNrDays(); d++) for (int t = 0; t < oldModel.getNrTimes(); t++) { if (PreferenceLevel.sRequired.equals(oldModel.getPreference(d, t))) { newModel.setExactDays(oldModel.getDayCode(d)); newModel.setExactStartSlot(oldModel.getStartSlot(t)); TimePref newTimePref = new TimePref(); newTimePref.setPrefLevel(timePref.getPrefLevel()); newTimePref.setTimePattern(newTimePattern); newTimePref.setPreference(newModel.getPreferences()); return newTimePref; } } } return null; } TimePatternModel newModel = newTimePattern.getTimePatternModel(); if (newModel.isExactTime()) { newModel.setExactDays(oldModel.getExactDays()); newModel.setExactStartSlot(oldModel.getExactStartSlot()); } else { newModel.combineMatching(oldModel); } TimePref newTimePref = new TimePref(); newTimePref.setPrefLevel(timePref.getPrefLevel()); newTimePref.setTimePattern(newTimePattern); newTimePref.setPreference(newModel.getPreferences()); return newTimePref; } /** * @return the sTimePatternEditableInitialDataLoad */ public static boolean isTimePatternEditableInitialDataLoad() { return ApplicationProperty.TimePatternEditableDuringInitialDataLoad.isTrue(); } }