Beispiel #1
0
  public XSubpart(SchedulingSubpart subpart, boolean courseCredit, OnlineSectioningHelper helper) {
    iUniqueId = subpart.getUniqueId();
    iInstructionalType =
        sF3Z.format(subpart.getItype().getItype())
            + subpart.getSchedulingSubpartSuffix(helper.getHibSession());
    iAllowOverlap = subpart.isStudentAllowOverlap();
    iName = subpart.getItype().getAbbv().trim();
    iConfigId = subpart.getInstrOfferingConfig().getUniqueId();
    iParentId =
        subpart.getParentSubpart() == null ? null : subpart.getParentSubpart().getUniqueId();
    if (subpart.getCredit() != null) {
      iCreditAbbv = subpart.getCredit().creditAbbv();
      iCreditText = subpart.getCredit().creditText();
    }
    if (courseCredit) {
      for (CourseOffering co :
          subpart.getInstrOfferingConfig().getInstructionalOffering().getCourseOfferings()) {
        if (co.getCredit() != null)
          iCreditByCourse.put(
              co.getUniqueId(),
              new String[] {co.getCredit().creditAbbv(), co.getCredit().creditText()});
      }
    }
    for (Class_ clazz : subpart.getClasses()) iSections.add(new XSection(clazz, helper));

    Collections.sort(iSections);
  }
 public boolean getHasScheduleBookNote() {
   if (courseOfferings == null || courseOfferings.isEmpty()) return false;
   for (Iterator i = courseOfferings.iterator(); i.hasNext(); ) {
     CourseOffering course = (CourseOffering) i.next();
     if (course.getScheduleBookNote() != null && !course.getScheduleBookNote().isEmpty())
       return true;
   }
   return false;
 }
 @Override
 public Set<WeightedStudentId> getDemands(CourseOffering course) {
   Hashtable<Long, Set<WeightedStudentId>> demands =
       iDemands.get(course.getSubjectArea().getUniqueId());
   if (demands == null) {
     demands = loadDemandsForSubjectArea(course.getSubjectArea());
     iDemands.put(course.getSubjectArea().getUniqueId(), demands);
   }
   return demands.get(course.getUniqueId());
 }
 @Override
 public Set<WeightedCourseOffering> getCourses(Long studentId) {
   if (iStudentRequests == null) {
     iStudentRequests = new Hashtable<Long, Set<WeightedCourseOffering>>();
     for (Object[] o :
         (List<Object[]>)
             iHibSession
                 .createQuery(
                     "select distinct d.student.uniqueId, c, d.priority, d.alternative, r.order "
                         + "from CourseRequest r inner join r.courseOffering c inner join r.courseDemand d where d.student.session.uniqueId = :sessionId")
                 .setLong("sessionId", iSessionId)
                 .setCacheable(true)
                 .list()) {
       Long sid = (Long) o[0];
       CourseOffering co = (CourseOffering) o[1];
       Integer priority = (Integer) o[2];
       Boolean alternative = (Boolean) o[3];
       Integer order = (Integer) o[4];
       Set<WeightedCourseOffering> courses = iStudentRequests.get(sid);
       if (courses == null) {
         courses = new HashSet<WeightedCourseOffering>();
         iStudentRequests.put(sid, courses);
       }
       courses.add(new WeightedCourseOffering(co));
       if (priority != null && Boolean.FALSE.equals(alternative)) {
         if (order != null) priority += order;
         Hashtable<Long, Double> priorities = iEnrollmentPriorities.get(studentId);
         if (priorities == null) {
           priorities = new Hashtable<Long, Double>();
           iEnrollmentPriorities.put(studentId, priorities);
         }
         priorities.put(co.getUniqueId(), Math.pow(iBasePriorityWeight, priority));
       }
     }
   }
   return iStudentRequests.get(studentId);
 }
Beispiel #5
0
 protected void printHeader() throws DocumentException {
   out(
       renderMiddle(
           ApplicationProperty.WorksheetPdfAuthor.value().replace("%", Constants.getVersion()),
           ApplicationProperty.WorksheetPdfTitle.value()));
   out(
       mpad(
           new SimpleDateFormat("EEE MMM dd, yyyy").format(new Date()),
           iCurrentSubjectArea.getSession().getAcademicInitiative()
               + " "
               + iCurrentSubjectArea.getSession().getAcademicTerm()
               + " "
               + iCurrentSubjectArea.getSession().getAcademicYear(),
           ' ',
           sNrChars));
   outln('=');
   iLineNo = 0;
   if (iCourseOffering != null) println("(" + iCourseOffering.getCourseName() + " Continued)");
 }
  public int compare(Object o1, Object o2) {
    // Check if objects are of class Instructional Offering
    if (!(o1 instanceof CourseOffering)) {
      throw new ClassCastException("o1 Class must be of type CourseOffering");
    }
    if (!(o2 instanceof CourseOffering)) {
      throw new ClassCastException("o2 Class must be of type CourseOffering");
    }

    CourseOffering co1 = (CourseOffering) o1;
    CourseOffering co2 = (CourseOffering) o2;

    // Same Course Offering
    if (co1.getUniqueId().equals(co2.getUniqueId())) {
      return 0;
    }

    // One of the offerings is a Controlling Course
    if (compareBy == COMPARE_BY_CTRL_CRS) {
      if (co1.isIsControl().booleanValue()) return -1;
      if (co2.isIsControl().booleanValue()) return 1;
    }

    // Compare by course name (also used if neither is controlling)
    if (co1.getSubjectAreaAbbv().equals(co2.getSubjectAreaAbbv())) {
      if (co1.getCourseNbr().equals(co2.getCourseNbr())) {
        if (co1.getTitle() == null && co2.getTitle() == null) {
          return (0);
        } else if (co1.getTitle() == null) {
          return (-1);
        } else if (co2.getTitle() == null) {
          return (1);
        }
        return (co1.getTitle().compareTo(co2.getTitle()));
      } else {
        return (co1.getCourseNbr().compareTo(co2.getCourseNbr()));
      }
    } else {
      return (co1.getSubjectAreaAbbv().compareTo(co2.getSubjectAreaAbbv()));
    }
  }
 private void loadCourseOfferings(Long sessionId) {
   for (Iterator it = CourseOffering.findAll(sessionId).iterator(); it.hasNext(); ) {
     CourseOffering offer = (CourseOffering) it.next();
     if (offer.getPermId() != null) {
       courseOfferings.put(
           offer.getCourseNbr() + offer.getSubjectArea().getUniqueId().toString(),
           offer.getPermId());
     }
     externalIdSubjectArea.put(offer.getExternalUniqueId(), offer.getSubjectArea());
     externalIdCourseNumber.put(offer.getExternalUniqueId(), offer.getCourseNbr());
     externalIdCoursePermId.put(offer.getExternalUniqueId(), offer.getPermId());
   }
 }
Beispiel #8
0
  protected void print(CourseOffering co) throws DocumentException {
    if (!iCurrentSubjectArea.equals(co.getSubjectArea())) {
      lastPage();
      iCurrentSubjectArea = co.getSubjectArea();
      iDoc.newPage();
      printHeader();
    } else {
      if (iLineNo + 5 >= sNrLines) newPage();
    }
    iCourseOffering = co;
    int courseLimit = -1;
    InstructionalOffering offering = co.getInstructionalOffering();
    if (co.getReservation() != null) courseLimit = co.getReservation();
    if (courseLimit < 0) {
      if (offering.getCourseOfferings().size() == 1 && offering.getLimit() != null)
        courseLimit = offering.getLimit().intValue();
    }
    boolean unlimited = false;
    String courseOrg = "";
    for (Iterator i = offering.getInstrOfferingConfigs().iterator(); i.hasNext(); ) {
      InstrOfferingConfig config = (InstrOfferingConfig) i.next();
      if (config.isUnlimitedEnrollment().booleanValue()) unlimited = true;
      Hashtable creditPerIType = new Hashtable();
      for (Iterator j = config.getSchedulingSubparts().iterator(); j.hasNext(); ) {
        SchedulingSubpart subpart = (SchedulingSubpart) j.next();
        if (subpart.getMinutesPerWk().intValue() <= 0) continue;
        Integer credit = (Integer) creditPerIType.get(subpart.getItype());
        creditPerIType.put(
            subpart.getItype(),
            new Integer(
                (credit == null ? 0 : credit.intValue()) + subpart.getMinutesPerWk().intValue()));
      }
      TreeSet itypes =
          new TreeSet(
              new Comparator() {
                public int compare(Object o1, Object o2) {
                  ItypeDesc i1 = (ItypeDesc) o1;
                  ItypeDesc i2 = (ItypeDesc) o2;
                  return i1.getItype().compareTo(i2.getItype());
                }
              });
      itypes.addAll(creditPerIType.keySet());
      for (Iterator j = itypes.iterator(); j.hasNext(); ) {
        ItypeDesc itype = (ItypeDesc) j.next();
        int minPerWeek = ((Integer) creditPerIType.get(itype)).intValue();
        if (courseOrg.length() > 0) courseOrg += ", ";
        courseOrg += itype.getAbbv().trim() + " " + ((minPerWeek + 49) / 50);
      }
      break;
    }
    int enrl = -1;
    String s1 =
        co.getSubjectArea().getSession().getAcademicTerm().substring(0, 1)
            + co.getSubjectArea().getSession().getAcademicYear().substring(2);
    String s2 =
        co.getSubjectArea().getSession().getAcademicTerm().substring(0, 1)
            + new DecimalFormat("00")
                .format(
                    Integer.parseInt(
                            co.getSubjectArea().getSession().getAcademicYear().substring(2))
                        - 1);
    if (co.getProjectedDemand() != null) enrl = co.getProjectedDemand().intValue();
    int lastLikeEnrl = co.getCourseOfferingDemands().size();
    String title = co.getTitle();
    if (title == null) title = "*** Title not set";
    println(
        "                                                                                              Proj  "
            + s2
            + "                     ");
    println(
        "Course     Title/Notes                           Credit Course Organization             Limit Enrl  Enrl  Consent    Cross List");
    println(
        "---------- ------------------------------------- ------ ------------------------------- ----- ----- ----- ---------- ----------");
    println(
        rpad(co.getCourseName(), 10)
            + " "
            + rpad(title, 37)
            + (title.length() > 37 ? "-" : " ")
            + " "
            + rpad(co.getCredit() == null ? "" : co.getCredit().creditAbbv(), 5)
            + " "
            + rpad(courseOrg, 31)
            + " "
            + lpad(courseLimit <= 0 ? unlimited ? "  inf" : "" : String.valueOf(courseLimit), 5)
            + " "
            + lpad(enrl <= 0 ? "" : String.valueOf(enrl), 5)
            + " "
            + lpad(lastLikeEnrl <= 0 ? "" : String.valueOf(lastLikeEnrl), 5)
            + " "
            + rpad(co.getConsentType() == null ? "" : co.getConsentType().getAbbv(), 10)
            + " "
            + rpad(offering.getCourseOfferings().size() > 1 ? offering.getCourseName() : "", 10));
    while (title.length() > 37) {
      title = title.substring(37);
      println("           " + rpad(title, 37) + (title.length() > 37 ? "-" : " "));
    }
    if (co.getScheduleBookNote() != null && co.getScheduleBookNote().trim().length() > 0) {
      String note = co.getScheduleBookNote();
      note = note.replaceAll("\\. ", "\\.\n");
      for (StringTokenizer s = new StringTokenizer(note, "\n\r"); s.hasMoreTokens(); ) {
        String line = s.nextToken().trim();
        while (line.length() > sNrChars - 7) {
          println("   " + line.substring(0, sNrChars - 7) + "-");
          line = line.substring(sNrChars - 7);
        }
        println("   " + line);
      }
    }
    if (iLineNo + 5 >= sNrLines) newPage();
    else println("");
    println("        " + s1 + "   " + s2 + "  Proj | Type");
    println(
        "Curr  Reqst  Enrl  Enrl | Instr Number Time                                     Limit Bldg-Room          Instructor            Mgr");
    println(
        "----  -----  ----  ---- | ----- ------ ---------------------------------------- ----- ------------------ --------------------- ------");

    Vector rTable = new Vector();
    // TODO: Print request data based on curricula
    /*
    int a=0,b=0,c=0;
    for (Iterator i=co.getAcadAreaReservations().iterator();i.hasNext();) {
        AcadAreaReservation ar = (AcadAreaReservation)i.next();
        rTable.add(
                lpad(ar.getAcademicArea().getAcademicAreaAbbreviation(),4)+"  "+
                lpad(ar.getRequested()==null?"":ar.getRequested().toString(),5)+" "+
                lpad(ar.getPriorEnrollment()==null?"":ar.getPriorEnrollment().toString(),5)+" "+
                lpad(ar.getProjectedEnrollment()==null?"":ar.getProjectedEnrollment().toString(),5));
        if (ar.getRequested()!=null) a+=ar.getRequested().intValue();
        if (ar.getPriorEnrollment()!=null) b+=ar.getPriorEnrollment().intValue();
        if (ar.getProjectedEnrollment()!=null) c+=ar.getProjectedEnrollment().intValue();
    }
    if (rTable.isEmpty()) {
        rTable.add(" *** No Request Data   ");
    } else {
        rTable.add(
                " Tot  "+
                lpad(String.valueOf(a),5)+" "+
                lpad(String.valueOf(b),5)+" "+
                lpad(String.valueOf(c),5));
        rTable.add("                       ");
        rTable.add(" *Please check requests");
    }
    */
    Vector cTable = new Vector();
    if (offering.isNotOffered().booleanValue()) cTable.add(" ** Course not offered");
    Vector gTable = new Vector();
    TreeSet configs = new TreeSet(new InstrOfferingConfigComparator(null));
    configs.addAll(offering.getInstrOfferingConfigs());
    for (Iterator i = configs.iterator(); i.hasNext(); ) {
      InstrOfferingConfig config = (InstrOfferingConfig) i.next();
      if (offering.getInstrOfferingConfigs().size() > 1)
        cTable.add("** Configuration " + config.getName());
      TreeSet subparts = new TreeSet(new SchedulingSubpartComparator());
      subparts.addAll(config.getSchedulingSubparts());
      for (Iterator j = subparts.iterator(); j.hasNext(); ) {
        SchedulingSubpart subpart = (SchedulingSubpart) j.next();
        TreeSet classes = new TreeSet(new ClassComparator(ClassComparator.COMPARE_BY_HIERARCHY));
        classes.addAll(subpart.getClasses());
        String subpartLabel = subpart.getItype().getAbbv();
        boolean same = false;
        for (Iterator k = classes.iterator(); k.hasNext(); ) {
          Class_ clazz = (Class_) k.next();
          String[] time = time(clazz);
          String[] rooms = room(clazz);
          String[] instr = instructor(clazz);
          for (int x = 0;
              x < Math.max(Math.max(1, time.length), Math.max(instr.length, rooms.length));
              x++) {
            cTable.add(
                rpad(same ? "" : x == 0 ? subpartLabel : "", 5)
                    + " "
                    + lpad(x == 0 ? clazz.getSectionNumberString() : "", 6)
                    + " "
                    + rpad(time != null && x < time.length ? time[x] : "", 40)
                    + " "
                    + lpad(
                        x == 0 && clazz.getClassLimit() > 0 && clazz.getNbrRooms().intValue() > 0
                            ? (clazz.getNbrRooms().intValue() > 1 ? clazz.getNbrRooms() + "x" : "")
                                + String.valueOf(clazz.getClassLimit())
                            : "",
                        5)
                    + " "
                    + rpad(rooms != null && x < rooms.length ? rooms[x] : "", 18)
                    + " "
                    + rpad(instr != null && x < instr.length ? instr[x] : "", 21)
                    + " "
                    + rpad(x == 0 ? clazz.getManagingDept().getShortLabel() : "", 6));
          }
          same = true;
          if (clazz.getParentClass() != null && clazz.getChildClasses().isEmpty()) {
            String gr =
                clazz.getSchedulingSubpart().getItype().getAbbv().trim()
                    + lpad(clazz.getSectionNumberString(), 4);
            Class_ parent = clazz.getParentClass();
            while (parent != null) {
              gr =
                  parent.getSchedulingSubpart().getItype().getAbbv().trim()
                      + lpad(parent.getSectionNumberString(), 4)
                      + ", "
                      + gr;
              parent = parent.getParentClass();
            }
            gTable.add(gr);
          }
        }
      }
    }
    for (int i = 0; i < 1 + Math.max(rTable.size(), cTable.size()); i++) {
      String res = null;
      String cl = null;
      if (i < rTable.size()) res = (String) rTable.elementAt(i);
      if (i < cTable.size()) cl = (String) cTable.elementAt(i);
      println(rpad(res, 23) + " | " + (cl == null ? "" : cl));
    }
    if (!gTable.isEmpty()) {
      println(rep('-', sNrChars));
      println("     Course groups:");
      int half = (gTable.size() + 1) / 2;
      for (int i = 0; i < half; i++) {
        String gr1 = (String) gTable.elementAt(i);
        String gr2 = (half + i < gTable.size() ? (String) gTable.elementAt(half + i) : "");
        println("     " + rpad(gr1, 60) + " | " + rpad(gr2, 60));
      }
    }
    println(rep('=', sNrChars));
    iCourseOffering = null;
  }
  public void reloadOffering(
      final OnlineSectioningServer server, OnlineSectioningHelper helper, Long offeringId) {
    // Load new students
    Map<Long, org.unitime.timetable.model.Student> newStudents =
        new HashMap<Long, org.unitime.timetable.model.Student>();
    /*
    for (org.unitime.timetable.model.Student student : (List<org.unitime.timetable.model.Student>)helper.getHibSession().createQuery(
                  "select s from Student s " +
                  "left join fetch s.courseDemands as cd " +
                  "left join fetch cd.courseRequests as cr " +
                  "left join fetch cr.courseOffering as co " +
                  "left join fetch cr.classWaitLists as cwl " +
                  "left join fetch s.classEnrollments as e " +
                  "left join fetch s.academicAreaClassifications as a " +
                  "left join fetch s.posMajors as mj " +
                  "left join fetch s.waitlists as w " +
                  "left join fetch s.groups as g " +
                  "where s.uniqueId in (select xe.student.uniqueId from StudentClassEnrollment xe where xe.courseOffering.instructionalOffering.uniqueId = :offeringId) " +
                  "or s.uniqueId in (select xr.courseDemand.student.uniqueId from CourseRequest xr where xr.courseOffering.instructionalOffering.uniqueId = :offeringId)"
                  ).setLong("offeringId", offeringId).list()) {
    	newStudents.put(student.getUniqueId(), student);
    }
    */
    for (org.unitime.timetable.model.Student student :
        (List<org.unitime.timetable.model.Student>)
            helper
                .getHibSession()
                .createQuery(
                    "select distinct s from Student s "
                        + "left join s.courseDemands as cd "
                        + "left join cd.courseRequests as cr "
                        + "left join fetch s.classEnrollments as e "
                        + "left join fetch s.academicAreaClassifications as a "
                        + "left join fetch s.posMajors as mj "
                        + "left join fetch s.waitlists as w "
                        + "left join fetch s.groups as g "
                        + "where cr.courseOffering.instructionalOffering.uniqueId = :offeringId")
                .setLong("offeringId", offeringId)
                .list()) {
      newStudents.put(student.getUniqueId(), student);
    }
    for (org.unitime.timetable.model.Student student :
        (List<org.unitime.timetable.model.Student>)
            helper
                .getHibSession()
                .createQuery(
                    "select distinct s from Student s "
                        + "left join fetch s.courseDemands as cd "
                        + "left join fetch cd.courseRequests as cr "
                        + "left join fetch cr.courseOffering as co "
                        + "left join fetch cr.classWaitLists as cwl "
                        + "left join fetch s.classEnrollments as e "
                        + "left join fetch s.academicAreaClassifications as a "
                        + "left join fetch s.posMajors as mj "
                        + "left join fetch s.waitlists as w "
                        + "left join fetch s.groups as g "
                        + "where e.courseOffering.instructionalOffering.uniqueId = :offeringId and e.courseRequest is null")
                .setLong("offeringId", offeringId)
                .list()) {
      newStudents.put(student.getUniqueId(), student);
    }

    // Persist expected spaces if needed
    if (server.needPersistExpectedSpaces(offeringId))
      PersistExpectedSpacesAction.persistExpectedSpaces(offeringId, false, server, helper);

    // Existing offering
    XOffering oldOffering = server.getOffering(offeringId);
    XEnrollments oldEnrollments = server.getEnrollments(offeringId);

    // New offering
    XOffering newOffering = null;
    InstructionalOffering io =
        InstructionalOfferingDAO.getInstance().get(offeringId, helper.getHibSession());
    List<XDistribution> distributions = new ArrayList<XDistribution>();
    if (io != null) {
      // Load linked sections and ignore student conflict constraints
      List<DistributionPref> distPrefs =
          helper
              .getHibSession()
              .createQuery(
                  "select distinct p from DistributionPref p inner join p.distributionObjects o, Department d, "
                      + "Class_ c inner join c.schedulingSubpart.instrOfferingConfig.instructionalOffering io "
                      + "where p.distributionType.reference in (:ref1, :ref2) and d.session.uniqueId = :sessionId "
                      + "and io.uniqueId = :offeringId and (o.prefGroup = c or o.prefGroup = c.schedulingSubpart) "
                      + "and p.owner = d and p.prefLevel.prefProlog = :pref")
              .setString("ref1", GroupConstraint.ConstraintType.LINKED_SECTIONS.reference())
              .setString("ref2", IgnoreStudentConflictsConstraint.REFERENCE)
              .setString("pref", PreferenceLevel.sRequired)
              .setLong("sessionId", server.getAcademicSession().getUniqueId())
              .setLong("offeringId", offeringId)
              .list();
      if (!distPrefs.isEmpty()) {
        for (DistributionPref pref : distPrefs) {
          int variant = 0;
          for (Collection<Class_> sections : ReloadAllData.getSections(pref)) {
            XDistributionType type = XDistributionType.IngoreConflicts;
            if (GroupConstraint.ConstraintType.LINKED_SECTIONS
                .reference()
                .equals(pref.getDistributionType().getReference()))
              type = XDistributionType.LinkedSections;
            XDistribution distribution =
                new XDistribution(type, pref.getUniqueId(), variant++, sections);
            distributions.add(distribution);
          }
        }
      }

      newOffering = ReloadAllData.loadOffering(io, distributions, server, helper);
      if (newOffering != null) server.update(newOffering);
      else if (oldOffering != null) server.remove(oldOffering);

      // Load sectioning info
      List<Object[]> infos =
          helper
              .getHibSession()
              .createQuery(
                  "select i.clazz.uniqueId, i.nbrExpectedStudents from SectioningInfo i where i.clazz.schedulingSubpart.instrOfferingConfig.instructionalOffering.uniqueId = :offeringId")
              .setLong("offeringId", offeringId)
              .list();
      XExpectations expectations = new XExpectations(offeringId);
      for (Object[] info : infos) {
        Long sectionId = (Long) info[0];
        Double expected = (Double) info[1];
        expectations.setExpectedSpace(sectionId, expected);
      }
      server.update(expectations);
    } else if (oldOffering != null) {
      server.remove(oldOffering);
    }

    List<XStudent[]> students = new ArrayList<XStudent[]>();

    if (oldEnrollments != null) {
      Set<Long> checked = new HashSet<Long>();
      for (XRequest old : oldEnrollments.getRequests()) {
        if (!checked.add(old.getStudentId())) continue;
        XStudent oldStudent = server.getStudent(old.getStudentId());
        org.unitime.timetable.model.Student student = newStudents.get(oldStudent.getStudentId());
        if (student == null)
          student = StudentDAO.getInstance().get(oldStudent.getStudentId(), helper.getHibSession());
        XStudent newStudent =
            (student == null ? null : ReloadAllData.loadStudent(student, null, server, helper));
        if (newStudent != null) server.update(newStudent, true);
        else server.remove(oldStudent);
        students.add(new XStudent[] {oldStudent, newStudent});
        newStudents.remove(oldStudent.getStudentId());
      }
    }
    for (org.unitime.timetable.model.Student student : newStudents.values()) {
      XStudent oldStudent = server.getStudent(student.getUniqueId());
      XStudent newStudent = ReloadAllData.loadStudent(student, null, server, helper);
      if (newStudent != null) server.update(newStudent, true);
      else if (oldStudent != null) server.remove(oldStudent);
      students.add(new XStudent[] {oldStudent, newStudent});
    }

    if (!server.getAcademicSession().isSectioningEnabled()) return;

    if (!CustomStudentEnrollmentHolder.isAllowWaitListing()) return;

    if (newOffering == null && oldOffering == null) return;

    Set<SectioningRequest> queue = new TreeSet<SectioningRequest>();

    Set<XCourseId> courseIds = new HashSet<XCourseId>();
    if (newOffering != null) courseIds.addAll(newOffering.getCourses());
    if (oldOffering != null) courseIds.addAll(oldOffering.getCourses());

    for (XCourseId course : courseIds) {
      for (XStudent[] student : students) {
        if (student[0] == null && student[1] == null) continue;
        XEnrollment oldEnrollment = null;
        XCourseRequest oldRequest = null;
        if (student[0] != null) {
          for (XRequest r : student[0].getRequests())
            if (r instanceof XCourseRequest) {
              XCourseRequest cr = (XCourseRequest) r;
              for (XCourseId c : cr.getCourseIds()) {
                if (c.equals(course)) {
                  oldRequest = cr;
                  if (cr.getEnrollment() != null
                      && offeringId.equals(cr.getEnrollment().getOfferingId()))
                    oldEnrollment = cr.getEnrollment();
                  break;
                }
              }
            }
        }
        XCourseRequest newRequest = null;
        XEnrollment newEnrollment = null;
        if (student[1] != null) {
          for (XRequest r : student[1].getRequests())
            if (r instanceof XCourseRequest) {
              XCourseRequest cr = (XCourseRequest) r;
              for (XCourseId c : cr.getCourseIds())
                if (c.equals(course)) {
                  newRequest = cr;
                  if (cr.getEnrollment() != null
                      && offeringId.equals(cr.getEnrollment().getOfferingId()))
                    newEnrollment = cr.getEnrollment();
                  break;
                }
            }
        }
        if (oldRequest == null && newRequest == null) continue;

        OnlineSectioningLog.Action.Builder action =
            helper.addAction(this, server.getAcademicSession());
        action.setStudent(
            OnlineSectioningLog.Entity.newBuilder()
                .setUniqueId(
                    student[0] == null ? student[1].getStudentId() : student[0].getStudentId())
                .setExternalId(
                    student[0] == null ? student[1].getExternalId() : student[0].getExternalId()));
        action.addOther(
            OnlineSectioningLog.Entity.newBuilder()
                .setUniqueId(offeringId)
                .setName(newOffering == null ? oldOffering.getName() : newOffering.getName())
                .setType(OnlineSectioningLog.Entity.EntityType.OFFERING));
        action.addOther(
            OnlineSectioningLog.Entity.newBuilder()
                .setUniqueId(course.getCourseId())
                .setName(course.getCourseName())
                .setType(OnlineSectioningLog.Entity.EntityType.COURSE));

        if (oldEnrollment != null) {
          OnlineSectioningLog.Enrollment.Builder enrollment =
              OnlineSectioningLog.Enrollment.newBuilder();
          enrollment.setType(OnlineSectioningLog.Enrollment.EnrollmentType.PREVIOUS);
          for (Long sectionId : oldEnrollment.getSectionIds())
            enrollment.addSection(
                OnlineSectioningHelper.toProto(oldOffering.getSection(sectionId), oldEnrollment));
          action.addEnrollment(enrollment);
          if (newRequest == null) action.addRequest(OnlineSectioningHelper.toProto(oldRequest));
        }

        if (newRequest == null) {
          // nothing to re-assign
          if (oldEnrollment != null && CustomStudentEnrollmentHolder.hasProvider()) {
            // there was a drop
            try {
              CustomStudentEnrollmentHolder.getProvider()
                  .resection(
                      server,
                      helper,
                      new SectioningRequest(newOffering, newRequest, student[1], action)
                          .setOldOffering(oldOffering)
                          .setOldStudent(student[0])
                          .setOldRequest(oldRequest)
                          .setLastEnrollment(oldEnrollment),
                      null);
            } catch (Exception ex) {
              action.setResult(OnlineSectioningLog.Action.ResultType.FAILURE);
              action.addMessage(
                  OnlineSectioningLog.Message.newBuilder()
                      .setLevel(OnlineSectioningLog.Message.Level.FATAL)
                      .setText(ex.getMessage() == null ? "null" : ex.getMessage()));
              helper.error("Unable to resection student: " + ex.getMessage(), ex);
            }
          }
          action.setEndTime(System.currentTimeMillis());
          server.execute(
              server
                  .createAction(NotifyStudentAction.class)
                  .forStudent(
                      student[0] == null ? student[1].getStudentId() : student[0].getStudentId())
                  .oldEnrollment(oldOffering, course, oldEnrollment),
              helper.getUser());
          continue;
        } else {
          action.addRequest(OnlineSectioningHelper.toProto(newRequest));
        }

        if (oldEnrollment == null && newEnrollment == null) {
          if (student[1].canAssign(newRequest)
              && isWaitListed(student[1], newRequest, server, helper))
            queue.add(
                new SectioningRequest(newOffering, newRequest, student[1], action)
                    .setOldOffering(oldOffering)
                    .setOldRequest(oldRequest)
                    .setOldStudent(student[0]));
          continue;
        }

        if (newEnrollment != null) {
          // new enrollment is valid and / or has all the same times
          if (check(
              newOffering,
              course,
              distributions,
              student[1],
              newEnrollment,
              server)) { // || isSame(oldEnrollment, newEnrollment)) {
            OnlineSectioningLog.Enrollment.Builder enrollment =
                OnlineSectioningLog.Enrollment.newBuilder();
            enrollment.setType(OnlineSectioningLog.Enrollment.EnrollmentType.STORED);
            for (XSection assignment : newOffering.getSections(newEnrollment))
              enrollment.addSection(OnlineSectioningHelper.toProto(assignment, newEnrollment));
            action.addEnrollment(enrollment);

            // there may have been a change
            if (CustomStudentEnrollmentHolder.hasProvider()) {
              try {
                CustomStudentEnrollmentHolder.getProvider()
                    .resection(
                        server,
                        helper,
                        new SectioningRequest(newOffering, newRequest, student[1], action)
                            .setOldOffering(oldOffering)
                            .setOldStudent(student[0])
                            .setOldRequest(oldRequest)
                            .setLastEnrollment(oldEnrollment),
                        newEnrollment);
              } catch (Exception ex) {
                action.setResult(OnlineSectioningLog.Action.ResultType.FAILURE);
                action.addMessage(
                    OnlineSectioningLog.Message.newBuilder()
                        .setLevel(OnlineSectioningLog.Message.Level.FATAL)
                        .setText(ex.getMessage() == null ? "null" : ex.getMessage()));
                helper.error("Unable to resection student: " + ex.getMessage(), ex);
              }
            }
            action.setEndTime(System.currentTimeMillis());

            if (!isVerySame(
                newEnrollment.getCourseId(),
                newOffering.getSections(newEnrollment),
                oldOffering.getSections(oldEnrollment)))
              server.execute(
                  server
                      .createAction(NotifyStudentAction.class)
                      .forStudent(
                          student[0] == null
                              ? student[1].getStudentId()
                              : student[0].getStudentId())
                      .oldEnrollment(oldOffering, course, oldEnrollment),
                  helper.getUser());
            continue;
          }
        }
        newRequest = server.assign(newRequest, null);
        queue.add(
            new SectioningRequest(newOffering, newRequest, student[1], action)
                .setOldOffering(oldOffering)
                .setOldRequest(oldRequest)
                .setOldStudent(student[0])
                .setLastEnrollment(oldEnrollment)
                .setNewEnrollment(newEnrollment));
      }
    }

    if (!queue.isEmpty()) {
      DataProperties properties = new DataProperties();
      ResectioningWeights w = new ResectioningWeights(properties);
      DistanceConflict dc = new DistanceConflict(server.getDistanceMetric(), properties);
      TimeOverlapsCounter toc = new TimeOverlapsCounter(null, properties);
      Date ts = new Date();
      for (SectioningRequest r : queue) {
        helper.debug(
            "Resectioning "
                + r.getRequest()
                + " (was "
                + (r.getLastEnrollment() == null
                    ? "not assigned"
                    : r.getLastEnrollment().getSectionIds())
                + ")");
        long c0 = OnlineSectioningHelper.getCpuTime();
        XEnrollment e = r.resection(server, w, dc, toc);

        if (e != null) {
          e.setTimeStamp(ts);
          OnlineSectioningLog.Enrollment.Builder enrollment =
              OnlineSectioningLog.Enrollment.newBuilder();
          enrollment.setType(OnlineSectioningLog.Enrollment.EnrollmentType.STORED);
          for (Long sectionId : e.getSectionIds())
            enrollment.addSection(
                OnlineSectioningHelper.toProto(newOffering.getSection(sectionId), e));
          r.getAction().addEnrollment(enrollment);
        }

        if (CustomStudentEnrollmentHolder.hasProvider()) {
          try {
            e = CustomStudentEnrollmentHolder.getProvider().resection(server, helper, r, e);
          } catch (Exception ex) {
            r.getAction().setResult(OnlineSectioningLog.Action.ResultType.FAILURE);
            r.getAction()
                .addMessage(
                    OnlineSectioningLog.Message.newBuilder()
                        .setLevel(OnlineSectioningLog.Message.Level.FATAL)
                        .setText(ex.getMessage() == null ? "null" : ex.getMessage()));
            helper.error("Unable to resection student: " + ex.getMessage(), ex);
            if (r.getNewEnrollment() != null) server.assign(r.getRequest(), r.getNewEnrollment());
            continue;
          }
        }

        if (e == null && r.getLastEnrollment() == null) {
          // remained unassigned
          continue;
        }

        if (e != null) {
          r.setRequest(server.assign(r.getRequest(), e));
        }
        helper.debug("New: " + (e == null ? "not assigned" : e.getSectionIds()));

        org.unitime.timetable.model.Student student =
            StudentDAO.getInstance().get(r.getRequest().getStudentId(), helper.getHibSession());
        Map<Long, StudentClassEnrollment> enrollmentMap =
            new HashMap<Long, StudentClassEnrollment>();
        String approvedBy = null;
        Date approvedDate = null;
        for (Iterator<StudentClassEnrollment> i = student.getClassEnrollments().iterator();
            i.hasNext(); ) {
          StudentClassEnrollment enrl = i.next();
          if ((enrl.getCourseRequest() != null
                  && enrl.getCourseRequest()
                      .getCourseDemand()
                      .getUniqueId()
                      .equals(r.getRequest().getRequestId()))
              || (enrl.getCourseOffering() != null
                  && enrl.getCourseOffering()
                      .getUniqueId()
                      .equals(r.getCourseId().getCourseId()))) {
            helper.debug("Deleting " + enrl.getClazz().getClassLabel());
            enrollmentMap.put(enrl.getClazz().getUniqueId(), enrl);
            if (approvedBy == null && enrl.getApprovedBy() != null) {
              approvedBy = enrl.getApprovedBy();
              approvedDate = enrl.getApprovedDate();
            }
            enrl.getClazz().getStudentEnrollments().remove(enrl);
            helper.getHibSession().delete(enrl);
            i.remove();
          }
        }
        CourseDemand cd = null;
        demands:
        for (CourseDemand x : student.getCourseDemands())
          for (org.unitime.timetable.model.CourseRequest q : x.getCourseRequests())
            if (q.getCourseOffering().getInstructionalOffering().getUniqueId().equals(offeringId)) {
              cd = x;
              break demands;
            }

        if (r.getRequest().getEnrollment() != null) { // save enrollment
          org.unitime.timetable.model.CourseRequest cr = null;
          CourseOffering co = null;
          if (co == null)
            for (CourseOffering x : io.getCourseOfferings())
              if (x.getUniqueId().equals(r.getRequest().getEnrollment().getCourseId())) co = x;
          for (Long sectionId : r.getRequest().getEnrollment().getSectionIds()) {
            Class_ clazz = Class_DAO.getInstance().get(sectionId, helper.getHibSession());
            if (cd != null && cr == null) {
              for (org.unitime.timetable.model.CourseRequest x : cd.getCourseRequests())
                if (x.getCourseOffering()
                    .getInstructionalOffering()
                    .getUniqueId()
                    .equals(offeringId)) {
                  cr = x;
                  break;
                }
            }
            if (co == null)
              co =
                  clazz
                      .getSchedulingSubpart()
                      .getInstrOfferingConfig()
                      .getInstructionalOffering()
                      .getControllingCourseOffering();
            StudentClassEnrollment enrl = new StudentClassEnrollment();
            enrl.setClazz(clazz);
            clazz.getStudentEnrollments().add(enrl);
            enrl.setCourseOffering(co);
            enrl.setCourseRequest(cr);
            StudentClassEnrollment old = enrollmentMap.get(sectionId);
            enrl.setTimestamp(old != null ? old.getTimestamp() : ts);
            enrl.setChangedBy(
                old != null
                    ? old.getChangedBy()
                    : helper.getUser() == null
                        ? StudentClassEnrollment.SystemChange.SYSTEM.toString()
                        : helper.getUser().getExternalId());
            enrl.setStudent(student);
            enrl.setApprovedBy(approvedBy);
            enrl.setApprovedDate(approvedDate);
            student.getClassEnrollments().add(enrl);
            /*
            if (cr != null) {
            	if (cr.getClassEnrollments() == null) cr.setClassEnrollments(new HashSet<StudentClassEnrollment>());
            	cr.getClassEnrollments().add(enrl);
            }
            */
            helper.debug("Adding " + enrl.getClazz().getClassLabel());
          }
        } else if (!r.getRequest().isAlternative()) { // wait-list
          if (cd != null && !cd.isWaitlist()) {
            cd.setWaitlist(true);
            helper.getHibSession().saveOrUpdate(cd);
          }
          if (!r.getRequest().isWaitlist()) r.setRequest(server.waitlist(r.getRequest(), true));
        }

        helper.getHibSession().save(student);

        EnrollStudent.updateSpace(
            server,
            r.getRequest().getEnrollment() == null
                ? null
                : SectioningRequest.convert(
                    r.getStudent(),
                    r.getRequest(),
                    server,
                    newOffering,
                    r.getRequest().getEnrollment()),
            r.getLastEnrollment() == null
                ? null
                : SectioningRequest.convert(
                    r.getOldStudent(),
                    r.getOldRequest(),
                    server,
                    oldOffering,
                    r.getLastEnrollment()),
            newOffering,
            oldOffering);
        server.persistExpectedSpaces(offeringId);

        server.execute(
            server
                .createAction(NotifyStudentAction.class)
                .forStudent(r.getRequest().getStudentId())
                .oldEnrollment(oldOffering, r.getCourseId(), r.getLastEnrollment()),
            helper.getUser());

        r.getAction()
            .setResult(
                e == null
                    ? OnlineSectioningLog.Action.ResultType.NULL
                    : OnlineSectioningLog.Action.ResultType.SUCCESS);
        r.getAction().setCpuTime(OnlineSectioningHelper.getCpuTime() - c0);
        r.getAction().setEndTime(System.currentTimeMillis());
      }
    }
  }
  public void csvTableForClasses(
      PrintWriter out,
      ClassAssignmentProxy classAssignment,
      ExamAssignmentProxy examAssignment,
      ClassAssignmentsReportForm form,
      SessionContext context)
      throws Exception {
    setVisibleColumns(form);

    Collection classes = (Collection) form.getClasses();

    if (isShowTimetable()) {
      boolean hasTimetable = false;
      if (context.hasPermission(Right.ClassAssignments) && classAssignment != null) {
        if (classAssignment instanceof CachedClassAssignmentProxy) {
          ((CachedClassAssignmentProxy) classAssignment).setCache(classes);
        }
        for (Iterator i = classes.iterator(); i.hasNext(); ) {
          Object[] o = (Object[]) i.next();
          Class_ clazz = (Class_) o[0];
          if (classAssignment.getAssignment(clazz) != null) {
            hasTimetable = true;
            break;
          }
        }
      }
      setDisplayTimetable(hasTimetable);
    }
    setUserSettings(context.getUser());

    if (examAssignment != null
        || Exam.hasTimetable(context.getUser().getCurrentAcademicSessionId())) {
      setShowExam(true);
      setShowExamTimetable(true);
      setShowExamName(false);
    }
    setShowInstructor(true);
    if (StudentClassEnrollment.sessionHasEnrollments(
        context.getUser().getCurrentAcademicSessionId())) {
      setShowDemand(true);
    }

    iFile = new CSVFile();

    int ct = 0;
    Iterator it = classes.iterator();
    SubjectArea subjectArea = null;
    String prevLabel = null;
    while (it.hasNext()) {
      Object[] o = (Object[]) it.next();
      Class_ c = (Class_) o[0];
      CourseOffering co = (CourseOffering) o[1];
      if (subjectArea == null
          || !subjectArea.getUniqueId().equals(co.getSubjectArea().getUniqueId())) {
        if (iFile.getLines() != null) iFile.addLine();

        subjectArea = co.getSubjectArea();
        ct = 0;

        iFile.addLine(labelForTable(subjectArea));
        csvBuildTableHeader(context.getUser().getCurrentAcademicSessionId());
      }

      csvBuildClassRow(classAssignment, examAssignment, ++ct, co, c, "", context, prevLabel);
      prevLabel = c.getClassLabel(co);
    }

    save(out);
  }