/**
   * Test uploading a "primary" file
   *
   * @throws IOException
   */
  @Test
  public void testUploadPrimary() throws IOException {
    context.turnOffAuthorization();

    Person person = personRepo.findPersonByEmail("*****@*****.**");
    Submission submission = subRepo.createSubmission(person);
    submission.setAssignee(person);
    submission.save();
    File file = getResourceFile("SamplePrimaryDocument.pdf");

    Long id = submission.getId();

    JPA.em().getTransaction().commit();
    JPA.em().clear();
    JPA.em().getTransaction().begin();

    LOGIN();

    String UPDATE_URL = Router.reverse("ViewTab.view").url;

    // Update a primary document
    Map<String, String> params = new HashMap<String, String>();
    params.put("subId", id.toString());
    params.put("uploadType", "primary");
    params.put("addFile", "true");

    Map<String, File> files = new HashMap<String, File>();
    files.put("primaryAttachment", file);

    Response response = POST(UPDATE_URL, params, files);
    assertIsOk(response);

    // Re-upload a primary document
    params = new HashMap<String, String>();
    params.put("subId", id.toString());
    params.put("uploadType", "primary");
    params.put("status_change", "true");
    params.put("addFile", "true");

    files = new HashMap<String, File>();
    files.put("primaryAttachment", file);

    response = POST(UPDATE_URL, params, files);
    assertIsOk(response);

    file.delete();
    // Verify the files were uploaded and archived
    submission = subRepo.findSubmission(id);
    assertEquals("PRIMARY-DOCUMENT.pdf", submission.getPrimaryDocument().getName());
    assertEquals(
        "PRIMARY-DOCUMENT-archived-on-" + JpaAttachmentImpl.dateFormat.format(new Date()) + ".pdf",
        submission.getAttachmentsByType(AttachmentType.ARCHIVED).get(0).getName());
    assertEquals(submission.getState(), stateManager.getState("NeedsCorrection"));

    submission.delete();

    context.restoreAuthorization();
  }
  /** Test uploading an "additonal" file */
  @Test
  public void testUploadAdditonal() {
    context.turnOffAuthorization();

    Person person = personRepo.findPersonByEmail("*****@*****.**");
    Submission submission = subRepo.createSubmission(person);
    submission.setAssignee(person);
    submission.save();

    Long id = submission.getId();

    JPA.em().getTransaction().commit();
    JPA.em().clear();
    JPA.em().getTransaction().begin();

    LOGIN();

    String UPDATE_URL = Router.reverse("ViewTab.view").url;

    Map<String, String> params = new HashMap<String, String>();
    params.put("subId", id.toString());
    params.put("uploadType", "additional");
    params.put("attachmentType", "SUPPLEMENTAL");
    params.put("status_change", "true");
    params.put("addFile", "true");

    Map<String, File> files = new HashMap<String, File>();
    File file = null;

    try {
      file = getResourceFile("SampleSupplementalDocument.doc");
      files.put("additionalAttachment", file);
    } catch (IOException ioe) {
      fail("Test upload file not found.");
    }

    Response response = POST(UPDATE_URL, params, files);
    assertIsOk(response);

    submission = subRepo.findSubmission(id);

    assertNotNull(submission.getSupplementalDocuments().get(0));
    assertEquals(submission.getState(), stateManager.getState("NeedsCorrection"));

    Attachment attachment = submission.getSupplementalDocuments().get(0);

    attachment.delete();
    submission.delete();

    context.restoreAuthorization();
  }
  /** Test that the left column gets refreshed properly. */
  @Test
  public void testRefreshLeftColumn() {
    context.turnOffAuthorization();

    Person person = personRepo.findPersonByEmail("*****@*****.**");
    Submission submission = subRepo.createSubmission(person);
    submission.setDocumentTitle("My Document Title");
    State state = stateManager.getState("InReview");
    submission.setState(state);
    EmbargoType embargo = settingRepo.findAllEmbargoTypes().get(0);
    submission.addEmbargoType(embargo);
    submission.save();
    Long id = submission.getId();

    assertEquals("My Document Title", submission.getDocumentTitle());

    JPA.em().getTransaction().commit();
    JPA.em().clear();
    JPA.em().getTransaction().begin();

    LOGIN();

    String UPDATE_URL = Router.reverse("ViewTab.updateJSON").url;

    Map<String, String> params = new HashMap<String, String>();
    params.put("subId", id.toString());
    params.put("field", "title");
    params.put("value", "This is a new title");

    Response response = POST(UPDATE_URL, params);
    assertIsOk(response);
    assertContentMatch("\"success\": true,", response);

    submission = subRepo.findSubmission(id);

    UPDATE_URL = Router.reverse("ViewTab.refreshLeftColumn").url;

    params.clear();
    params.put("id", id.toString());

    response = POST(UPDATE_URL, params);
    assertIsOk(response);
    assertContentMatch("Document title changed to", response);

    submission.delete();

    context.restoreAuthorization();
  }
  /** Test that an admin can add an action log comment */
  @Test
  public void testAddActionLogComment() {
    context.turnOffAuthorization();

    Person person = personRepo.findPersonByEmail("*****@*****.**");
    Submission submission = subRepo.createSubmission(person);
    submission.setAssignee(person);
    submission.save();

    Long id = submission.getId();
    int numActionLogs = subRepo.findActionLog(submission).size();

    assertEquals(submission.getAssignee().getCurrentEmailAddress(), "*****@*****.**");

    JPA.em().getTransaction().commit();
    JPA.em().clear();
    JPA.em().getTransaction().begin();

    LOGIN();

    String UPDATE_URL = Router.reverse("ViewTab.view").url;

    Map<String, String> params = new HashMap<String, String>();
    params.put("primary_recipients", "Student, Librarians, [email protected]");
    params.put("cc_recipients", "Advisor, [email protected]");
    params.put("subId", id.toString());
    params.put("subject", "The subject");
    params.put("comment", "This is the comment.");
    params.put("visibility", "public");
    params.put("status_change", "true");
    params.put("addActionLogComment", "true");

    Response response = POST(UPDATE_URL, params);
    assertIsOk(response);

    submission = subRepo.findSubmission(id);
    assertTrue(subRepo.findActionLog(submission).size() > numActionLogs);
    assertEquals(
        "Submission status changed to 'Needs Correction'",
        subRepo.findActionLog(submission).get(0).getEntry());
    assertEquals(submission.getState(), stateManager.getState("NeedsCorrection"));

    submission.delete();

    context.restoreAuthorization();
  }
  /** Test that an admin can change the submission status */
  @Test
  public void testChangeSubmissionStatus() {
    context.turnOffAuthorization();

    Person person = personRepo.findPersonByEmail("*****@*****.**");
    Submission submission = subRepo.createSubmission(person);
    State state = stateManager.getState("InReview");
    submission.setState(state);
    submission.save();
    Long id = submission.getId();

    assertEquals(submission.getState().getBeanName(), "InReview");

    JPA.em().getTransaction().commit();
    JPA.em().clear();
    JPA.em().getTransaction().begin();

    LOGIN();

    String UPDATE_URL = Router.reverse("ViewTab.changeSubmissionStatus").url;

    Map<String, String> params = new HashMap<String, String>();
    params.put("id", id.toString());
    params.put("submission-status", "NeedsCorrection");
    params.put("depositLocationId", "1");
    params.put("special_value", "");

    Response response = POST(UPDATE_URL, params);
    assertStatus(302, response);

    submission = subRepo.findSubmission(id);

    assertEquals(submission.getState().getBeanName(), "NeedsCorrection");

    submission.delete();

    context.restoreAuthorization();
  }
  /**
   * This method produces the common part of the query handle the filter search clauses.
   *
   * @param andQuery The existing and-based query
   * @param filter The filter search paramaters.
   * @param submissions Whether this is for submissions or action logs
   */
  public void buildQuery(BooleanQuery andQuery, SearchFilter filter, boolean submissions) {
    QueryParser parser = new QueryParser(indexer.version, "searchText", indexer.standardAnalyzer);

    // Include Submission filter
    if (filter.getIncludedSubmissions().size() > 0) {
      BooleanQuery orQuery = new BooleanQuery();
      for (Submission sub : filter.getIncludedSubmissions()) {
        orQuery.add(
            new TermQuery(new Term("subId", NumericUtils.longToPrefixCoded(sub.getId()))),
            Occur.SHOULD);
      }
      andQuery.add(orQuery, Occur.MUST);
    }

    // Include Log filter
    if (filter.getIncludedActionLogs().size() > 0) {
      BooleanQuery orQuery = new BooleanQuery();
      for (ActionLog log : filter.getIncludedActionLogs()) {
        orQuery.add(
            new TermQuery(new Term("logId", NumericUtils.longToPrefixCoded(log.getId()))),
            Occur.SHOULD);
      }
      andQuery.add(orQuery, Occur.MUST);
    }

    // Exclude Submission filter
    for (Submission sub : filter.getExcludedSubmissions()) {
      andQuery.add(
          new TermQuery(new Term("subId", NumericUtils.longToPrefixCoded(sub.getId()))),
          Occur.MUST_NOT);
    }

    // Exclude Log filter
    for (ActionLog log : filter.getExcludedActionLogs()) {
      andQuery.add(
          new TermQuery(new Term("logId", NumericUtils.longToPrefixCoded(log.getId()))),
          Occur.MUST_NOT);
    }

    // Search Text Filter
    if (filter.getSearchText().size() > 0) {
      BooleanQuery orQuery = new BooleanQuery();
      for (String searchText : filter.getSearchText()) {
        try {
          // First try to interpret it as a complex lucene search string.
          orQuery.add(parser.parse(searchText), Occur.SHOULD);
        } catch (ParseException e) {
          // If that fails just fall back to a term query.
          orQuery.add(new TermQuery(new Term("searchText", searchText)), Occur.SHOULD);
        }
      }
      andQuery.add(orQuery, Occur.MUST);
    }

    // State Filter
    if (filter.getStates().size() > 0) {
      BooleanQuery orQuery = new BooleanQuery();
      for (String stateName : filter.getStates()) {
        State state = stateManager.getState(stateName);
        orQuery.add(new TermQuery(new Term("state", state.getDisplayName())), Occur.SHOULD);
      }
      andQuery.add(orQuery, Occur.MUST);
    }

    // Assignee Filter
    if (filter.getAssignees().size() > 0) {
      BooleanQuery orQuery = new BooleanQuery();
      for (Person assignee : filter.getAssignees()) {

        long assigneeId = 0;
        if (assignee != null) assigneeId = assignee.getId();

        orQuery.add(
            new TermQuery(new Term("searchAssigned", NumericUtils.longToPrefixCoded(assigneeId))),
            Occur.SHOULD);
      }
      andQuery.add(orQuery, Occur.MUST);
    }

    // Embargo Filter
    if (filter.getEmbargoTypes().size() > 0) {
      BooleanQuery orQuery = new BooleanQuery();
      for (EmbargoType embargo : filter.getEmbargoTypes()) {
        orQuery.add(
            new TermQuery(
                new Term("embargo", embargo.getName() + " " + embargo.getGuarantor().name())),
            Occur.SHOULD);
      }
      andQuery.add(orQuery, Occur.MUST);
    }

    // Graduation Semester Filter
    if (filter.getGraduationSemesters().size() > 0) {
      BooleanQuery orQuery = new BooleanQuery();
      for (Semester semester : filter.getGraduationSemesters()) {

        // We can't index it if it dosn't have a date.
        if (semester.year == null) continue;

        Calendar cal = Calendar.getInstance();
        cal.clear();
        cal.set(Calendar.YEAR, semester.year);
        if (semester.month != null) {
          cal.set(Calendar.MONTH, semester.month);
        }
        orQuery.add(
            new TermQuery(
                new Term(
                    "graduationSemester", NumericUtils.longToPrefixCoded(cal.getTimeInMillis()))),
            Occur.SHOULD);
      }
      andQuery.add(orQuery, Occur.MUST);
    }

    // Degree Filter
    if (filter.getDegrees().size() > 0) {
      BooleanQuery orQuery = new BooleanQuery();
      for (String degree : filter.getDegrees()) {
        orQuery.add(new TermQuery(new Term("degree", degree)), Occur.SHOULD);
      }
      andQuery.add(orQuery, Occur.MUST);
    }

    // Department Filter
    if (filter.getDepartments().size() > 0) {
      BooleanQuery orQuery = new BooleanQuery();
      for (String dept : filter.getDepartments()) {
        orQuery.add(new TermQuery(new Term("department", dept)), Occur.SHOULD);
      }
      andQuery.add(orQuery, Occur.MUST);
    }

    // Program Filter
    if (filter.getPrograms().size() > 0) {
      BooleanQuery orQuery = new BooleanQuery();
      for (String program : filter.getPrograms()) {
        orQuery.add(new TermQuery(new Term("program", program)), Occur.SHOULD);
      }
      andQuery.add(orQuery, Occur.MUST);
    }

    // College Filter
    if (filter.getColleges().size() > 0) {
      BooleanQuery orQuery = new BooleanQuery();
      for (String college : filter.getColleges()) {
        orQuery.add(new TermQuery(new Term("college", college)), Occur.SHOULD);
      }
      andQuery.add(orQuery, Occur.MUST);
    }

    // Major Filter
    if (filter.getMajors().size() > 0) {
      BooleanQuery orQuery = new BooleanQuery();
      for (String major : filter.getMajors()) {
        orQuery.add(new TermQuery(new Term("major", major)), Occur.SHOULD);
      }
      andQuery.add(orQuery, Occur.MUST);
    }

    // Document Type Filter
    if (filter.getDocumentTypes().size() > 0) {
      BooleanQuery orQuery = new BooleanQuery();
      for (String docType : filter.getDocumentTypes()) {
        orQuery.add(new TermQuery(new Term("documentType", docType)), Occur.SHOULD);
      }
      andQuery.add(orQuery, Occur.MUST);
    }

    // UMI Release Filter
    if (filter.getUMIRelease() != null) {
      if (filter.getUMIRelease()) {
        andQuery.add(new TermQuery(new Term("umiRelease", "yes")), Occur.MUST);
      } else {
        andQuery.add(new TermQuery(new Term("umiRelease", "no")), Occur.MUST);
      }
    }

    // Date Range Filter
    if (filter.getDateRangeStart() != null || filter.getDateRangeEnd() != null) {

      long startTime = 0;
      if (filter.getDateRangeStart() != null) startTime = filter.getDateRangeStart().getTime();

      long endTime = Long.MAX_VALUE;
      if (filter.getDateRangeEnd() != null) endTime = filter.getDateRangeEnd().getTime();

      if (submissions)
        andQuery.add(
            NumericRangeQuery.newLongRange("submissionDate", startTime, endTime, true, true),
            Occur.MUST);
      else
        andQuery.add(
            NumericRangeQuery.newLongRange("lastEventTime", startTime, endTime, true, true),
            Occur.MUST);
    }
    // Custom Action Filter
    if (filter.getCustomActions().size() > 0) {
      BooleanQuery orQuery = new BooleanQuery();
      for (CustomActionDefinition customAction : filter.getCustomActions()) {
        orQuery.add(new TermQuery(new Term("customAction", customAction.getLabel())), Occur.SHOULD);
      }
      andQuery.add(orQuery, Occur.MUST);
    }
  }