public void toPdfTable(
      OutputStream out,
      HttpServletRequest request,
      SessionContext context,
      Collection distPrefs,
      Long examTypeId)
      throws Exception {
    WebTable.setOrder(context, "examDistPrefsTable.ord", request.getParameter("order"), 4);

    PdfWebTable tbl =
        new PdfWebTable(
            4,
            ExamTypeDAO.getInstance().get(examTypeId).getLabel()
                + " Examination Distribution Preferences",
            null,
            new String[] {" Preference ", " Type ", " Exam ", " Class/Course "},
            new String[] {"left", "left", "left", "left"},
            new boolean[] {true, true, true, true});

    int nrPrefs = 0;

    for (Iterator i1 = distPrefs.iterator(); i1.hasNext(); ) {
      DistributionPref dp = (DistributionPref) i1.next();

      if (!context.hasPermission(dp, Right.ExaminationDistributionPreferenceDetail)) continue;

      nrPrefs++;

      String examStr = "";
      String objStr = "";

      for (Iterator i2 = dp.getOrderedSetOfDistributionObjects().iterator(); i2.hasNext(); ) {
        DistributionObject dO = (DistributionObject) i2.next();
        Exam exam = (Exam) dO.getPrefGroup();
        examStr += dO.preferenceText();
        for (Iterator i3 = exam.getOwners().iterator(); i3.hasNext(); ) {
          ExamOwner owner = (ExamOwner) i3.next();
          objStr += owner.getLabel();
          if (i3.hasNext()) {
            examStr += "\n";
            objStr += "\n";
          }
        }
        if (i2.hasNext()) {
          examStr += "\n";
          objStr += "\n";
        }
      }

      String distType = dp.getDistributionType().getLabel();
      String prefLevel = dp.getPrefLevel().getPrefName();

      tbl.addLine(
          null,
          new String[] {prefLevel, distType, examStr, objStr},
          new Comparable[] {null, distType, examStr, objStr});
    }

    if (nrPrefs == 0) tbl.addLine(null, new String[] {"No preferences found", "", "", ""}, null);

    int ord = WebTable.getOrder(context, "examDistPrefsTable.ord");
    ord = (ord > 0 ? 1 : -1) * (1 + Math.abs(ord));

    PdfPTable table = tbl.printPdfTable(ord);

    float width = tbl.getWidth();

    Document doc = new Document(new Rectangle(60f + width, 60f + 1.30f * width), 30, 30, 30, 30);

    PdfWriter iWriter = PdfWriter.getInstance(doc, out);
    iWriter.setPageEvent(new PdfEventHandler());
    doc.open();

    if (tbl.getName() != null) doc.add(new Paragraph(tbl.getName(), PdfFont.getBigFont(true)));

    doc.add(table);

    doc.close();
  }
  public PdfWebTable getTable(
      boolean html, boolean color, ExamReportForm form, Collection<ExamInfo> exams) {
    if (exams == null || exams.isEmpty()) return null;
    boolean timeVertical = RequiredTimeTable.getTimeGridVertical(sessionContext.getUser());
    boolean timeText = RequiredTimeTable.getTimeGridAsText(sessionContext.getUser());

    String nl = (html ? "<br>" : "\n");
    PdfWebTable table =
        new PdfWebTable(
            9,
            "Not-assigned Examinations",
            "unassignedExams.do?ord=%%",
            new String[] {
              (form.getShowSections() ? "Classes / Courses" : "Examination"),
              "Length",
              "Seating" + nl + "Type",
              "Size",
              "Max" + nl + "Rooms",
              "Instructor",
              "Period" + nl + "Preferences",
              "Room" + nl + "Preferences",
              "Distribution" + nl + "Preferences"
            },
            new String[] {
              "left", "right", "center", "right", "right", "left", "left", "left", "left"
            },
            new boolean[] {true, true, true, false, false, true, true, true, true});
    table.setRowStyle("white-space:nowrap");
    try {
      for (ExamInfo exam : exams) {
        String perPref = "", roomPref = "", distPref = "";

        if (html) {
          roomPref += exam.getExam().getEffectivePrefHtmlForPrefType(RoomPref.class);
          if (roomPref.length() > 0) roomPref += nl;
          roomPref += exam.getExam().getEffectivePrefHtmlForPrefType(BuildingPref.class);
          if (roomPref.length() > 0) roomPref += nl;
          roomPref += exam.getExam().getEffectivePrefHtmlForPrefType(RoomFeaturePref.class);
          if (roomPref.length() > 0) roomPref += nl;
          roomPref += exam.getExam().getEffectivePrefHtmlForPrefType(RoomGroupPref.class);
          if (roomPref.endsWith(nl))
            roomPref = roomPref.substring(0, roomPref.length() - nl.length());
          if (timeText) {
            perPref += exam.getExam().getEffectivePrefHtmlForPrefType(ExamPeriodPref.class);
          } else {
            if (exam.getExam().getExamType().getType() == ExamType.sExamTypeMidterm) {
              MidtermPeriodPreferenceModel epx =
                  new MidtermPeriodPreferenceModel(
                      exam.getExam().getSession(), exam.getExam().getExamType());
              epx.load(exam.getExam());
              perPref += epx.toString(true);
            } else {
              PeriodPreferenceModel px =
                  new PeriodPreferenceModel(exam.getExam().getSession(), exam.getExamTypeId());
              px.load(exam.getExam());
              perPref =
                  "<img border='0' src='pattern?v="
                      + (timeVertical ? 1 : 0)
                      + "&x="
                      + exam.getExamId()
                      + "' title='"
                      + px.toString()
                      + "'>";
            }
          }
          distPref += exam.getExam().getEffectivePrefHtmlForPrefType(DistributionPref.class);
        } else {
          for (Iterator j = exam.getExam().effectivePreferences(RoomPref.class).iterator();
              j.hasNext(); ) {
            Preference pref = (Preference) j.next();
            if (roomPref.length() > 0) roomPref += nl;
            roomPref +=
                (color
                        ? "@@COLOR "
                            + PreferenceLevel.prolog2color(pref.getPrefLevel().getPrefProlog())
                            + " "
                        : "")
                    + PreferenceLevel.prolog2abbv(pref.getPrefLevel().getPrefProlog())
                    + " "
                    + pref.preferenceText();
          }
          for (Iterator j = exam.getExam().effectivePreferences(BuildingPref.class).iterator();
              j.hasNext(); ) {
            Preference pref = (Preference) j.next();
            if (roomPref.length() > 0) roomPref += nl;
            roomPref +=
                (color
                        ? "@@COLOR "
                            + PreferenceLevel.prolog2color(pref.getPrefLevel().getPrefProlog())
                            + " "
                        : "")
                    + PreferenceLevel.prolog2abbv(pref.getPrefLevel().getPrefProlog())
                    + " "
                    + pref.preferenceText();
          }
          for (Iterator j = exam.getExam().effectivePreferences(RoomFeaturePref.class).iterator();
              j.hasNext(); ) {
            Preference pref = (Preference) j.next();
            if (roomPref.length() > 0) roomPref += nl;
            roomPref +=
                (color
                        ? "@@COLOR "
                            + PreferenceLevel.prolog2color(pref.getPrefLevel().getPrefProlog())
                            + " "
                        : "")
                    + PreferenceLevel.prolog2abbv(pref.getPrefLevel().getPrefProlog())
                    + " "
                    + pref.preferenceText();
          }
          for (Iterator j = exam.getExam().effectivePreferences(RoomGroupPref.class).iterator();
              j.hasNext(); ) {
            Preference pref = (Preference) j.next();
            if (roomPref.length() > 0) roomPref += nl;
            roomPref +=
                (color
                        ? "@@COLOR "
                            + PreferenceLevel.prolog2color(pref.getPrefLevel().getPrefProlog())
                            + " "
                        : "")
                    + PreferenceLevel.prolog2abbv(pref.getPrefLevel().getPrefProlog())
                    + " "
                    + pref.preferenceText();
          }
          if (ExamType.sExamTypeMidterm == exam.getExamType().getType()) {
            MidtermPeriodPreferenceModel epx =
                new MidtermPeriodPreferenceModel(exam.getExam().getSession(), exam.getExamType());
            epx.load(exam.getExam());
            perPref += epx.toString(false, true);
          } else {
            if (timeText || !color) {
              for (Iterator j =
                      exam.getExam().effectivePreferences(ExamPeriodPref.class).iterator();
                  j.hasNext(); ) {
                Preference pref = (Preference) j.next();
                if (perPref.length() > 0) perPref += nl;
                perPref +=
                    (color
                            ? "@@COLOR "
                                + PreferenceLevel.prolog2color(pref.getPrefLevel().getPrefProlog())
                                + " "
                            : "")
                        + PreferenceLevel.prolog2abbv(pref.getPrefLevel().getPrefProlog())
                        + " "
                        + pref.preferenceText();
              }
            } else {
              PeriodPreferenceModel px =
                  new PeriodPreferenceModel(
                      exam.getExam().getSession(), exam.getExamType().getUniqueId());
              px.load(exam.getExam());
              RequiredTimeTable rtt = new RequiredTimeTable(px);
              Image image = rtt.createBufferedImage(timeVertical);
              if (image != null) {
                table.addImage(exam.getExamId().toString(), image);
                perPref += "@@IMAGE " + exam.getExamId().toString() + " ";
              } else {
                for (Iterator j =
                        exam.getExam().effectivePreferences(ExamPeriodPref.class).iterator();
                    j.hasNext(); ) {
                  Preference pref = (Preference) j.next();
                  if (perPref.length() > 0) perPref += nl;
                  perPref +=
                      (color
                              ? "@@COLOR "
                                  + PreferenceLevel.prolog2color(
                                      pref.getPrefLevel().getPrefProlog())
                                  + " "
                              : "")
                          + PreferenceLevel.prolog2abbv(pref.getPrefLevel().getPrefProlog())
                          + " "
                          + pref.preferenceText();
                }
              }
            }
          }
          for (Iterator j = exam.getExam().effectivePreferences(DistributionPref.class).iterator();
              j.hasNext(); ) {
            DistributionPref pref = (DistributionPref) j.next();
            if (distPref.length() > 0) distPref += nl;
            distPref +=
                (color
                        ? "@@COLOR "
                            + PreferenceLevel.prolog2color(pref.getPrefLevel().getPrefProlog())
                            + " "
                        : "")
                    + PreferenceLevel.prolog2abbv(pref.getPrefLevel().getPrefProlog())
                    + " "
                    + pref.preferenceText(true, true, " (", ", ", ")")
                        .replaceAll("&lt;", "<")
                        .replaceAll("&gt;", ">");
          }
        }

        String instructors = exam.getInstructorName(", ");

        table.addLine(
            "onClick=\"showGwtDialog('Examination Assignment', 'examInfo.do?examId="
                + exam.getExamId()
                + "','900','90%');\"",
            new String[] {
              (html ? "<a name='" + exam.getExamId() + "'>" : "")
                  + (form.getShowSections() ? exam.getSectionName(nl) : exam.getExamName())
                  + (html ? "</a>" : ""),
              String.valueOf(exam.getLength()),
              (Exam.sSeatingTypeNormal == exam.getSeatingType() ? "Normal" : "Exam"),
              String.valueOf(exam.getNrStudents()),
              String.valueOf(exam.getMaxRooms()),
              instructors,
              perPref,
              roomPref,
              distPref
            },
            new Comparable[] {
              exam,
              exam.getLength(),
              exam.getSeatingType(),
              exam.getNrStudents(),
              exam.getMaxRooms(),
              instructors,
              perPref,
              roomPref,
              distPref
            },
            exam.getExamId().toString());
      }
    } catch (Exception e) {
      Debug.error(e);
      table.addLine(new String[] {"<font color='red'>ERROR:" + e.getMessage() + "</font>"}, null);
    }
    return table;
  }
  /**
   * Build a html table with the list representing distribution prefs
   *
   * @param distPrefs
   * @param ordCol
   * @param editable
   * @return
   */
  public String toHtmlTable(
      HttpServletRequest request, SessionContext context, Collection distPrefs, String title)
      throws Exception {

    String backId =
        ("PreferenceGroup".equals(request.getParameter("backType"))
            ? request.getParameter("backId")
            : null);

    WebTable.setOrder(context, "examDistPrefsTable.ord", request.getParameter("order"), 4);

    WebTable tbl =
        new WebTable(
            3,
            title,
            "examDistributionPrefs.do?order=%%",
            new String[] {" Type ", " Exam ", " Class/Course "},
            new String[] {"left", "left", "left"},
            new boolean[] {true, true, true});

    int nrPrefs = 0;

    for (Iterator i1 = distPrefs.iterator(); i1.hasNext(); ) {
      DistributionPref dp = (DistributionPref) i1.next();

      if (!context.hasPermission(dp, Right.ExaminationDistributionPreferenceDetail)) continue;

      boolean prefEditable = context.hasPermission(dp, Right.ExaminationDistributionPreferenceEdit);

      nrPrefs++;

      String examStr = "";
      String objStr = "";

      for (Iterator i2 = dp.getOrderedSetOfDistributionObjects().iterator(); i2.hasNext(); ) {
        DistributionObject dO = (DistributionObject) i2.next();
        Exam exam = (Exam) dO.getPrefGroup();
        examStr += dO.preferenceText();
        for (Iterator i3 = exam.getOwners().iterator(); i3.hasNext(); ) {
          ExamOwner owner = (ExamOwner) i3.next();
          objStr += owner.getLabel();
          if (i3.hasNext()) {
            examStr += "<BR>";
            objStr += "<BR>";
          }
        }
        if (i2.hasNext()) {
          examStr += "<BR>";
          objStr += "<BR>";
        }
      }

      String distType = dp.getDistributionType().getLabel();
      String prefLevel = dp.getPrefLevel().getPrefName();
      String prefColor = dp.getPrefLevel().prefcolor();
      if (PreferenceLevel.sNeutral.equals(dp.getPrefLevel().getPrefProlog())) prefColor = "gray";
      String onClick = null;

      boolean gray = false;

      if (prefEditable) {
        onClick =
            "onClick=\"document.location='examDistributionPrefs.do"
                + "?dp="
                + dp.getUniqueId().toString()
                + "&op=view'\"";
      } // else gray = true;

      boolean back = dp.getUniqueId().toString().equals(backId);

      tbl.addLine(
          onClick,
          new String[] {
            (back ? "<A name=\"back\"</A>" : "")
                + (gray
                    ? "<span style='color:gray;'>"
                    : "<span style='color:"
                        + prefColor
                        + ";font-weight:bold;' title='"
                        + prefLevel
                        + " "
                        + distType
                        + "'>")
                + distType
                + "</span>",
            (gray ? "<span style='color:gray;'>" : "") + examStr + (gray ? "</span>" : ""),
            (gray ? "<span style='color:gray;'>" : "") + objStr + (gray ? "</span>" : "")
          },
          new Comparable[] {distType, examStr, objStr});
    }

    if (nrPrefs == 0) tbl.addLine(null, new String[] {"No preferences found", "", ""}, null);

    return tbl.printTable(WebTable.getOrder(context, "examDistPrefsTable.ord"));
  }