/**
   * This method should be used by admin only since the previous searching does not restrict the
   * visibility according to the logged-in user's google ID. Therefore,This fromResults method does
   * not require a googleID as a parameter. Returned results bundle will contain information related
   * to matched instructors only.
   *
   * @param results
   * @return studentResultBundle containing information related to matched students only.
   */
  public InstructorSearchResultBundle getInstructorsfromResults(Results<ScoredDocument> results) {
    if (results == null) {
      return this;
    }

    cursor = results.getCursor();

    for (ScoredDocument doc : results) {
      InstructorAttributes instructor =
          JsonUtils.fromJson(
              doc.getOnlyField(Const.SearchDocumentField.INSTRUCTOR_ATTRIBUTE).getText(),
              InstructorAttributes.class);

      if (instructorsLogic.getInstructorForRegistrationKey(StringHelper.encrypt(instructor.key))
          == null) {
        instructorsLogic.deleteDocument(instructor);
        continue;
      }

      instructorList.add(instructor);
      numberOfResults++;
    }

    sortInstructorResultList();

    return this;
  }
  public void testGetCourseSummariesForInstructor() throws Exception {

    ______TS("Instructor with 2 courses");

    InstructorAttributes instructor = dataBundle.instructors.get("instructor3OfCourse1");
    HashMap<String, CourseDetailsBundle> courseList =
        coursesLogic.getCourseSummariesForInstructor(instructor.googleId);
    assertEquals(2, courseList.size());
    for (CourseDetailsBundle cdd : courseList.values()) {
      // check if course belongs to this instructor
      assertTrue(
          InstructorsLogic.inst()
              .isGoogleIdOfInstructorOfCourse(instructor.googleId, cdd.course.id));
    }

    ______TS("Instructor with 0 courses");
    courseList = coursesLogic.getCourseSummariesForInstructor("instructorWithoutCourses");
    assertEquals(0, courseList.size());

    ______TS("Non-existent instructor");

    try {
      coursesLogic.getCourseSummariesForInstructor("non-existent-instructor");
      signalFailureToDetectException();
    } catch (EntityDoesNotExistException e) {
      AssertHelper.assertContains("does not exist", e.getMessage());
    }

    ______TS("Null parameter");

    try {
      coursesLogic.getCourseSummariesForInstructor(null);
      signalFailureToDetectException();
    } catch (AssertionError e) {
      assertEquals("Supplied parameter was null\n", e.getMessage());
    }
  }
  @Test
  public void testExecuteAndPostProcess() throws Exception {
    InstructorsDb instrDb = new InstructorsDb();

    InstructorAttributes instructor = dataBundle.instructors.get("instructor1OfCourse1");
    instructor = instrDb.getInstructorForEmail(instructor.courseId, instructor.email);

    gaeSimulation.loginAsInstructor(instructor.googleId);

    ______TS("not enough parameters");

    verifyAssumptionFailure();

    ______TS("invalid key");

    String[] submissionParams = new String[] {Const.ParamsNames.REGKEY, "invalidKey"};

    InstructorCourseJoinAuthenticatedAction a = getAction(submissionParams);
    RedirectResult r = (RedirectResult) a.executeAndPostProcess();

    assertEquals(
        Const.ActionURIs.INSTRUCTOR_HOME_PAGE
            + "?message=You+have+used+an+invalid+join+link"
            + "%3A+%2Fpage%2FinstructorCourseJoin%3Fregkey%3DinvalidKey"
            + "&error=true&user="******"instructor already registered");

    submissionParams =
        new String[] {Const.ParamsNames.REGKEY, StringHelper.encrypt(instructor.key)};

    a = getAction(submissionParams);
    r = (RedirectResult) a.executeAndPostProcess();

    assertEquals(
        Const.ActionURIs.INSTRUCTOR_HOME_PAGE
            + "?message=idOfInstructor1OfCourse1+has+already+joined+this+course"
            + "&persistencecourse="
            + instructor.courseId
            + "&error=true&user="******"instructor object belongs to another account");

    InstructorAttributes instructor2 = dataBundle.instructors.get("instructor2OfCourse1");
    instructor2 = instrDb.getInstructorForGoogleId(instructor2.courseId, instructor2.googleId);

    submissionParams =
        new String[] {Const.ParamsNames.REGKEY, StringHelper.encrypt(instructor2.key)};

    a = getAction(submissionParams);
    r = (RedirectResult) a.executeAndPostProcess();

    assertEquals(
        Const.ActionURIs.INSTRUCTOR_HOME_PAGE
            + "?message=The+join+link+used+belongs+to+a+different+user"
            + "+whose+Google+ID+is+idOfInst..fCourse1"
            + "+%28only+part+of+the+Google+ID+is+shown+to+protect+privacy%29."
            + "+If+that+Google+ID+is+owned+by+you%2C+please+logout+and"
            + "+re-login+using+that+Google+account.+If+it+doesn%E2%80%99t"
            + "+belong+to+you%2C+please+%3Ca+href%3D%22mailto"
            + "%3Ateammates%40comp.nus.edu.sg%3Fbody%3D"
            + "Your+name%3A%250AYour+course%3A%250AYour+university%3A%22%3E"
            + "contact+us%3C%2Fa%3E+so+that+we+can+investigate."
            + "&persistencecourse="
            + instructor2.courseId
            + "&error=true&user="******"typical case");

    instructor =
        new InstructorAttributes(
            "ICJAAT.instr", instructor.courseId, "New Instructor", "*****@*****.**");
    InstructorsLogic.inst().addInstructor(instructor.courseId, instructor.name, instructor.email);

    AccountAttributes newInstructorAccount =
        new AccountAttributes(instructor.googleId, instructor.name, false, instructor.email, "NUS");
    AccountsLogic.inst().createAccount(newInstructorAccount);

    InstructorAttributes newInstructor =
        instrDb.getInstructorForEmail(instructor.courseId, instructor.email);

    gaeSimulation.loginUser(instructor.googleId);

    submissionParams =
        new String[] {Const.ParamsNames.REGKEY, StringHelper.encrypt(newInstructor.key)};

    a = getAction(submissionParams);
    r = (RedirectResult) a.executeAndPostProcess();

    assertEquals(
        Const.ActionURIs.INSTRUCTOR_HOME_PAGE
            + "?persistencecourse=idOfTypicalCourse1"
            + "&error=false&user=ICJAAT.instr",
        r.getDestinationWithParams());
    assertFalse(r.isError);

    InstructorAttributes retrievedInstructor =
        instrDb.getInstructorForEmail(instructor.courseId, instructor.email);
    assertEquals(instructor.googleId, retrievedInstructor.googleId);
  }
public class InstructorSearchResultBundle extends SearchResultBundle {

  public List<InstructorAttributes> instructorList = new ArrayList<InstructorAttributes>();
  public Cursor cursor;
  private int numberOfResults;
  private InstructorsLogic instructorsLogic = InstructorsLogic.inst();

  /**
   * This method should be used by admin only since the previous searching does not restrict the
   * visibility according to the logged-in user's google ID. Therefore,This fromResults method does
   * not require a googleID as a parameter. Returned results bundle will contain information related
   * to matched instructors only.
   *
   * @param results
   * @return studentResultBundle containing information related to matched students only.
   */
  public InstructorSearchResultBundle getInstructorsfromResults(Results<ScoredDocument> results) {
    if (results == null) {
      return this;
    }

    cursor = results.getCursor();

    for (ScoredDocument doc : results) {
      InstructorAttributes instructor =
          JsonUtils.fromJson(
              doc.getOnlyField(Const.SearchDocumentField.INSTRUCTOR_ATTRIBUTE).getText(),
              InstructorAttributes.class);

      if (instructorsLogic.getInstructorForRegistrationKey(StringHelper.encrypt(instructor.key))
          == null) {
        instructorsLogic.deleteDocument(instructor);
        continue;
      }

      instructorList.add(instructor);
      numberOfResults++;
    }

    sortInstructorResultList();

    return this;
  }

  private void sortInstructorResultList() {

    Collections.sort(
        instructorList,
        new Comparator<InstructorAttributes>() {
          @Override
          public int compare(InstructorAttributes ins1, InstructorAttributes ins2) {
            int compareResult = ins1.courseId.compareTo(ins2.courseId);
            if (compareResult != 0) {
              return compareResult;
            }

            compareResult = ins1.role.compareTo(ins2.role);
            if (compareResult != 0) {
              return compareResult;
            }

            compareResult = ins1.name.compareTo(ins2.name);
            if (compareResult != 0) {
              return compareResult;
            }

            return ins1.email.compareTo(ins2.email);
          }
        });
  }

  @Override
  public int getResultSize() {
    return numberOfResults;
  }
}
  @Test
  public void testExecuteAndPostProcess() throws Exception {
    InstructorAttributes instructor1OfCourse1 = dataBundle.instructors.get("instructor1OfCourse1");
    String instructorId = instructor1OfCourse1.googleId;
    String courseId = instructor1OfCourse1.courseId;
    String adminUserId = "admin.user";

    ______TS("Typical case: add an instructor successfully");

    gaeSimulation.loginAsInstructor(instructorId);

    String newInstructorName = "New Instructor Name";
    String newInstructorEmail = "*****@*****.**";

    String[] submissionParams =
        new String[] {
          Const.ParamsNames.COURSE_ID,
          courseId,
          Const.ParamsNames.INSTRUCTOR_NAME,
          newInstructorName,
          Const.ParamsNames.INSTRUCTOR_EMAIL,
          newInstructorEmail,
          Const.ParamsNames.INSTRUCTOR_ROLE_NAME,
          Const.InstructorPermissionRoleNames.INSTRUCTOR_PERMISSION_ROLE_COOWNER,
          Const.ParamsNames.INSTRUCTOR_DISPLAY_NAME,
          Const.InstructorPermissionRoleNames.INSTRUCTOR_PERMISSION_ROLE_COOWNER,
          Const.ParamsNames.INSTRUCTOR_PERMISSION_MODIFY_COURSE,
          "true",
          Const.ParamsNames.INSTRUCTOR_PERMISSION_MODIFY_INSTRUCTOR,
          "true",
          Const.ParamsNames.INSTRUCTOR_PERMISSION_MODIFY_SESSION,
          "true",
          Const.ParamsNames.INSTRUCTOR_PERMISSION_MODIFY_STUDENT,
          "true"
        };

    Action addAction = getAction(submissionParams);
    RedirectResult redirectResult = (RedirectResult) addAction.executeAndPostProcess();

    assertEquals(Const.ActionURIs.INSTRUCTOR_COURSE_EDIT_PAGE, redirectResult.destination);
    assertFalse(redirectResult.isError);
    assertEquals(
        String.format(
            Const.StatusMessages.COURSE_INSTRUCTOR_ADDED, newInstructorName, newInstructorEmail),
        redirectResult.getStatusMessage());

    assertTrue(instructorsLogic.isEmailOfInstructorOfCourse(newInstructorEmail, courseId));

    InstructorAttributes instructorAdded =
        instructorsLogic.getInstructorForEmail(courseId, newInstructorEmail);
    assertEquals(newInstructorName, instructorAdded.name);
    assertEquals(newInstructorEmail, instructorAdded.email);

    String expectedLogSegment =
        "New instructor (<span class=\"bold\"> "
            + newInstructorEmail
            + "</span>)"
            + " for Course <span class=\"bold\">["
            + courseId
            + "]</span> created.<br>";
    AssertHelper.assertContains(expectedLogSegment, addAction.getLogMessage());

    verifySpecifiedTasksAdded(
        addAction, Const.TaskQueue.INSTRUCTOR_COURSE_JOIN_EMAIL_QUEUE_NAME, 1);

    TaskWrapper taskAdded = addAction.getTaskQueuer().getTasksAdded().get(0);
    Map<String, String[]> paramMap = taskAdded.getParamMap();
    assertEquals(courseId, paramMap.get(ParamsNames.COURSE_ID)[0]);
    assertEquals(instructorAdded.email, paramMap.get(ParamsNames.INSTRUCTOR_EMAIL)[0]);

    ______TS("Error: try to add an existing instructor");

    addAction = getAction(submissionParams);
    redirectResult = (RedirectResult) addAction.executeAndPostProcess();

    AssertHelper.assertContains(
        Const.ActionURIs.INSTRUCTOR_COURSE_EDIT_PAGE, redirectResult.getDestinationWithParams());
    assertTrue(redirectResult.isError);
    assertEquals(Const.StatusMessages.COURSE_INSTRUCTOR_EXISTS, redirectResult.getStatusMessage());

    expectedLogSegment =
        "TEAMMATESLOG|||instructorCourseInstructorAdd|||instructorCourseInstructorAdd"
            + "|||true|||Instructor|||Instructor 1 of Course 1|||idOfInstructor1OfCourse1|||[email protected]"
            + "|||Servlet Action Failure : Trying to create a Instructor that exists: "
            + "idOfTypicalCourse1/[email protected]"
            + "|||/page/instructorCourseInstructorAdd";
    AssertHelper.assertLogMessageEquals(expectedLogSegment, addAction.getLogMessage());

    verifyNoTasksAdded(addAction);

    ______TS("Error: try to add an instructor with invalid email");
    String newInvalidInstructorEmail = "ICIAAT.newInvalidInstructor.email.tmt";
    submissionParams =
        new String[] {
          Const.ParamsNames.COURSE_ID,
          courseId,
          Const.ParamsNames.INSTRUCTOR_NAME,
          newInstructorName,
          Const.ParamsNames.INSTRUCTOR_EMAIL,
          newInvalidInstructorEmail,
          Const.ParamsNames.INSTRUCTOR_ROLE_NAME,
          Const.InstructorPermissionRoleNames.INSTRUCTOR_PERMISSION_ROLE_COOWNER
        };

    addAction = getAction(submissionParams);
    redirectResult = (RedirectResult) addAction.executeAndPostProcess();

    AssertHelper.assertContains(
        Const.ActionURIs.INSTRUCTOR_COURSE_EDIT_PAGE, redirectResult.getDestinationWithParams());
    assertTrue(redirectResult.isError);
    assertEquals(
        getPopulatedErrorMessage(
            FieldValidator.EMAIL_ERROR_MESSAGE,
            newInvalidInstructorEmail,
            FieldValidator.EMAIL_FIELD_NAME,
            FieldValidator.REASON_INCORRECT_FORMAT,
            FieldValidator.EMAIL_MAX_LENGTH),
        redirectResult.getStatusMessage());

    expectedLogSegment =
        "TEAMMATESLOG|||instructorCourseInstructorAdd|||instructorCourseInstructorAdd"
            + "|||true|||Instructor|||Instructor 1 of Course 1|||idOfInstructor1OfCourse1|||[email protected]"
            + "|||Servlet Action Failure : "
            + getPopulatedErrorMessage(
                FieldValidator.EMAIL_ERROR_MESSAGE,
                newInvalidInstructorEmail,
                FieldValidator.EMAIL_FIELD_NAME,
                FieldValidator.REASON_INCORRECT_FORMAT,
                FieldValidator.EMAIL_MAX_LENGTH)
            + "|||/page/instructorCourseInstructorAdd";
    AssertHelper.assertLogMessageEquals(expectedLogSegment, addAction.getLogMessage());

    verifyNoTasksAdded(addAction);

    ______TS("Masquerade mode: add an instructor");

    instructorsLogic.deleteInstructorCascade(courseId, newInstructorEmail);

    gaeSimulation.loginAsAdmin(adminUserId);
    submissionParams =
        new String[] {
          Const.ParamsNames.COURSE_ID,
          courseId,
          Const.ParamsNames.INSTRUCTOR_NAME,
          newInstructorName,
          Const.ParamsNames.INSTRUCTOR_EMAIL,
          newInstructorEmail,
          Const.ParamsNames.INSTRUCTOR_ROLE_NAME,
          Const.InstructorPermissionRoleNames.INSTRUCTOR_PERMISSION_ROLE_COOWNER,
          Const.ParamsNames.INSTRUCTOR_DISPLAY_NAME,
          Const.InstructorPermissionRoleNames.INSTRUCTOR_PERMISSION_ROLE_COOWNER,
          Const.ParamsNames.INSTRUCTOR_PERMISSION_MODIFY_COURSE,
          "true",
          Const.ParamsNames.INSTRUCTOR_PERMISSION_MODIFY_INSTRUCTOR,
          "true",
          Const.ParamsNames.INSTRUCTOR_PERMISSION_MODIFY_SESSION,
          "true",
          Const.ParamsNames.INSTRUCTOR_PERMISSION_MODIFY_STUDENT,
          "true"
        };
    addAction = getAction(addUserIdToParams(instructorId, submissionParams));
    redirectResult = (RedirectResult) addAction.executeAndPostProcess();

    assertEquals(Const.ActionURIs.INSTRUCTOR_COURSE_EDIT_PAGE, redirectResult.destination);
    assertFalse(redirectResult.isError);
    assertEquals(
        String.format(
            Const.StatusMessages.COURSE_INSTRUCTOR_ADDED, newInstructorName, newInstructorEmail),
        redirectResult.getStatusMessage());

    assertTrue(instructorsLogic.isEmailOfInstructorOfCourse(newInstructorEmail, courseId));

    instructorAdded = instructorsLogic.getInstructorForEmail(courseId, newInstructorEmail);
    assertEquals(newInstructorName, instructorAdded.name);
    assertEquals(newInstructorEmail, instructorAdded.email);

    expectedLogSegment =
        "New instructor (<span class=\"bold\"> "
            + newInstructorEmail
            + "</span>)"
            + " for Course <span class=\"bold\">["
            + courseId
            + "]</span> created.<br>";
    AssertHelper.assertContains(expectedLogSegment, addAction.getLogMessage());

    verifySpecifiedTasksAdded(
        addAction, Const.TaskQueue.INSTRUCTOR_COURSE_JOIN_EMAIL_QUEUE_NAME, 1);

    taskAdded = addAction.getTaskQueuer().getTasksAdded().get(0);
    paramMap = taskAdded.getParamMap();
    assertEquals(courseId, paramMap.get(ParamsNames.COURSE_ID)[0]);
    assertEquals(instructorAdded.email, paramMap.get(ParamsNames.INSTRUCTOR_EMAIL)[0]);
  }