public static void main(String args[]) {
    long start = System.currentTimeMillis();
    RegistSchedulerImproved scheduler;
    String prefix = "../regist-data/data/";
    RegistOffering offering = new RegistOffering(prefix + "CLASSES-SAMPLE");
    RegistWriteInSource wis = new RegistWriteInSource(prefix + "WRITEIN-SAMPLE");

    wis.load();
    offering.load();

    scheduler = new RegistSchedulerImproved(offering, wis.getWriteIns());
    scheduler.assign();
    long stop = System.currentTimeMillis();
    System.out.println("TimeMillis: " + (stop - start));

    Set studs = scheduler.getStudents();
    int randStud = new Random().nextInt(studs.size());
    String stdNum = (String) studs.toArray()[randStud];

    RegistScheduleExporter exporter =
        new RegistScheduleExporter(scheduler, prefix + "FORM5-SAMPLE", "2004", "SECOND");
    exporter.export();

    Statistics stat = new Statistics(scheduler);
    stat.display();

    // scheduler.validate();

    System.out.println("PL(" + stdNum + ") :" + stat.getPercentageLoad(stdNum));
    Iterator ite = scheduler.getSchedule(stdNum).getSections().iterator();
    while (ite.hasNext()) {
      Section s = (Section) ite.next();
      System.out.println(s.getSubject().getName() + " " + s.getSectionName());
    }
  }
  /**
   * Enlist
   *
   * @param studentWI
   * @param subject
   */
  private void enlist(WriteIn studentWI, String subject) {
    // Get the schedule of the student
    Schedule sked = (Schedule) schedules.get(studentWI.getStudentNumber());

    /* guard to make sure units must not exceed allowed
     */
    ISubject temp = studentWI.getSubjectInfo(subject);
    int unt = temp.getUnitCredit() + sked.getUnitsObtained();
    if (unt > studentWI.getUnitsAllowed()) {
      return;
    }

    List lectures = offering.getLecSections(subject);

    // Collections.shuffle(lectures);
    rankLectureSections(lectures);

    // less slots first?
    // Collections.reverse(lectures);

    // For each lec section
    for (Iterator ite6 = lectures.iterator(); ite6.hasNext(); ) {
      Section lab = null;
      SectionAssignment sectAss = new SectionAssignment();
      Section lecture = (Section) ite6.next();

      // Create a classlist of the section if it does
      // not exist yet
      String clkey = lecture.getSubject().getName() + ":" + lecture.getSectionName();
      Classlist cl = (Classlist) classlists.get(clkey);

      if (cl == null) {
        cl = new Classlist(lecture, null);
      }

      // proceed to next section if this section full
      if (cl.full()) {
        continue;
      }

      // Create a sked node for it
      SkedNode lecnode = new SkedNode(lecture);

      // temporarily add the lecnode
      sked.addSection(lecnode);

      // proceed to next lecture section
      // since this lecture is in conflict
      // already,
      // there is no need to process its labs
      if (!sked.passed(lecnode)) {
        sked.removeLastSectionAdded();
        continue;
      }

      sectAss.setLecture(lecture);

      // ok the lec node was added, however, it is not
      // a guaranteed slot unless a lab is found

      // now we get the lab sections
      List labs = offering.getLabSections(lecture.getSubject().getName(), lecture.getSectionName());

      boolean labFound = false;

      // this lecture got labs!
      if (labs.size() > 0) {
        // rankLabSections(labs);

        // less slots first?
        // Collections.reverse(labs);

        // try to find a lab
        for (Iterator ite7 = labs.iterator(); ite7.hasNext(); ) {
          lab = (Section) ite7.next();

          // Create a classlist of the section if
          // it does not exist yet
          clkey = lab.getSubject().getName() + ":" + lab.getSectionName();

          cl = (Classlist) classlists.get(clkey);

          if (cl == null) {
            cl = new Classlist(lecture, lab);
          }

          // Create a node for the lab
          SkedNode labNode = new SkedNode(lab);

          // Add it to the sked
          sked.addSection(labNode);

          // Did it satisfy the constraint?
          if (!sked.passed(labNode)) {
            // remove this lab section from sked
            sked.removeLastSectionAdded();
          } else {
            if (cl.addStudent(studentWI.getStudentNumber())) {
              sectAss.setLab(lab);
              sked.addSectionAssignment(sectAss);
              classlists.put(clkey, cl);
              // We found a lab! great
              labFound = true;
              break;
            } else {
              sked.removeLastSectionAdded();
            }
          }
        }
        // got one
        if (labFound == true) {
          break;
        } else {
          // remove the lecture node
          sked.removeLastSectionAdded();
        }
      } else {
        if (cl.addStudent(studentWI.getStudentNumber())) {
          sked.addSectionAssignment(sectAss);
          classlists.put(clkey, cl);
          if (studentWI.getStudentNumber().equals(stdNum)) {
            log(2, "\t\t\t\tEnlisted!");
          }
        } else {
          if (studentWI.getStudentNumber().equals(stdNum)) {
            log(2, "\t\t\t\tSection is full!");
          }
          sked.removeLastSectionAdded();
          sked.removeLastSectionAdded();
        }
        break;
      }
    }
  }
  /**
   * Ranked students
   *
   * @param subject
   * @return
   */
  public Map getRankedStudents(String subject) {
    log(3, "Obtaining students interested in subject and sorting based on priority.");
    Vector students = (Vector) demandMap.get(subject);
    Map returnMap = new Hashtable();

    Map priorityMap = new Hashtable();

    for (Iterator ite1 = students.iterator(); ite1.hasNext(); ) {
      WriteIn wri = (WriteIn) ite1.next();
      Float priority = new Float(wri.getPriority());
      List samePriorityList = (List) priorityMap.get(priority);
      if (samePriorityList == null) samePriorityList = new Vector();
      samePriorityList.add(wri);
      priorityMap.put(priority, samePriorityList);
    }

    // TODO: sort the students on the same rank based on the number of
    // options available
    //

    for (Iterator ite2 = priorityMap.keySet().iterator(); ite2.hasNext(); ) { // for each rank
      Map sameRankMap = new Hashtable();
      Float studentRank = (Float) ite2.next();
      // logger.info(rank);
      List sameRankedStudents = (List) priorityMap.get(studentRank);

      for (Iterator ite3 = sameRankedStudents.iterator();
          ite3.hasNext(); ) { // for each student on the same rank
        WriteIn studentWI = (WriteIn) ite3.next();
        // Get the schedule of the student
        Schedule sked = (Schedule) schedules.get(studentWI.getStudentNumber());

        // Get the lec sections for the subject
        List lectures = offering.getLecSections(subject);

        // Get the lecture sections to count the number of options
        float numOptions = 0;
        float totalNumOptions = 0;
        Classlist cl;
        String clkey;

        for (Iterator ite4 = lectures.iterator(); ite4.hasNext(); ) {
          totalNumOptions++;
          Section lecture = (Section) ite4.next();
          // Passed constraints
          if (sked.passed(lecture)) {
            // Count as option only if section is not full
            clkey = lecture.getSubject().getName() + ":" + lecture.getSectionName();
            cl = (Classlist) classlists.get(clkey);
            if (cl == null) {
              cl = new Classlist(lecture, null);
            }

            // Get the lab if any
            List labs = offering.getLabSections(subject, lecture.getSectionName());
            if (labs.size() > 0) {
              totalNumOptions++;
              for (Iterator ite5 = labs.iterator(); ite5.hasNext(); ) {
                Section lab = (Section) ite5.next();
                if (sked.passed(lab)) {
                  // Create a classlist of the section if it
                  // does not exist yet
                  clkey = lab.getSubject().getName() + ":" + lab.getSectionName();
                  cl = (Classlist) classlists.get(clkey);
                  if (cl == null) {
                    cl = new Classlist(lecture, lab);
                  }
                  classlists.put(clkey, cl);
                  if (!cl.full()) {
                    numOptions++;
                  }
                }
              }
            } else {
              classlists.put(clkey, cl);
              if (!cl.full()) {
                numOptions++;
              }
            }
          }
        }

        float currentLoad = sked.getUnitsObtained();
        float allowed = studentWI.getUnitsAllowed();
        float percentageLoad = currentLoad / allowed;

        float percentageNumOptions = numOptions / totalNumOptions;

        ISubject subji = studentWI.getSubjectInfo(subject);
        float subjectPriority =
            (studentWI.getSubjectPriority(subji) - 1) / studentWI.getSubjects().size();

        Float key =
            new Float(
                percentageNumOptions * 0.0 + percentageLoad * 0.0 + (1 - subjectPriority) * 1.0);

        // key is based on the priority of the subject in the writein

        List tmpL = (List) sameRankMap.get(key);
        if (tmpL == null) {
          tmpL = new Vector();
        }
        studentWI.setOptionCount(numOptions);
        tmpL.add(studentWI);
        sameRankMap.put(key, tmpL);
      }

      returnMap.put(studentRank, sameRankMap);
    }

    return returnMap;
  }