@Override
  public List<EnrollmentRequest> execute(
      OnlineSectioningServer server, OnlineSectioningHelper helper) {
    Lock readLock = server.readLock();
    try {
      Set<Long> offeringIds = new HashSet<Long>();
      for (ClassAssignmentInterface.ClassAssignment ca : getAssignment())
        if (ca != null && !ca.isFreeTime()) {
          XCourse course = server.getCourse(ca.getCourseId());
          if (course != null) offeringIds.add(course.getOfferingId());
        }

      Lock lock = server.lockStudent(getStudentId(), offeringIds, name());
      try {
        return check(server, helper);
      } finally {
        lock.release();
      }
    } finally {
      readLock.release();
    }
  }
  public static GwtRpcResponseList<ClassAssignmentInterface.Enrollment> convert(
      Collection<StudentClassEnrollment> enrollments,
      Map<Long, List<Meeting>> conflicts,
      boolean canShowExtId,
      boolean canRegister,
      boolean canUseAssistant) {
    GwtRpcResponseList<ClassAssignmentInterface.Enrollment> converted =
        new GwtRpcResponseList<ClassAssignmentInterface.Enrollment>();
    Map<String, String> approvedBy2name = new Hashtable<String, String>();
    Hashtable<Long, ClassAssignmentInterface.Enrollment> student2enrollment =
        new Hashtable<Long, ClassAssignmentInterface.Enrollment>();
    for (StudentClassEnrollment enrollment : enrollments) {
      ClassAssignmentInterface.Enrollment enrl =
          student2enrollment.get(enrollment.getStudent().getUniqueId());
      if (enrl == null) {
        ClassAssignmentInterface.Student st = new ClassAssignmentInterface.Student();
        st.setId(enrollment.getStudent().getUniqueId());
        st.setExternalId(enrollment.getStudent().getExternalUniqueId());
        st.setCanShowExternalId(canShowExtId);
        st.setCanRegister(canRegister);
        st.setCanUseAssistant(canUseAssistant);
        st.setName(
            enrollment
                .getStudent()
                .getName(ApplicationProperty.OnlineSchedulingStudentNameFormat.value()));
        for (AcademicAreaClassification ac :
            enrollment.getStudent().getAcademicAreaClassifications()) {
          st.addArea(ac.getAcademicArea().getAcademicAreaAbbreviation());
          st.addClassification(ac.getAcademicClassification().getCode());
        }
        for (PosMajor m : enrollment.getStudent().getPosMajors()) {
          st.addMajor(m.getCode());
        }
        for (StudentGroup g : enrollment.getStudent().getGroups()) {
          st.addGroup(g.getGroupAbbreviation());
        }
        for (StudentAccomodation a : enrollment.getStudent().getAccomodations()) {
          st.addAccommodation(a.getAbbreviation());
        }
        enrl = new ClassAssignmentInterface.Enrollment();
        enrl.setStudent(st);
        enrl.setEnrolledDate(enrollment.getTimestamp());
        CourseAssignment c = new CourseAssignment();
        c.setCourseId(enrollment.getCourseOffering().getUniqueId());
        c.setSubject(enrollment.getCourseOffering().getSubjectAreaAbbv());
        c.setCourseNbr(enrollment.getCourseOffering().getCourseNbr());
        enrl.setCourse(c);
        student2enrollment.put(enrollment.getStudent().getUniqueId(), enrl);
        if (enrollment.getCourseRequest() != null) {
          enrl.setPriority(1 + enrollment.getCourseRequest().getCourseDemand().getPriority());
          if (enrollment.getCourseRequest().getCourseDemand().getCourseRequests().size() > 1) {
            CourseRequest first = null;
            for (CourseRequest r :
                enrollment.getCourseRequest().getCourseDemand().getCourseRequests()) {
              if (first == null || r.getOrder().compareTo(first.getOrder()) < 0) first = r;
            }
            if (!first.equals(enrollment.getCourseRequest()))
              enrl.setAlternative(first.getCourseOffering().getCourseName());
          }
          if (enrollment.getCourseRequest().getCourseDemand().isAlternative()) {
            CourseDemand first = enrollment.getCourseRequest().getCourseDemand();
            demands:
            for (CourseDemand cd : enrollment.getStudent().getCourseDemands()) {
              if (!cd.isAlternative()
                  && cd.getPriority().compareTo(first.getPriority()) < 0
                  && !cd.getCourseRequests().isEmpty()) {
                for (CourseRequest cr : cd.getCourseRequests())
                  if (cr.getClassEnrollments().isEmpty()) continue demands;
                first = cd;
              }
            }
            CourseRequest alt = null;
            for (CourseRequest r : first.getCourseRequests()) {
              if (alt == null || r.getOrder().compareTo(alt.getOrder()) < 0) alt = r;
            }
            enrl.setAlternative(alt.getCourseOffering().getCourseName());
          }
          enrl.setRequestedDate(enrollment.getCourseRequest().getCourseDemand().getTimestamp());
          enrl.setApprovedDate(enrollment.getApprovedDate());
          if (enrollment.getApprovedBy() != null) {
            String name = approvedBy2name.get(enrollment.getApprovedBy());
            if (name == null) {
              TimetableManager mgr =
                  (TimetableManager)
                      EventDAO.getInstance()
                          .getSession()
                          .createQuery("from TimetableManager where externalUniqueId = :externalId")
                          .setString("externalId", enrollment.getApprovedBy())
                          .setMaxResults(1)
                          .uniqueResult();
              if (mgr != null) {
                name = mgr.getName();
              } else {
                DepartmentalInstructor instr =
                    (DepartmentalInstructor)
                        EventDAO.getInstance()
                            .getSession()
                            .createQuery(
                                "from DepartmentalInstructor where externalUniqueId = :externalId and department.session.uniqueId = :sessionId")
                            .setString("externalId", enrollment.getApprovedBy())
                            .setLong(
                                "sessionId", enrollment.getStudent().getSession().getUniqueId())
                            .setMaxResults(1)
                            .uniqueResult();
                if (instr != null) name = instr.nameLastNameFirst();
              }
              if (name != null) approvedBy2name.put(enrollment.getApprovedBy(), name);
            }
            enrl.setApprovedBy(name == null ? enrollment.getApprovedBy() : name);
          }
        } else {
          enrl.setPriority(-1);
        }

        List<Meeting> conf =
            (conflicts == null ? null : conflicts.get(enrollment.getStudent().getUniqueId()));
        if (conf != null) {
          Map<Event, TreeSet<Meeting>> events = new HashMap<Event, TreeSet<Meeting>>();
          for (Meeting m : conf) {
            TreeSet<Meeting> ms = events.get(m.getEvent());
            if (ms == null) {
              ms = new TreeSet<Meeting>();
              events.put(m.getEvent(), ms);
            }
            ms.add(m);
          }
          for (Event confEvent : new TreeSet<Event>(events.keySet())) {
            Conflict conflict = new Conflict();
            conflict.setName(confEvent.getEventName());
            conflict.setType(confEvent.getEventTypeAbbv());
            String lastDate = null, lastTime = null, lastRoom = null;
            for (MultiMeeting mm : Event.getMultiMeetings(events.get(confEvent))) {
              String date =
                  getDateFormat().format(mm.getMeetings().first().getMeetingDate())
                      + (mm.getMeetings().size() == 1
                          ? ""
                          : " - "
                              + getDateFormat().format(mm.getMeetings().last().getMeetingDate()));
              if (lastDate == null) {
                conflict.setDate(date);
              } else if (lastDate.equals(date)) {
                conflict.setDate(conflict.getDate() + "<br>");
              } else {
                conflict.setDate(conflict.getDate() + "<br>" + date);
              }
              lastDate = date;

              String time =
                  mm.getDays(CONSTANTS.days(), CONSTANTS.shortDays())
                      + " "
                      + (mm.getMeetings().first().isAllDay()
                          ? "All Day"
                          : mm.getMeetings().first().startTime()
                              + " - "
                              + mm.getMeetings().first().stopTime());
              if (lastTime == null) {
                conflict.setTime(time);
              } else if (lastTime.equals(time)) {
                conflict.setTime(conflict.getTime() + "<br>");
              } else {
                conflict.setTime(conflict.getTime() + "<br>" + time);
              }
              lastTime = time;

              String room =
                  (mm.getMeetings().first().getLocation() == null
                      ? ""
                      : mm.getMeetings().first().getLocation().getLabel());
              if (lastRoom == null) {
                conflict.setRoom(room);
              } else if (lastRoom.equals(room)) {
                conflict.setRoom(conflict.getRoom() + "<br>");
              } else {
                conflict.setRoom(conflict.getRoom() + "<br>" + room);
              }
              lastRoom = room;
            }
            enrl.addConflict(conflict);
          }
        }

        converted.add(enrl);
      }
      ClassAssignmentInterface.ClassAssignment c = enrl.getCourse().addClassAssignment();
      c.setClassId(enrollment.getClazz().getUniqueId());
      c.setSection(enrollment.getClazz().getClassSuffix(enrollment.getCourseOffering()));
      if (c.getSection() == null) c.setSection(enrollment.getClazz().getSectionNumberString());
      c.setClassNumber(enrollment.getClazz().getSectionNumberString());
      c.setSubpart(enrollment.getClazz().getSchedulingSubpart().getItypeDesc());
    }
    return converted;
  }
  public List<EnrollmentRequest> check(
      OnlineSectioningServer server, OnlineSectioningHelper helper) {
    XStudent student = server.getStudent(getStudentId());
    if (student == null) throw new SectioningException(MSG.exceptionBadStudentId());
    List<EnrollmentRequest> requests = new ArrayList<EnrollmentRequest>();
    Hashtable<Long, EnrollmentRequest> courseId2request = new Hashtable<Long, EnrollmentRequest>();
    Hashtable<Long, XOffering> courseId2offering = new Hashtable<Long, XOffering>();
    for (ClassAssignmentInterface.ClassAssignment ca : getAssignment()) {
      // Skip free times and dummy sections
      if (ca == null || ca.isFreeTime() || ca.getClassId() == null || ca.isDummy()) continue;

      XCourse course = server.getCourse(ca.getCourseId());
      if (course == null)
        throw new SectioningException(
            MSG.exceptionCourseDoesNotExist(MSG.courseName(ca.getSubject(), ca.getClassNumber())));
      XOffering offering = server.getOffering(course.getOfferingId());
      if (offering == null)
        throw new SectioningException(
            MSG.exceptionCourseDoesNotExist(MSG.courseName(ca.getSubject(), ca.getClassNumber())));

      // Check section limits
      XSection section = offering.getSection(ca.getClassId());
      if (section == null)
        throw new SectioningException(
            MSG.exceptionEnrollNotAvailable(
                MSG.clazz(ca.getSubject(), ca.getCourseNbr(), ca.getSubpart(), ca.getSection())));

      // Check cancelled flag
      if (section.isCancelled()) {
        if (server.getConfig().getPropertyBoolean("Enrollment.CanKeepCancelledClass", false)) {
          boolean contains = false;
          for (XRequest r : student.getRequests())
            if (r instanceof XCourseRequest) {
              XCourseRequest cr = (XCourseRequest) r;
              if (cr.getEnrollment() != null
                  && cr.getEnrollment().getSectionIds().contains(section.getSectionId())) {
                contains = true;
                break;
              }
            }
          if (!contains)
            throw new SectioningException(
                MSG.exceptionEnrollCancelled(
                    MSG.clazz(
                        ca.getSubject(), ca.getCourseNbr(), ca.getSubpart(), ca.getSection())));
        } else {
          throw new SectioningException(
              MSG.exceptionEnrollCancelled(
                  MSG.clazz(ca.getSubject(), ca.getCourseNbr(), ca.getSubpart(), ca.getSection())));
        }
      }

      EnrollmentRequest request = courseId2request.get(ca.getCourseId());
      if (request == null) {
        request = new EnrollmentRequest(course, new ArrayList<XSection>());
        courseId2request.put(ca.getCourseId(), request);
        requests.add(request);
      }
      request.getSections().add(section);
      courseId2offering.put(course.getCourseId(), offering);
    }

    // Check for NEW and CHANGE deadlines
    check:
    for (EnrollmentRequest request : requests) {
      XCourse course = request.getCourse();
      List<XSection> sections = request.getSections();

      for (XRequest r : student.getRequests()) {
        if (r instanceof XCourseRequest) {
          XEnrollment enrollment = ((XCourseRequest) r).getEnrollment();
          if (enrollment != null
              && enrollment.getCourseId().equals(course.getCourseId())) { // course change
            for (XSection s : sections)
              if (!enrollment.getSectionIds().contains(s.getSectionId())
                  && !server.checkDeadline(
                      course.getCourseId(), s.getTime(), OnlineSectioningServer.Deadline.CHANGE))
                throw new SectioningException(
                    MSG.exceptionEnrollDeadlineChange(
                        MSG.clazz(
                            course.getSubjectArea(),
                            course.getCourseNumber(),
                            s.getSubpartName(),
                            s.getName(course.getCourseId()))));
            continue check;
          }
        }
      }

      // new course
      for (XSection section : sections) {
        if (!server.checkDeadline(
            course.getOfferingId(), section.getTime(), OnlineSectioningServer.Deadline.NEW))
          throw new SectioningException(
              MSG.exceptionEnrollDeadlineNew(
                  MSG.clazz(
                      course.getSubjectArea(),
                      course.getCourseNumber(),
                      section.getSubpartName(),
                      section.getName(course.getCourseId()))));
      }
    }

    // Check for DROP deadlines
    for (XRequest r : student.getRequests()) {
      if (r instanceof XCourseRequest) {
        XEnrollment enrollment = ((XCourseRequest) r).getEnrollment();
        if (enrollment != null && !courseId2offering.containsKey(enrollment.getCourseId())) {
          XOffering offering = server.getOffering(enrollment.getOfferingId());
          if (offering != null)
            for (XSection section : offering.getSections(enrollment)) {
              if (!server.checkDeadline(
                  offering.getOfferingId(),
                  section.getTime(),
                  OnlineSectioningServer.Deadline.DROP))
                throw new SectioningException(
                    MSG.exceptionEnrollDeadlineDrop(enrollment.getCourseName()));
            }
        }
      }
    }

    Hashtable<Long, XConfig> courseId2config = new Hashtable<Long, XConfig>();
    for (EnrollmentRequest request : requests) {
      XCourse course = request.getCourse();
      XOffering offering = courseId2offering.get(course.getCourseId());
      XEnrollments enrollments = server.getEnrollments(course.getOfferingId());
      List<XSection> sections = request.getSections();
      XSubpart subpart = offering.getSubpart(sections.get(0).getSubpartId());
      XConfig config = offering.getConfig(subpart.getConfigId());
      courseId2config.put(course.getCourseId(), config);

      XReservation reservation = null;
      reservations:
      for (XReservation r : offering.getReservations()) {
        if (!r.isApplicable(student)) continue;
        if (r.getLimit() >= 0
            && r.getLimit() <= enrollments.countEnrollmentsForReservation(r.getReservationId())) {
          boolean contain = false;
          for (XEnrollment e : enrollments.getEnrollmentsForReservation(r.getReservationId()))
            if (e.getStudentId().equals(student.getStudentId())) {
              contain = true;
              break;
            }
          if (!contain) continue;
        }
        if (!r.getConfigsIds().isEmpty() && !r.getConfigsIds().contains(config.getConfigId()))
          continue;
        for (XSection section : sections)
          if (r.getSectionIds(section.getSubpartId()) != null
              && !r.getSectionIds(section.getSubpartId()).contains(section.getSectionId()))
            continue reservations;
        if (reservation == null || r.compareTo(reservation) < 0) reservation = r;
      }

      if (reservation == null || !reservation.canAssignOverLimit()) {
        for (XSection section : sections) {
          if (section.getLimit() >= 0
              && section.getLimit()
                  <= enrollments.countEnrollmentsForSection(section.getSectionId())) {
            boolean contain = false;
            for (XEnrollment e : enrollments.getEnrollmentsForSection(section.getSectionId()))
              if (e.getStudentId().equals(student.getStudentId())) {
                contain = true;
                break;
              }
            if (!contain)
              throw new SectioningException(
                  MSG.exceptionEnrollNotAvailable(
                      MSG.clazz(
                          course.getSubjectArea(),
                          course.getCourseNumber(),
                          section.getSubpartName(),
                          section.getName())));
          }
          if ((reservation == null
                  || !offering.getSectionReservations(section.getSectionId()).contains(reservation))
              && offering.getUnreservedSectionSpace(section.getSectionId(), enrollments) <= 0) {
            boolean contain = false;
            for (XEnrollment e : enrollments.getEnrollmentsForSection(section.getSectionId()))
              if (e.getStudentId().equals(student.getStudentId())) {
                contain = true;
                break;
              }
            if (!contain)
              throw new SectioningException(
                  MSG.exceptionEnrollNotAvailable(
                      MSG.clazz(
                          course.getSubjectArea(),
                          course.getCourseNumber(),
                          section.getSubpartName(),
                          section.getName())));
          }
        }

        if (config.getLimit() >= 0
            && config.getLimit() <= enrollments.countEnrollmentsForConfig(config.getConfigId())) {
          boolean contain = false;
          for (XEnrollment e : enrollments.getEnrollmentsForConfig(config.getConfigId()))
            if (e.getStudentId().equals(student.getStudentId())) {
              contain = true;
              break;
            }
          if (!contain)
            throw new SectioningException(
                MSG.exceptionEnrollNotAvailable(
                        MSG.courseName(course.getSubjectArea(), course.getCourseNumber()))
                    + " "
                    + config.getName());
        }
        if ((reservation == null
                || !offering.getConfigReservations(config.getConfigId()).contains(reservation))
            && offering.getUnreservedConfigSpace(config.getConfigId(), enrollments) <= 0) {
          boolean contain = false;
          for (XEnrollment e : enrollments.getEnrollmentsForConfig(config.getConfigId()))
            if (e.getStudentId().equals(student.getStudentId())) {
              contain = true;
              break;
            }
          if (!contain)
            throw new SectioningException(
                MSG.exceptionEnrollNotAvailable(
                        MSG.courseName(course.getSubjectArea(), course.getCourseNumber()))
                    + " "
                    + config.getName());
        }

        if (course.getLimit() >= 0
            && course.getLimit() <= enrollments.countEnrollmentsForCourse(course.getCourseId())) {
          boolean contain = false;
          for (XEnrollment e : enrollments.getEnrollmentsForCourse(course.getCourseId()))
            if (e.getStudentId().equals(student.getStudentId())) {
              contain = true;
              break;
            }
          if (!contain)
            throw new SectioningException(
                MSG.exceptionEnrollNotAvailable(
                    MSG.courseName(course.getSubjectArea(), course.getCourseNumber())));
        }
      }
    }

    for (EnrollmentRequest request : requests) {
      XCourse course = request.getCourse();
      XOffering offering = courseId2offering.get(course.getCourseId());
      List<XSection> sections = request.getSections();
      XSubpart subpart = offering.getSubpart(sections.get(0).getSubpartId());
      XConfig config = offering.getConfig(subpart.getConfigId());
      if (sections.size() < config.getSubparts().size()) {
        throw new SectioningException(
            MSG.exceptionEnrollmentIncomplete(
                MSG.courseName(course.getSubjectArea(), course.getCourseNumber())));
      } else if (sections.size() > config.getSubparts().size()) {
        throw new SectioningException(
            MSG.exceptionEnrollmentInvalid(
                MSG.courseName(course.getSubjectArea(), course.getCourseNumber())));
      }
      for (XSection s1 : sections) {
        for (XSection s2 : sections) {
          if (s1.getSectionId() < s2.getSectionId()
              && s1.isOverlapping(offering.getDistributions(), s2)) {
            throw new SectioningException(
                MSG.exceptionEnrollmentOverlapping(
                    MSG.courseName(course.getSubjectArea(), course.getCourseNumber())));
          }
          if (!s1.getSectionId().equals(s2.getSectionId())
              && s1.getSubpartId().equals(s2.getSubpartId())) {
            throw new SectioningException(
                MSG.exceptionEnrollmentInvalid(
                    MSG.courseName(course.getSubjectArea(), course.getCourseNumber())));
          }
        }
        if (!offering.getSubpart(s1.getSubpartId()).getConfigId().equals(config.getConfigId())) {
          throw new SectioningException(
              MSG.exceptionEnrollmentInvalid(
                  MSG.courseName(course.getSubjectArea(), course.getCourseNumber())));
        }
      }
      if (!offering.isAllowOverlap(student, config.getConfigId(), sections))
        for (EnrollmentRequest otherRequest : requests) {
          XOffering other = courseId2offering.get(otherRequest.getCourse().getCourseId());
          XConfig otherConfig = courseId2config.get(otherRequest.getCourse().getCourseId());
          if (!other.equals(offering)
              && !other.isAllowOverlap(
                  student, otherConfig.getConfigId(), otherRequest.getSections())) {
            List<XSection> assignment = otherRequest.getSections();
            for (XSection section : sections)
              if (section.isOverlapping(offering.getDistributions(), assignment))
                throw new SectioningException(
                    MSG.exceptionEnrollmentConflicting(
                        MSG.courseName(course.getSubjectArea(), course.getCourseNumber())));
          }
        }
    }

    return requests;
  }