org.unitime.timetable.model.Class_.java Source code

Java tutorial

Introduction

Here is the source code for org.unitime.timetable.model.Class_.java

Source

/*
 * 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.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.TreeSet;
import java.util.Vector;

import org.cpsolver.coursett.preference.MinMaxPreferenceCombination;
import org.cpsolver.coursett.preference.PreferenceCombination;
import org.hibernate.FlushMode;
import org.hibernate.Transaction;
import org.unitime.commons.Debug;
import org.unitime.localization.impl.Localization;
import org.unitime.localization.messages.CourseMessages;
import org.unitime.timetable.defaults.ApplicationProperty;
import org.unitime.timetable.gwt.resources.GwtConstants;
import org.unitime.timetable.interfaces.ExternalClassEditAction;
import org.unitime.timetable.interfaces.ExternalClassNameHelperInterface;
import org.unitime.timetable.model.base.BaseClass_;
import org.unitime.timetable.model.comparators.InstructorComparator;
import org.unitime.timetable.model.comparators.NavigationComparator;
import org.unitime.timetable.model.dao.Class_DAO;
import org.unitime.timetable.model.dao.DatePatternDAO;
import org.unitime.timetable.model.dao.DepartmentalInstructorDAO;
import org.unitime.timetable.model.dao.SectioningInfoDAO;
import org.unitime.timetable.model.dao._RootDAO;
import org.unitime.timetable.security.SessionContext;
import org.unitime.timetable.security.UserContext;
import org.unitime.timetable.security.rights.Right;
import org.unitime.timetable.solver.ClassAssignmentProxy;
import org.unitime.timetable.solver.CommitedClassAssignmentProxy;
import org.unitime.timetable.solver.course.ui.ClassAssignmentInfo;
import org.unitime.timetable.solver.course.ui.ClassInstructorInfo;
import org.unitime.timetable.solver.course.ui.ClassRoomInfo;
import org.unitime.timetable.solver.ui.AssignmentPreferenceInfo;
import org.unitime.timetable.util.Constants;
import org.unitime.timetable.util.DefaultExternalClassNameHelper;
import org.unitime.timetable.webutil.Navigation;

/**
 * @author Tomas Muller, Stephanie Schluttenhofer
 */
public class Class_ extends BaseClass_ {
    private static final long serialVersionUID = 1L;
    private static ExternalClassNameHelperInterface externalClassNameHelper = null;
    private static CourseMessages MSG = Localization.create(CourseMessages.class);
    protected static GwtConstants CONSTANTS = Localization.create(GwtConstants.class);

    /* [CONSTRUCTOR MARKER BEGIN] */
    public Class_() {
        super();
    }

    /**
     * Constructor for primary key
     */
    public Class_(java.lang.Long uniqueId) {
        super(uniqueId);
    }

    /* [CONSTRUCTOR MARKER END] */

    public String getCourseName() {
        return getSchedulingSubpart().getCourseName();
    }

    public String getCourseNameWithTitle() {
        return getSchedulingSubpart().getCourseNameWithTitle();
    }

    /**
     *
     * @return
     */
    public String getItypeDesc() {
        return getSchedulingSubpart().getItypeDesc();
    }

    public Department getManagingDept() {
        if (super.getManagingDept() == null)
            return getControllingDept();
        return super.getManagingDept();
    }

    public void setManagingDept(Department dept) {
        Department oldDept = getManagingDept();
        super.setManagingDept(dept);
        if (dept == null)
            return;
        if (oldDept != null && !oldDept.equals(dept) && getAssignments() != null && !getAssignments().isEmpty()) {
            for (Iterator i = getAssignments().iterator(); i.hasNext();) {
                Assignment a = (Assignment) i.next();
                if (!a.getSolution().getOwner().getDepartments().contains(dept)) {
                    Class_DAO.getInstance().getSession().delete(a);
                    i.remove();
                }
            }
            ClassEvent event = getEvent();
            if (event != null)
                Class_DAO.getInstance().getSession().delete(event);
        }
    }

    /**
     * Retrieves the department for the subject area of the
     * controlling course offering for the class
     * @return Department object
     */
    public Department getDepartmentForSubjectArea() {
        Department dept = this.getSchedulingSubpart().getInstrOfferingConfig().getControllingCourseOffering()
                .getSubjectArea().getDepartment();
        return dept;
    }

    public Session getSession() {
        return (this.getSchedulingSubpart().getSession());
    }

    public Long getSessionId() {
        return (this.getSchedulingSubpart().getSessionId());
    }

    public Set classInstructorPrefsOfType(Class type) {
        List<DepartmentalInstructor> instructors = getLeadInstructors();
        if (instructors.isEmpty())
            return null;
        Set ret = null;
        for (DepartmentalInstructor instructor : instructors) {
            if (ret == null)
                ret = instructor.getPreferences(type);
            else
                ret = combinePreferences(ret, instructor.getPreferences(type));
        }
        return ret;
    }

    private Set weakenHardPreferences(Set prefs) {
        if (prefs == null || prefs.isEmpty())
            return prefs;
        Set ret = new TreeSet();
        for (Iterator i = prefs.iterator(); i.hasNext();) {
            Preference pref = (Preference) ((Preference) i.next()).clone();
            if (pref.weakenHardPreferences())
                ret.add(pref);
        }
        return ret;
    }

    private Set removeNeutralPreferences(Set prefs) {
        if (prefs == null)
            return new TreeSet();
        if (prefs.isEmpty())
            return prefs;
        Set ret = new TreeSet(prefs);
        for (Iterator i = ret.iterator(); i.hasNext();) {
            Preference pref = (Preference) i.next();
            if (PreferenceLevel.sNeutral.equals(pref.getPrefLevel().getPrefProlog()))
                i.remove();
        }
        return ret;
    }

    private Set removeDepartmentalPreferences(Set prefs) {
        if (prefs == null)
            return new TreeSet();
        if (prefs.isEmpty())
            return prefs;
        Set ret = new TreeSet();
        for (Iterator i = prefs.iterator(); i.hasNext();) {
            Preference pref = (Preference) i.next();
            if (pref instanceof RoomPref) {
                Location loc = ((RoomPref) pref).getRoom();
                for (RoomDept rd : loc.getRoomDepts())
                    if (rd.getDepartment().equals(getManagingDept())) {
                        ret.add(pref);
                        break;
                    }
            } else if (pref instanceof BuildingPref) {
                Building b = ((BuildingPref) pref).getBuilding();
                if (getAvailableBuildings().contains(b))
                    ret.add(pref);
            } else if (pref instanceof RoomFeaturePref) {
                RoomFeature rf = ((RoomFeaturePref) pref).getRoomFeature();
                if (rf instanceof GlobalRoomFeature)
                    ret.add(pref);
                else if (rf instanceof DepartmentRoomFeature
                        && ((DepartmentRoomFeature) rf).getDepartment().equals(getManagingDept()))
                    ret.add(pref);
            } else if (pref instanceof RoomGroupPref) {
                RoomGroup rg = ((RoomGroupPref) pref).getRoomGroup();
                if (rg.isGlobal() || getManagingDept().equals(rg.getDepartment()))
                    ret.add(pref);
            } else {
                ret.add(pref);
            }
        }
        return ret;
    }

    private Set<Preference> combinePreferences(Set<Preference> instrPrefs1, Set<Preference> instrPrefs2) {
        if (instrPrefs1 == null || instrPrefs1.isEmpty())
            return instrPrefs2;
        if (instrPrefs2 == null || instrPrefs2.isEmpty())
            return instrPrefs1;

        Set<Preference> ret = new TreeSet<Preference>();

        TimePref tp = null;
        for (Iterator<Preference> i = instrPrefs1.iterator(); i.hasNext();) {
            Preference p1 = i.next();
            if (p1 instanceof TimePref) {
                if (tp == null) {
                    tp = (TimePref) p1.clone();
                } else
                    tp.combineWith((TimePref) p1, false);
            } else
                ret.add(p1);
        }
        for (Iterator<Preference> i = instrPrefs2.iterator(); i.hasNext();) {
            Preference p2 = i.next();
            if (p2 instanceof TimePref) {
                if (tp == null) {
                    tp = (TimePref) p2.clone();
                } else
                    tp.combineWith((TimePref) p2, false);
            }
        }

        for (Iterator<Preference> i = instrPrefs2.iterator(); i.hasNext();) {
            Preference p2 = i.next();
            Preference p1 = null;
            for (Iterator<Preference> j = ret.iterator(); j.hasNext();) {
                Preference p = j.next();
                if (p.isSame(p2)) {
                    p1 = p;
                    j.remove();
                    break;
                }
            }
            if (p1 == null) {
                ret.add(p2);
            } else {
                Preference combPref = (Preference) p1.clone();
                PreferenceCombination com = new MinMaxPreferenceCombination();
                com.addPreferenceProlog(p1.getPrefLevel().getPrefProlog());
                com.addPreferenceProlog(p2.getPrefLevel().getPrefProlog());
                combPref.setPrefLevel(PreferenceLevel.getPreferenceLevel(com.getPreferenceProlog()));
                ret.add(combPref);
            }
        }

        if (tp != null)
            ret.add(tp);

        return ret;
    }

    private Set combinePreferences(Class type, Set subpartPrefs, Set instrPrefs) {
        if (TimePref.class.equals(type)) {
            if (subpartPrefs == null || subpartPrefs.isEmpty() || instrPrefs == null || instrPrefs.isEmpty())
                return subpartPrefs;
            TimePref instrPref = (TimePref) instrPrefs.iterator().next(); //there has to be only one TimePref for instructor/department/session

            Set ret = new TreeSet();
            for (Iterator i = subpartPrefs.iterator(); i.hasNext();) {
                TimePref pref = (TimePref) ((TimePref) i.next()).clone();
                pref.combineWith(instrPref, false);
                ret.add(pref);
            }

            return ret;
        }

        if (subpartPrefs == null || subpartPrefs.isEmpty())
            return instrPrefs;
        if (instrPrefs == null || instrPrefs.isEmpty())
            return subpartPrefs;

        Set ret = new TreeSet(subpartPrefs);
        for (Iterator i = instrPrefs.iterator(); i.hasNext();) {
            Preference instrPref = (Preference) i.next();
            Preference subpartPref = null;
            for (Iterator j = ret.iterator(); j.hasNext();) {
                Preference p = (Preference) j.next();
                if (p.isSame(instrPref)) {
                    subpartPref = p;
                    j.remove();
                    break;
                }
            }
            if (subpartPref == null) {
                ret.add(instrPref);
            } else {
                Preference combPref = (Preference) subpartPref.clone();
                PreferenceCombination com = new MinMaxPreferenceCombination();
                com.addPreferenceProlog(instrPref.getPrefLevel().getPrefProlog());
                com.addPreferenceProlog(subpartPref.getPrefLevel().getPrefProlog());
                combPref.setPrefLevel(PreferenceLevel.getPreferenceLevel(com.getPreferenceProlog()));
                ret.add(combPref);
            }
        }
        return ret;
    }

    private Set combinePreferences(Class type, Set classPrefs, Set subpartPrefs, Set instrPrefs) {
        Set ret = new TreeSet(classPrefs);
        Set combined = combinePreferences(type, subpartPrefs, instrPrefs);

        if (combined == null)
            return ret;

        for (Iterator i = combined.iterator(); i.hasNext();) {
            Preference combPref = (Preference) i.next();
            Preference classPref = null;
            for (Iterator j = classPrefs.iterator(); j.hasNext();) {
                Preference p = (Preference) j.next();
                if (p.isSame(combPref)) {
                    classPref = p;
                    break;
                }
            }
            if (classPref == null)
                ret.add(combPref);
        }

        return ret;
    }

    public Set getDistributionPreferences() {
        TreeSet prefs = new TreeSet();
        if (getDistributionObjects() != null) {
            for (Iterator i = getDistributionObjects().iterator(); i.hasNext();) {
                DistributionObject distObj = (DistributionObject) i.next();
                prefs.add(distObj.getDistributionPref());
            }
        }
        return prefs;
    }

    public Set effectiveDistributionPreferences(Department owningDept) {
        TreeSet prefs = new TreeSet();
        if (getDistributionObjects() != null) {
            for (Iterator i = getDistributionObjects().iterator(); i.hasNext();) {
                DistributionObject distObj = (DistributionObject) i.next();
                DistributionPref pref = distObj.getDistributionPref();
                if (owningDept == null || owningDept.equals(pref.getOwner()))
                    prefs.add(pref);
            }
        }
        if (getSchedulingSubpart().getDistributionObjects() != null) {
            for (Iterator i = getSchedulingSubpart().getDistributionObjects().iterator(); i.hasNext();) {
                DistributionObject distObj = (DistributionObject) i.next();
                DistributionPref pref = distObj.getDistributionPref();
                if (owningDept == null || owningDept.equals(pref.getOwner()))
                    prefs.add(pref);
            }
        }
        return prefs;
    }

    public Set effectivePreferences(Class type, Vector leadInstructors) {
        Department mngDept = getManagingDept();
        if (DistributionPref.class.equals(type)) {
            return effectiveDistributionPreferences(mngDept);
        }

        if (leadInstructors == null || leadInstructors.isEmpty())
            return effectivePreferences(type);

        Set instrPrefs = null;
        for (Enumeration e = leadInstructors.elements(); e.hasMoreElements();) {
            DepartmentalInstructor leadInstructor = (DepartmentalInstructor) e.nextElement();
            instrPrefs = combinePreferences(instrPrefs,
                    leadInstructor.prefsOfTypeForDepartment(type, getControllingDept()));
        }
        // weaken instructor preferences, if needed
        if (instrPrefs != null && !instrPrefs.isEmpty()) {
            if (TimePref.class.equals(type)) {
                if (mngDept.isExternalManager() && !mngDept.isAllowReqTime())
                    instrPrefs = weakenHardPreferences(instrPrefs);
            } else {
                if (mngDept.isExternalManager() && !mngDept.isAllowReqRoom())
                    instrPrefs = weakenHardPreferences(instrPrefs);
            }
        }
        // if external department, remove departmental preferences
        if (mngDept.isExternalManager() && instrPrefs != null && !instrPrefs.isEmpty()) {
            instrPrefs = removeDepartmentalPreferences(instrPrefs);
        }

        // take subpart preferences
        Set subpartPrefs = (getSchedulingSubpart().canInheritParentPreferences()
                ? getSchedulingSubpart().effectivePreferences(type, this)
                : getSchedulingSubpart().getPreferences(type, this));
        if (subpartPrefs != null && !subpartPrefs.isEmpty()
                && !mngDept.equals(getSchedulingSubpart().getManagingDept())) {
            // different managers -> weaken preferences, if needed
            if (TimePref.class.equals(type)) {
                if (mngDept.isExternalManager() && !mngDept.isAllowReqTime())
                    subpartPrefs = weakenHardPreferences(subpartPrefs);
            } else {
                if (mngDept.isExternalManager() && !mngDept.isAllowReqRoom())
                    subpartPrefs = weakenHardPreferences(subpartPrefs);
            }
            // remove departmental preferences
            if (mngDept.isExternalManager() && instrPrefs != null && !instrPrefs.isEmpty()) {
                subpartPrefs = removeDepartmentalPreferences(subpartPrefs);
            }
        }

        return removeNeutralPreferences(combinePreferences(type, subpartPrefs, instrPrefs));
    }

    public Set effectivePreferences(Class type) {
        Department mngDept = getManagingDept();
        // special handling of distribution preferences
        if (DistributionPref.class.equals(type)) {
            Set prefs = effectiveDistributionPreferences(mngDept);
            if (!mngDept.isExternalManager()) {
                Set instPref = classInstructorPrefsOfType(type);
                if (instPref != null)
                    prefs.addAll(instPref);
            }
            return prefs;
        }

        Set classPrefs = getPreferences(type, this);

        Set instrPrefs = null;
        // take instructor preferences if allowed
        if (mngDept.isInheritInstructorPreferences()) {
            instrPrefs = classInstructorPrefsOfType(type);
            // weaken instructor preferences, if needed
            if (instrPrefs != null && !instrPrefs.isEmpty()) {
                if (mngDept.isExternalManager() && TimePref.class.equals(type)) {
                    if (!mngDept.isAllowReqTime())
                        instrPrefs = weakenHardPreferences(instrPrefs);
                } else {
                    if (mngDept.isExternalManager() && !mngDept.isAllowReqRoom())
                        instrPrefs = weakenHardPreferences(instrPrefs);
                }
            }
            // if external department, remove departmental preferences
            if (mngDept.isExternalManager() && instrPrefs != null && !instrPrefs.isEmpty()) {
                instrPrefs = removeDepartmentalPreferences(instrPrefs);
            }
        }

        boolean hasExactTimePattern = false;
        if (TimePref.class.equals(type)) {
            if (classPrefs != null && !classPrefs.isEmpty()) {
                for (Iterator i = classPrefs.iterator(); i.hasNext();) {
                    TimePref tp = (TimePref) i.next();
                    if (tp.getTimePattern() != null
                            && tp.getTimePattern().getType().intValue() == TimePattern.sTypeExactTime) {
                        hasExactTimePattern = true;
                        break;
                    }
                }
            }
        }

        // take subpart preferences
        Set subpartPrefs = (hasExactTimePattern ? null
                : getSchedulingSubpart().canInheritParentPreferences()
                        ? getSchedulingSubpart().effectivePreferences(type, this)
                        : getSchedulingSubpart().getPreferences(type, this));
        if (subpartPrefs != null && !subpartPrefs.isEmpty()
                && !mngDept.equals(getSchedulingSubpart().getManagingDept())) {
            // different managers -> weaken preferences, if needed
            if (TimePref.class.equals(type)) {
                if (mngDept.isExternalManager() && !mngDept.isAllowReqTime())
                    subpartPrefs = weakenHardPreferences(subpartPrefs);
            } else {
                if (mngDept.isExternalManager() && !mngDept.isAllowReqRoom())
                    subpartPrefs = weakenHardPreferences(subpartPrefs);
            }
            // remove departmental preferences
            if (mngDept.isExternalManager() && instrPrefs != null && !instrPrefs.isEmpty()) {
                subpartPrefs = removeDepartmentalPreferences(subpartPrefs);
            }
        }

        return removeNeutralPreferences(combinePreferences(type, classPrefs, subpartPrefs, instrPrefs));
    }

    public String instructorHtml(String instructorNameFormat) {
        StringBuffer sb = new StringBuffer();
        if (this.getClassInstructors() == null)
            return "";
        TreeSet sortedInstructors = new TreeSet(new InstructorComparator());
        sortedInstructors.addAll(this.getClassInstructors());

        Iterator it = sortedInstructors.iterator();
        ClassInstructor ci = null;
        while (it.hasNext()) {
            ci = (ClassInstructor) it.next();
            String title = ci.getInstructor().getNameLastFirst();
            title += " (" + ci.getPercentShare() + "%" + (ci.isLead().booleanValue() ? ", lead" : "") + ")";
            if (!isDisplayInstructor().booleanValue()) {
                title += " - Do Not Display Instructor.";
            }
            if (ci.isLead().booleanValue()) {
                sb.append("<span style='font-weight:bold;"
                        + (isDisplayInstructor().booleanValue() ? "" : "font-style:italic;") + "' title='" + title
                        + "'>");
            } else {
                sb.append("<span title='" + title + "'>");
            }
            sb.append(ci.getInstructor().getName(instructorNameFormat));
            sb.append("</span>");
            if (it.hasNext())
                sb.append("<br>");
            sb.append("\n");
        }
        return (sb.toString());
    }

    private String htmlForTimePatterns(Set patterns) {
        StringBuffer sb = new StringBuffer();
        if (patterns != null) {
            Iterator it = patterns.iterator();
            TimePattern t = null;
            while (it.hasNext()) {
                t = (TimePattern) it.next();
                sb.append(t.getName());
                if (it.hasNext()) {
                    sb.append("<BR>");
                }
            }
        }
        if (patterns == null || patterns.isEmpty()) {
            if (getSchedulingSubpart().getMinutesPerWk().intValue() <= 0) {
                sb.append("<span title='Arrange Hours'>Arr Hrs</span>");
            } else {
                int nrHours = Math.round(getSchedulingSubpart().getMinutesPerWk().intValue() / 50.0f);
                sb.append("<span title='Arrange " + nrHours + " Hours'>Arr " + nrHours + " Hrs</span>");
            }
        }
        return (sb.toString());
    }

    public String effectiveTimePatternHtml() {
        return (htmlForTimePatterns(this.effectiveTimePatterns()));
    }

    public String timePatternHtml() {
        return (htmlForTimePatterns(this.getTimePatterns()));
    }

    public Integer getSectionNumber() {
        return getSectionNumber(null, true);
    }

    public Integer getSectionNumber(org.hibernate.Session hibSession) {
        return getSectionNumber(hibSession, true);
    }

    public Integer getSectionNumber(boolean save) {
        return getSectionNumber(null, save);
    }

    public Integer getSectionNumber(org.hibernate.Session hibSession, boolean save) {
        Integer sectionNumber = getSectionNumberCache();
        if (sectionNumber != null)
            return sectionNumber;

        Comparator cmp = new Comparator() {
            public int compare(Object o1, Object o2) {
                Class_ c1 = (Class_) o1;
                Class_ c2 = (Class_) o2;
                if (c1.getParentClass() == null || c2.getParentClass() == null
                        || c1.getParentClass().equals(c2.getParentClass()))
                    return c1.getUniqueId().compareTo(c2.getUniqueId());
                else
                    return compare(c1.getParentClass(), c2.getParentClass());
            }
        };

        int idx = 0;
        for (Iterator i = getSchedulingSubpart().getClasses().iterator(); i.hasNext();) {
            Class_ clazz = (Class_) i.next();
            if (cmp.compare(clazz, this) < 0)
                idx++;
        }

        sectionNumber = new Integer(getSchedulingSubpart().getInstrOfferingConfig()
                .getFirstSectionNumber(getSchedulingSubpart().getItype()) + idx);
        setSectionNumberCache(sectionNumber);

        if (save) {
            if (hibSession != null) {
                hibSession.saveOrUpdate(this);
            } else {
                (new Class_DAO()).getSession().saveOrUpdate(this);
                (new Class_DAO()).getSession().flush();
            }
        }

        return sectionNumber;
    }

    public String getSectionNumberString() {
        return getSectionNumber() + getSchedulingSubpart().getSchedulingSubpartSuffix();
    }

    public String getSectionNumberString(org.hibernate.Session hibSession) {
        return getSectionNumber(hibSession) + getSchedulingSubpart().getSchedulingSubpartSuffix(hibSession);
    }

    public List<DepartmentalInstructor> getLeadInstructors() {
        List<DepartmentalInstructor> ret = new ArrayList<DepartmentalInstructor>();
        if (getClassInstructors() == null) {
            return ret;
        }
        for (ClassInstructor classInstructor : getClassInstructors()) {
            if (classInstructor.isLead().booleanValue())
                ret.add(classInstructor.getInstructor());
        }
        return ret;
    }

    /**
     * @return Class Label of the form {CourseName} {Itype} {[config]} {Section No.}
     */
    public String getClassLabel() {
        /*
        SchedulingSubpart ss = getSchedulingSubpart();
        String itypeDesc = ss.getItypeDesc();
        if (ss.getInstrOfferingConfig().getInstructionalOffering().hasMultipleConfigurations())
          itypeDesc += " [" + ss.getInstrOfferingConfig().getName() + "]";
        */
        return getCourseName() + " " + getItypeDesc().trim() + " " + getSectionNumberString();
        //       return(getClassLabel(getSchedulingSubpart().getControllingCourseOffering()));
    }

    public String getClassLabel(org.hibernate.Session hibSession) {
        return getCourseName() + " " + getItypeDesc().trim() + " " + getSectionNumberString(hibSession);
    }

    public String getClassLabelWithTitle() {
        return getCourseNameWithTitle() + " " + getItypeDesc().trim() + " " + getSectionNumberString();
        //       return(getClassLabelWithTitle(getSchedulingSubpart().getControllingCourseOffering()));
    }

    /**
     * @see getClassLabel()
     */
    public String toString() {
        return getClassLabel();
    }

    /**
     * @return Class type to distinguish the sub class in PrefGroup
     */
    public Class getInstanceOf() {
        return Class_.class;
    }

    public String htmlLabel() {
        return (getItypeDesc() + " " + getSectionNumberString());
    }

    public boolean canBeDeleted() {
        if (this.getChildClasses() != null && this.getChildClasses().size() > 0) {
            return (false);
        }
        if (this.getParentClass() != null) {
            int totalCapacity = 0;
            Class_ c = null;
            for (Iterator it = this.getParentClass().getChildClasses().iterator(); it.hasNext();) {
                c = (Class_) it.next();
                totalCapacity += c.getExpectedCapacity().intValue();
            }
            totalCapacity -= this.getExpectedCapacity().intValue();
            if (totalCapacity < this.getParentClass().getExpectedCapacity().intValue()) {
                return (false);
            }
        }
        return (true);
    }

    /**
     * Remove class from instructor list
     * @param ci
     */
    public void removeClassInstructor(ClassInstructor classInstr) {
        Set s = this.getClassInstructors();
        for (Iterator iter = s.iterator(); iter.hasNext();) {
            ClassInstructor ci = (ClassInstructor) iter.next();
            if (ci.getUniqueId().intValue() == classInstr.getUniqueId().intValue()) {
                s.remove(ci);
                break;
            }
        }
    }

    public DatePattern effectiveDatePattern() {
        if (getDatePattern() != null)
            return getDatePattern();
        return getSchedulingSubpart().effectiveDatePattern();
    }

    public Set<Location> getAvailableRooms() {

        Set<Location> rooms = new TreeSet<Location>();
        for (Iterator i = getManagingDept().getRoomDepts().iterator(); i.hasNext();) {
            RoomDept roomDept = (RoomDept) i.next();
            rooms.add(roomDept.getRoom());
        }

        return rooms;
    }

    public Set getAvailableRoomFeatures() {
        Set features = new TreeSet(GlobalRoomFeature.getAllGlobalRoomFeatures(getSession()));
        Department dept = getManagingDept();
        if (dept != null)
            features.addAll(DepartmentRoomFeature.getAllDepartmentRoomFeatures(dept));
        return features;

    }

    public Set getAvailableRoomGroups() {
        Set groups = super.getAvailableRoomGroups();
        Department dept = getManagingDept();
        if (dept != null)
            groups.addAll(RoomGroup.getAllDepartmentRoomGroups(dept));
        return groups;
    }

    public Class_ getNextClass(SessionContext context, Right right) {
        return getNextClass(context, new NavigationComparator(), right);
    }

    public Class_ getPreviousClass(SessionContext context, Right right) {
        return getPreviousClass(context, new NavigationComparator(), right);
    }

    public Class_ getNextClass(SessionContext context, Comparator cmp, Right right) {
        Long nextId = Navigation.getNext(context, Navigation.sClassLevel, getUniqueId());
        if (nextId != null) {
            if (nextId.longValue() < 0)
                return null;
            Class_ next = (new Class_DAO()).get(nextId);
            if (next == null)
                return null;
            if (right != null && !context.hasPermission(next, right))
                return next.getNextClass(context, cmp, right);
            return next;
        }
        Class_ next = null;
        SchedulingSubpart subpart = getSchedulingSubpart();
        while (next == null) {
            if (subpart == null)
                break;
            for (Iterator i = subpart.getClasses().iterator(); i.hasNext();) {
                Class_ c = (Class_) i.next();
                if (right != null && !context.hasPermission(c, right))
                    continue;
                if (subpart.equals(getSchedulingSubpart()) && cmp.compare(this, c) >= 0)
                    continue;
                if (next == null || cmp.compare(next, c) > 0)
                    next = c;
            }
            subpart = subpart.getNextSchedulingSubpart(context, cmp, null);
        }
        return next;
    }

    public Class_ getPreviousClass(SessionContext context, Comparator cmp, Right right) {
        Long previosId = Navigation.getPrevious(context, Navigation.sClassLevel, getUniqueId());
        if (previosId != null) {
            if (previosId.longValue() < 0)
                return null;
            Class_ previos = (new Class_DAO()).get(previosId);
            if (previos == null)
                return null;
            if (right != null && !context.hasPermission(previos, right))
                return previos.getPreviousClass(context, cmp, right);
            return previos;
        }
        Class_ previous = null;
        SchedulingSubpart subpart = getSchedulingSubpart();
        while (previous == null) {
            if (subpart == null)
                break;
            for (Iterator i = subpart.getClasses().iterator(); i.hasNext();) {
                Class_ c = (Class_) i.next();
                if (right != null && !context.hasPermission(c, right))
                    continue;
                if (subpart.equals(getSchedulingSubpart()) && cmp.compare(this, c) <= 0)
                    continue;
                if (previous == null || cmp.compare(previous, c) < 0)
                    previous = c;
            }
            subpart = subpart.getPreviousSchedulingSubpart(context, cmp, null);
        }
        return previous;
    }

    /**
     * Deletes all distribution prefs and updates the class_ objects
     * @param hibSession
     */
    public void deleteAllDistributionPreferences(org.hibernate.Session hibSession) {
        deleteAllDistributionPreferences(hibSession, true);
    }

    /**
     * Deletes all distribution prefs
     * @param hibSession
     * @param updateClass If true then class_ object is updated
     */
    public void deleteAllDistributionPreferences(org.hibernate.Session hibSession, boolean updateClass) {
        boolean deleted = false;
        if (getDistributionObjects() == null)
            return;
        for (Iterator i = getDistributionObjects().iterator(); i.hasNext();) {
            DistributionObject relatedObject = (DistributionObject) i.next();
            DistributionPref distributionPref = relatedObject.getDistributionPref();
            distributionPref.getDistributionObjects().remove(relatedObject);
            Integer seqNo = relatedObject.getSequenceNumber();
            hibSession.delete(relatedObject);
            deleted = true;
            if (distributionPref.getDistributionObjects().isEmpty()) {
                PreferenceGroup owner = distributionPref.getOwner();
                owner.getPreferences().remove(distributionPref);
                getPreferences().remove(distributionPref);
                hibSession.saveOrUpdate(owner);
                hibSession.delete(distributionPref);
            } else {
                if (seqNo != null) {
                    for (Iterator j = distributionPref.getDistributionObjects().iterator(); j.hasNext();) {
                        DistributionObject dObj = (DistributionObject) j.next();
                        if (seqNo.compareTo(dObj.getSequenceNumber()) < 0) {
                            dObj.setSequenceNumber(new Integer(dObj.getSequenceNumber().intValue() - 1));
                            hibSession.saveOrUpdate(dObj);
                        }
                    }
                }

                if (updateClass)
                    hibSession.saveOrUpdate(distributionPref);
            }
            i.remove();
        }

        if (deleted && updateClass)
            hibSession.saveOrUpdate(this);
    }

    public Integer getMinRoomLimit() {
        int expCap = (getExpectedCapacity() == null ? 0 : getExpectedCapacity().intValue());
        float roomRatio = (getRoomRatio() == null ? 0.0f : getRoomRatio().floatValue());
        return new Integer(Math.round(expCap <= 0 ? roomRatio : expCap * roomRatio));
    }

    public static List findAll(Long sessionId) {
        return findAll(Class_DAO.getInstance().getSession(), sessionId);
    }

    public static List findAll(org.hibernate.Session hibSession, Long sessionId) {
        return hibSession.createQuery("select distinct c from Class_ c where "
                + "c.schedulingSubpart.instrOfferingConfig.instructionalOffering.session.uniqueId=:sessionId")
                .setLong("sessionId", sessionId.longValue()).list();
    }

    public static List findAllForControllingSubjectArea(String subjectAreaAbbv, Long sessionId) {
        return (findAllForControllingSubjectArea(subjectAreaAbbv, sessionId, (new Class_DAO()).getSession()));
    }

    public static List findAllForControllingSubjectArea(String subjectAreaAbbv, Long sessionId,
            org.hibernate.Session hibSession) {
        return hibSession.createQuery(
                "select distinct c from Class_ c inner join c.schedulingSubpart.instrOfferingConfig.instructionalOffering.courseOfferings as co where "
                        + "co.subjectArea.subjectAreaAbbreviation=:subjectAreaAbbv and c.schedulingSubpart.instrOfferingConfig.instructionalOffering.session.uniqueId=:sessionId and co.isControl=1")
                .setString("subjectAreaAbbv", subjectAreaAbbv).setLong("sessionId", sessionId.longValue())
                .setFlushMode(FlushMode.MANUAL).list();
    }

    public String getDivSecNumber() {
        if (getParentClass() != null
                && getSchedulingSubpart().getItype().equals(getParentClass().getSchedulingSubpart().getItype())) {
            return getParentClass().getDivSecNumber();
        }
        String suffix = getClassSuffix();
        if (suffix != null && suffix.length() == 6)
            return suffix.substring(0, 3) + "-" + suffix.substring(3, 6);
        return suffix;
    }

    public int getClassLimit() {
        return getClassLimit(new CommitedClassAssignmentProxy());
    }

    public int getClassLimit(ClassAssignmentProxy proxy) {
        // MinClassLimit == MaxClassLimit == ClassLimit
        if (getExpectedCapacity().equals(getMaxExpectedCapacity()))
            return getExpectedCapacity().intValue();

        // No assignment -> take MaxClassLimit
        int maxClassLimit = getMaxExpectedCapacity().intValue();
        Assignment assignment = null;
        try {
            assignment = (proxy == null ? null : proxy.getAssignment(this));
        } catch (Exception e) {
            Debug.error(e);
        }
        if (assignment != null) {
            // Assignment -> take smaller from MaxClassLimit and RoomSize / RoomRatio
            maxClassLimit = Math.min(getMaxExpectedCapacity().intValue(),
                    (int) Math.floor(assignment.getPlacement().getRoomSize() / getRoomRatio().floatValue()));
        }

        if (getChildClasses().isEmpty())
            return maxClassLimit;

        // if there are children classes ...
        for (Iterator i = getSchedulingSubpart().getChildSubparts().iterator(); i.hasNext();) {
            SchedulingSubpart childSubpart = (SchedulingSubpart) i.next();
            // take all children classes of the same subpart, sum their class limit
            int maxChildrenLimit = 0;
            for (Iterator j = getChildClasses().iterator(); j.hasNext();) {
                Class_ childClass = (Class_) j.next();
                if (!childClass.getSchedulingSubpart().equals(childSubpart))
                    continue;
                maxChildrenLimit += childClass.getClassLimit(proxy);
            }
            // children class limit cannot be exceeded
            maxClassLimit = Math.min(maxClassLimit, maxChildrenLimit);
        }

        return maxClassLimit;
    }

    public int getClassLimit(CourseOffering offering) {
        return getClassLimit(new CommitedClassAssignmentProxy());
    }

    private boolean hasChildClass(Reservation r) {
        if (r.getClasses().contains(this))
            return true;
        for (Class_ child : getChildClasses())
            if (child.hasChildClass(r))
                return true;
        return false;
    }

    public boolean hasClass(Reservation r) {
        if (r.getClasses().isEmpty())
            return false;
        Class_ c = this;
        while (c != null) {
            if (r.getClasses().contains(c))
                return true;
            c = c.getParentClass();
        }
        for (Class_ child : getChildClasses())
            if (child.hasChildClass(r))
                return true;
        return false;
    }

    /**
     * Delete all objects that have an identifying relationship with a class
     * Usually use this method when one needs to delete a class
     * (in which case set updateClass to false because the class will eventually be deleted)
     * @param hibSession
     * @param updateClass Updates class when all dependent objects are deleted
     */
    public void deleteAllDependentObjects(org.hibernate.Session hibSession, boolean updateClass) {

        // Call individual methods to delete specific collections
        deleteAllDistributionPreferences(hibSession, updateClass);
        deleteClassInstructors(hibSession);
        deleteAssignments(hibSession);
        Exam.deleteFromExams(hibSession, this);
        Event.deleteFromEvents(hibSession, this);

        // Add more collection deletes if needed

        if (updateClass)
            hibSession.saveOrUpdate(this);
    }

    /**
     * Delete all class instructors
     * @param hibSession
     */
    public void deleteClassInstructors(org.hibernate.Session hibSession) {
        Set s = getClassInstructors();
        //deleteObjectsFromCollection(hibSession, s);
        if (s == null || s.size() == 0)
            return;

        for (Iterator i = s.iterator(); i.hasNext();) {
            ClassInstructor ci = (ClassInstructor) (i.next());

            DepartmentalInstructor di = new DepartmentalInstructorDAO().get(ci.getInstructor().getUniqueId());
            di.getClasses().remove(ci);
            ci.setInstructor(null);
            ci.setClassInstructing(null);
            hibSession.saveOrUpdate(di);
            hibSession.delete(ci);
            i.remove();
        }
    }

    /**
     * Delete all class assignments
     * @param hibSession
     */
    public void deleteAssignments(org.hibernate.Session hibSession) {
        Set s = getAssignments();
        deleteObjectsFromCollection(hibSession, s);
    }

    /**
     * Common method to delete objects from acollection
     * @param hibSession
     * @param s Collection from which objects have to be deleted
     */
    private void deleteObjectsFromCollection(org.hibernate.Session hibSession, Collection s) {
        if (s == null || s.size() == 0)
            return;

        for (Iterator i = s.iterator(); i.hasNext();) {
            hibSession.delete(i.next());
            i.remove();
        }
    }

    public boolean isOddOrEvenWeeksOnly() {
        if (effectiveDatePattern() != null
                && effectiveDatePattern().getType().equals(new Integer(DatePattern.sTypeAlternate))) {
            return (true);
        }
        return (false);

    }

    public Object clone() {
        Class_ newClass = new Class_();
        newClass.setDatePattern(getDatePattern());
        newClass.setEnabledForStudentScheduling(isEnabledForStudentScheduling());
        newClass.setDisplayInstructor(isDisplayInstructor());
        newClass.setExpectedCapacity(getExpectedCapacity());
        newClass.setManagingDept(getManagingDept());
        newClass.setMaxExpectedCapacity(getMaxExpectedCapacity());
        newClass.setNbrRooms(getNbrRooms());
        newClass.setNotes(getNotes());
        newClass.setRoomRatio(getRoomRatio());
        newClass.setSchedulePrintNote(getSchedulePrintNote());
        newClass.setSchedulingSubpart(getSchedulingSubpart());
        return (newClass);
    }

    public Object cloneWithPreferences() {
        Class_ newClass = (Class_) this.clone();
        if (getPreferences() != null) {
            Preference origPref = null;
            Preference newPref = null;
            for (Iterator prefIt = getPreferences().iterator(); prefIt.hasNext();) {
                origPref = (Preference) prefIt.next();
                if (!(origPref instanceof DistributionPref)) {
                    newPref = (Preference) origPref.clone();
                    newPref.setOwner(newClass);
                    newClass.addTopreferences(newPref);
                }
            }
        }
        if (getClassInstructors() != null && !getClassInstructors().isEmpty()) {
            ClassInstructor ci = null;
            ClassInstructor newCi = null;
            for (Iterator ciIt = getClassInstructors().iterator(); ciIt.hasNext();) {
                ci = (ClassInstructor) ciIt.next();
                newCi = new ClassInstructor();
                newCi.setClassInstructing(newClass);
                newCi.setInstructor(ci.getInstructor());
                newCi.setLead(ci.isLead());
                newCi.setPercentShare(ci.getPercentShare());
                ci.getInstructor().addToclasses(newCi);
                newClass.addToclassInstructors(newCi);
            }
        }
        return (newClass);
    }

    public static Class_ findByExternalId(Long sessionId, String externalId) {
        return (Class_) new Class_DAO().getSession().createQuery(
                "select c from Class_ c where c.schedulingSubpart.instrOfferingConfig.instructionalOffering.session.uniqueId=:sessionId and c.externalUniqueId=:externalId")
                .setLong("sessionId", sessionId.longValue()).setString("externalId", externalId).setCacheable(true)
                .uniqueResult();
    }

    public static Class_ findByIdRolledForwardFrom(Long sessionId, Long uniqueIdRolledForwardFrom) {
        return (Class_) new Class_DAO().getSession().createQuery(
                "select c from Class_ c where c.schedulingSubpart.instrOfferingConfig.instructionalOffering.session.uniqueId=:sessionId and c.uniqueIdRolledForwardFrom=:uniqueIdRolledForwardFrom")
                .setLong("sessionId", sessionId.longValue())
                .setLong("uniqueIdRolledForwardFrom", uniqueIdRolledForwardFrom.longValue()).setCacheable(true)
                .uniqueResult();
    }

    private ClassEvent iEvent = null;

    public ClassEvent getEvent() {
        if (iEvent == null)
            iEvent = (ClassEvent) new Class_DAO().getSession().createQuery(
                    "select e from ClassEvent e left join fetch e.meetings m where e.clazz.uniqueId=:classId")
                    .setLong("classId", getUniqueId()).setCacheable(true).uniqueResult();
        return iEvent;
    }

    public void setEvent(ClassEvent event) {
        iEvent = event;
    }

    public ClassEvent getCachedEvent() {
        return iEvent;
    }

    public String unassignCommited(UserContext user, org.hibernate.Session hibSession) {
        Transaction tx = null;
        try {
            if (hibSession.getTransaction() == null || !hibSession.getTransaction().isActive())
                tx = hibSession.beginTransaction();

            Assignment oldAssignment = getCommittedAssignment();

            if (oldAssignment == null)
                throw new RuntimeException("Class " + getClassLabel() + " does not have an assignment.");

            ClassEvent event = getEvent();
            if (event != null) {
                if (ApplicationProperty.ClassAssignmentChangePastMeetings.isTrue()) {
                    hibSession.delete(event);
                } else {
                    Calendar cal = Calendar.getInstance(Locale.US);
                    cal.set(Calendar.HOUR_OF_DAY, 0);
                    cal.set(Calendar.MINUTE, 0);
                    cal.set(Calendar.SECOND, 0);
                    cal.set(Calendar.MILLISECOND, 0);
                    Date today = cal.getTime();

                    for (Iterator<Meeting> i = event.getMeetings().iterator(); i.hasNext();)
                        if (!i.next().getMeetingDate().before(today))
                            i.remove();

                    if (event.getMeetings().isEmpty()) {
                        hibSession.delete(event);
                    } else {
                        if (event.getNotes() == null)
                            event.setNotes(new HashSet<EventNote>());
                        EventNote note = new EventNote();
                        note.setEvent(event);
                        note.setNoteType(EventNote.sEventNoteTypeDeletion);
                        note.setTimeStamp(new Date());
                        note.setUser(user.getName());
                        note.setUserId(user.getExternalUserId());
                        note.setTextNote(MSG.classNoteUnassigned(oldAssignment.getPlacement().getName()));
                        note.setMeetings(MSG.classMeetingsNotApplicable());
                        event.getNotes().add(note);
                        hibSession.saveOrUpdate(event);
                    }
                }
            }

            String old = oldAssignment.getPlacement().getName();

            oldAssignment.getSolution().getAssignments().remove(oldAssignment);

            // Remove all related constraint infos to avoid hibernate cache issues 
            // when an orphaned constraint info is automatically deleted
            for (ConstraintInfo ci : oldAssignment.getConstraintInfo()) {
                for (Assignment a : ci.getAssignments()) {
                    if (!a.equals(oldAssignment)) {
                        a.getConstraintInfo().remove(ci);
                    }
                }
                hibSession.delete(ci);
            }

            hibSession.delete(oldAssignment);

            setCommittedAssignment(null);
            hibSession.update(this);

            ChangeLog.addChange(hibSession, TimetableManager.findByExternalId(user.getExternalUserId()),
                    getSession(), this, getClassLabel() + " (" + old + " &rarr; N/A)", ChangeLog.Source.CLASS_INFO,
                    ChangeLog.Operation.UNASSIGN,
                    getSchedulingSubpart().getControllingCourseOffering().getSubjectArea(), getManagingDept());

            if (tx != null)
                tx.commit();

            new _RootDAO().getSession().refresh(this);
            String className = ApplicationProperty.ExternalActionClassEdit.value();
            if (className != null && className.trim().length() > 0) {
                ExternalClassEditAction editAction = (ExternalClassEditAction) (Class.forName(className)
                        .newInstance());
                editAction.performExternalClassEditAction(this, hibSession);
            }

            return null;
        } catch (Exception e) {
            if (tx != null)
                tx.rollback();
            e.printStackTrace();
            return "Unassignment of " + getClassLabel() + " failed, reason: " + e.getMessage();
        }
    }

    public String assignCommited(ClassAssignmentInfo assignment, UserContext user,
            org.hibernate.Session hibSession) {
        Transaction tx = null;
        try {
            if (hibSession.getTransaction() == null || !hibSession.getTransaction().isActive())
                tx = hibSession.beginTransaction();

            String old = "N/A";

            Assignment oldAssignment = getCommittedAssignment();
            if (oldAssignment != null) {
                old = oldAssignment.getPlacement().getName();

                oldAssignment.getSolution().getAssignments().remove(oldAssignment);

                // Remove all related constraint infos to avoid hibernate cache issues 
                // when an orphaned constraint info is automatically deleted
                for (ConstraintInfo ci : oldAssignment.getConstraintInfo()) {
                    for (Assignment a : ci.getAssignments()) {
                        if (!a.equals(oldAssignment)) {
                            a.getConstraintInfo().remove(ci);
                        }
                    }
                    hibSession.delete(ci);
                }

                hibSession.delete(oldAssignment);
            }

            SolverGroup group = getManagingDept().getSolverGroup();
            if (group == null)
                throw new RuntimeException("Department " + getManagingDept().getLabel() + " has no solver group.");
            Solution solution = group.getCommittedSolution();
            if (solution == null)
                throw new RuntimeException("Solver group " + group.getName() + " has no commited solution.");

            DatePattern dp = DatePatternDAO.getInstance().get(assignment.getDate().getId(), hibSession);

            Assignment a = new Assignment();
            a.setSolution(solution);
            a.setSlotsPerMtg(assignment.getTime().getNrSlotsPerMeeting());
            a.setBreakTime(assignment.getTime().getBreakTime());
            a.setClazz(this);
            a.setClassName(getClassLabel());
            a.setClassId(getUniqueId());
            a.setDays(assignment.getTime().getDayCode());
            a.setRooms(new HashSet());
            a.setInstructors(new HashSet());
            a.setStartSlot(assignment.getTime().getStartSlot());
            a.setTimePattern(assignment.getTime().getTimePattern(hibSession));
            a.setDatePattern(dp != null ? dp : effectiveDatePattern());
            a.setAssignmentInfo(new HashSet());

            for (ClassRoomInfo room : assignment.getRooms())
                a.getRooms().add(room.getLocation(hibSession));
            for (ClassInstructorInfo inst : assignment.getInstructors())
                if (inst.isLead())
                    a.getInstructors().add(inst.getInstructor(hibSession).getInstructor());

            hibSession.save(a);

            //TODO: More information should be gathered about the assignment.
            AssignmentPreferenceInfo pref = new AssignmentPreferenceInfo();
            pref.setTimePreference(assignment.getTime().getPreference());
            for (ClassRoomInfo room : assignment.getRooms())
                pref.setRoomPreference(room.getLocationId(), room.getPreference());
            AssignmentInfo ai = new AssignmentInfo();
            ai.setAssignment(a);
            ai.setDefinition(SolverInfoDef.findByName(hibSession, "AssignmentInfo"));
            ai.setOpt(null);
            ai.setInfo(pref);
            hibSession.save(ai);

            a.getAssignmentInfo().add(ai);
            a.cleastAssignmentInfoCache();

            ClassEvent event = getEvent();
            event = a.generateCommittedEvent(event, true);
            if (event != null && !event.getMeetings().isEmpty()) {
                if (event.getNotes() == null)
                    event.setNotes(new HashSet<EventNote>());
                EventNote note = new EventNote();
                note.setEvent(event);
                note.setNoteType(event.getUniqueId() == null ? EventNote.sEventNoteTypeCreateEvent
                        : EventNote.sEventNoteTypeEditEvent);
                note.setTimeStamp(new Date());
                note.setUser(user.getName());
                note.setUserId(user.getExternalUserId());
                if (oldAssignment == null)
                    note.setTextNote(MSG.classNoteAssigned(a.getPlacement().getName()));
                else
                    note.setTextNote(MSG.classNoteReassigned(oldAssignment.getPlacement().getName(),
                            a.getPlacement().getName()));
                note.setMeetings(assignment.getTime().getLongName()
                        + (assignment.getNrRooms() > 0 ? " " + assignment.getRoomNames(", ") : ""));
                event.getNotes().add(note);
                hibSession.saveOrUpdate(event);
            }
            if (event != null && event.getMeetings().isEmpty() && event.getUniqueId() != null)
                hibSession.delete(event);

            setCommittedAssignment(a);
            hibSession.update(this);

            ChangeLog.addChange(hibSession, TimetableManager.findByExternalId(user.getExternalUserId()),
                    getSession(), this,
                    getClassLabel() + " (" + old + " &rarr; " + assignment.getTime().getName() + " "
                            + assignment.getRoomNames(", ") + ")",
                    ChangeLog.Source.CLASS_INFO, ChangeLog.Operation.ASSIGN,
                    getSchedulingSubpart().getControllingCourseOffering().getSubjectArea(), getManagingDept());

            if (tx != null)
                tx.commit();

            new _RootDAO().getSession().refresh(this);
            String className = ApplicationProperty.ExternalActionClassEdit.value();
            if (className != null && className.trim().length() > 0) {
                ExternalClassEditAction editAction = (ExternalClassEditAction) (Class.forName(className)
                        .newInstance());
                editAction.performExternalClassEditAction(this, hibSession);
            }

            return null;
        } catch (Exception e) {
            if (tx != null)
                tx.rollback();
            e.printStackTrace();
            return "Assignment of " + getClassLabel() + " failed, reason: " + e.getMessage();
        }
    }

    public Collection<Long> getEnrolledStudentIds() {
        return Class_DAO.getInstance().getSession().createQuery(
                "select e.student.uniqueId from StudentClassEnrollment e where " + "e.clazz.uniqueId=:classId")
                .setLong("classId", getUniqueId()).setCacheable(true).list();

    }

    public String buildAssignedTimeHtml(ClassAssignmentProxy proxy) {
        Assignment a = null;
        StringBuffer sb = new StringBuffer();
        try {
            a = proxy.getAssignment(this);
        } catch (Exception e) {
            Debug.error(e);
        }
        if (a != null) {
            Enumeration<Integer> e = a.getTimeLocation().getDays();
            while (e.hasMoreElements()) {
                sb.append(Constants.DAY_NAMES_SHORT[e.nextElement()]);
            }
            sb.append(" ");
            sb.append(a.getTimeLocation().getStartTimeHeader(CONSTANTS.useAmPm()));
            sb.append("-");
            sb.append(a.getTimeLocation().getEndTimeHeader(CONSTANTS.useAmPm()));
        } else {
            if (getEffectiveTimePreferences().isEmpty()) {
                if (getSchedulingSubpart().getMinutesPerWk().intValue() <= 0) {
                    sb.append("Arr Hrs");
                } else {
                    int nrHours = Math.round(getSchedulingSubpart().getMinutesPerWk().intValue() / 50.0f);
                    sb.append("Arr " + nrHours + " Hrs");
                }
            }
        }
        if (sb.length() == 0) {
            sb.append(" ");
        }
        return (sb.toString());
    }

    public String buildAssignedRoomHtml(ClassAssignmentProxy proxy) {
        Assignment a = null;
        StringBuffer sb = new StringBuffer();
        try {
            a = proxy.getAssignment(this);
        } catch (Exception e) {
            Debug.error(e);
        }
        if (a != null) {
            Iterator it2 = a.getRooms().iterator();
            while (it2.hasNext()) {
                Location room = (Location) it2.next();
                sb.append(room.getLabel());
            }
        } else {
            if (getEffectiveTimePreferences().isEmpty()) {
                boolean first = true;
                for (Iterator it = getEffectiveRoomPreferences().iterator(); it.hasNext();) {
                    RoomPref rp = (RoomPref) it.next();
                    if (rp.getPrefLevel().getPrefId().toString().equals(PreferenceLevel.PREF_LEVEL_REQUIRED)) {
                        if (first) {
                            first = false;
                        } else {
                            sb.append("<br>");
                        }
                        sb.append(rp.getRoom().getLabel());
                    }
                }
            }
        }
        if (sb.length() == 0) {
            sb.append(" ");
        }
        return (sb.toString());
    }

    public String buildInstructorHtml(String nameFormat) {
        StringBuffer sb = new StringBuffer();
        if (getClassInstructors() != null && !getClassInstructors().isEmpty()) {
            boolean first = true;
            for (ClassInstructor ci : (Set<ClassInstructor>) getClassInstructors()) {
                if (first) {
                    first = false;
                } else {
                    sb.append("<br>");
                }
                sb.append(ci.getInstructor().getName(nameFormat));
            }
        } else {
            sb.append(" ");
        }
        return (sb.toString());
    }

    public static ExternalClassNameHelperInterface getExternalClassNameHelper() {
        if (externalClassNameHelper == null) {
            String className = ApplicationProperty.ClassNamingHelper.value();
            if (className != null && className.trim().length() > 0) {
                try {
                    externalClassNameHelper = (ExternalClassNameHelperInterface) (Class.forName(className)
                            .newInstance());
                } catch (InstantiationException e) {
                    Debug.error("Failed to instantiate instance of: " + className
                            + " using the default class name helper.");
                    e.printStackTrace();
                    externalClassNameHelper = new DefaultExternalClassNameHelper();
                } catch (IllegalAccessException e) {
                    Debug.error(
                            "Illegal Access Exception on: " + className + " using the default class name helper.");
                    e.printStackTrace();
                    externalClassNameHelper = new DefaultExternalClassNameHelper();
                } catch (ClassNotFoundException e) {
                    Debug.error("Failed to find class: " + className + " using the default class name helper.");
                    e.printStackTrace();
                    externalClassNameHelper = new DefaultExternalClassNameHelper();
                }
            } else {
                externalClassNameHelper = new DefaultExternalClassNameHelper();
            }
        }
        return externalClassNameHelper;
    }

    public String getClassLabel(CourseOffering courseOffering) {
        return (getExternalClassNameHelper().getClassLabel(this, courseOffering));
    }

    public String getClassSuffix(CourseOffering courseOffering) {
        return (getExternalClassNameHelper().getClassSuffix(this, courseOffering));
    }

    public String getClassLabelWithTitle(CourseOffering courseOffering) {
        return (getExternalClassNameHelper().getClassLabelWithTitle(this, courseOffering));
    }

    public String getExternalId(CourseOffering courseOffering) {
        return (getExternalClassNameHelper().getExternalId(this, courseOffering));
    }

    public SectioningInfo getSectioningInfo() {
        return (SectioningInfo) SectioningInfoDAO.getInstance().getSession()
                .createQuery("select i from SectioningInfo i where i.clazz.uniqueId = :classId")
                .setLong("classId", getUniqueId()).setCacheable(true).uniqueResult();
    }

    //   /* (non-Javadoc)
    //    * @see org.unitime.timetable.model.base.BaseClass_#getClassSuffix()
    //    */
    //   @Override
    //   public String getClassSuffix() {
    //      return(getClassSuffix(getSchedulingSubpart().getControllingCourseOffering()));
    //   }

    @Override
    public Department getDepartment() {
        return getManagingDept();
    }

}