Example #1
0
  private Set<String> populateRecipientEmails(
      String courseId,
      List<StudentAttributes> allStudents,
      CourseRoster roster,
      Map<String, List<StudentAttributes>> teamStudentTable,
      Map<String, List<StudentAttributes>> sectionStudentTable)
      throws EntityDoesNotExistException {
    Set<String> recipientEmailsList = new HashSet<String>();

    List<CommentAttributes> sendingCommentsList =
        commentsDb.getCommentsForSendingState(courseId, CommentSendingState.SENDING);
    populateRecipientEmailsFromPendingComments(
        sendingCommentsList,
        allStudents,
        roster,
        teamStudentTable,
        sectionStudentTable,
        recipientEmailsList);

    List<FeedbackResponseCommentAttributes> sendingResponseCommentsList =
        frcLogic.getFeedbackResponseCommentsForSendingState(courseId, CommentSendingState.SENDING);
    populateRecipientEmailsFromPendingResponseComments(
        sendingResponseCommentsList, allStudents, roster, teamStudentTable, recipientEmailsList);

    return recipientEmailsList;
  }
  public void updateFeedbackResponsesForChangingSection(
      String courseId, String userEmail, String oldSection, String newSection)
      throws EntityDoesNotExistException, InvalidParametersException {

    List<FeedbackResponseAttributes> responsesFromUser =
        getFeedbackResponsesFromGiverForCourse(courseId, userEmail);

    for (FeedbackResponseAttributes response : responsesFromUser) {
      response.giverSection = newSection;
      frDb.updateFeedbackResponse(response);
      frcLogic.updateFeedbackResponseCommentsForResponse(response.getId());
    }

    List<FeedbackResponseAttributes> responsesToUser =
        getFeedbackResponsesForReceiverForCourse(courseId, userEmail);

    for (FeedbackResponseAttributes response : responsesToUser) {
      response.recipientSection = newSection;
      frDb.updateFeedbackResponse(response);
      frcLogic.updateFeedbackResponseCommentsForResponse(response.getId());
    }
  }
  public void updateFeedbackResponseForChangingSection(
      StudentEnrollDetails enrollment, FeedbackResponseAttributes response)
      throws InvalidParametersException, EntityDoesNotExistException {

    FeedbackResponse feedbackResponse = frDb.getFeedbackResponseEntityOptimized(response);
    boolean isGiverSameForResponseAndEnrollment =
        feedbackResponse.getGiverEmail().equals(enrollment.email);
    boolean isReceiverSameForResponseAndEnrollment =
        feedbackResponse.getRecipientEmail().equals(enrollment.email);

    if (isGiverSameForResponseAndEnrollment) {
      feedbackResponse.setGiverSection(enrollment.newSection);
    }

    if (isReceiverSameForResponseAndEnrollment) {
      feedbackResponse.setRecipientSection(enrollment.newSection);
    }

    frDb.commitOutstandingChanges();

    if (isGiverSameForResponseAndEnrollment || isReceiverSameForResponseAndEnrollment) {
      frcLogic.updateFeedbackResponseCommentsForResponse(response.getId());
    }
  }
Example #4
0
/** Handles the logic related to {@link CommentAttributes}. */
public class CommentsLogic {

  private static CommentsLogic instance;

  @SuppressWarnings("unused") // used by test
  private static final Logger log = Utils.getLogger();

  private static final CommentsDb commentsDb = new CommentsDb();

  private static final CoursesLogic coursesLogic = CoursesLogic.inst();
  private static final InstructorsLogic instructorsLogic = InstructorsLogic.inst();
  private static final StudentsLogic studentsLogic = StudentsLogic.inst();
  private static final FeedbackQuestionsLogic fqLogic = FeedbackQuestionsLogic.inst();
  private static final FeedbackResponsesLogic frLogic = FeedbackResponsesLogic.inst();
  private static final FeedbackResponseCommentsLogic frcLogic =
      FeedbackResponseCommentsLogic.inst();

  public static CommentsLogic inst() {
    if (instance == null) {
      instance = new CommentsLogic();
    }
    return instance;
  }

  /** ********** CRUD *********** */
  public CommentAttributes createComment(CommentAttributes comment)
      throws InvalidParametersException, EntityAlreadyExistsException, EntityDoesNotExistException {
    verifyIsCoursePresent(comment.courseId, "create");
    verifyIsInstructorOfCourse(comment.courseId, comment.giverEmail);

    return commentsDb.createEntity(comment);
  }

  public CommentAttributes getComment(Long commentId) {
    return commentsDb.getComment(commentId);
  }

  public List<CommentAttributes> getCommentsForGiver(String courseId, String giverEmail)
      throws EntityDoesNotExistException {
    verifyIsCoursePresent(courseId, "get");
    return commentsDb.getCommentsForGiver(courseId, giverEmail);
  }

  public List<CommentAttributes> getCommentsForReceiver(
      String courseId,
      String giverEmail,
      CommentParticipantType recipientType,
      String receiverEmail)
      throws EntityDoesNotExistException {
    verifyIsCoursePresent(courseId, "get");
    List<CommentAttributes> comments =
        commentsDb.getCommentsForReceiver(courseId, recipientType, receiverEmail);
    Iterator<CommentAttributes> iterator = comments.iterator();
    while (iterator.hasNext()) {
      CommentAttributes c = iterator.next();
      if (!c.giverEmail.equals(giverEmail)) {
        iterator.remove();
      }
    }
    return comments;
  }

  public List<CommentAttributes> getCommentsForReceiver(
      String courseId, CommentParticipantType recipientType, String receiverEmail)
      throws EntityDoesNotExistException {
    verifyIsCoursePresent(courseId, "get");
    return commentsDb.getCommentsForReceiver(courseId, recipientType, receiverEmail);
  }

  public List<CommentAttributes> getCommentsForSendingState(
      String courseId, CommentSendingState sendingState) throws EntityDoesNotExistException {
    verifyIsCoursePresent(courseId, "get");
    return commentsDb.getCommentsForSendingState(courseId, sendingState);
  }

  public void updateCommentsSendingState(
      String courseId, CommentSendingState oldState, CommentSendingState newState)
      throws EntityDoesNotExistException {
    verifyIsCoursePresent(courseId, "clear pending");
    commentsDb.updateComments(courseId, oldState, newState);
  }

  public CommentAttributes updateComment(CommentAttributes comment)
      throws InvalidParametersException, EntityDoesNotExistException {
    verifyIsCoursePresent(comment.courseId, "update");

    return commentsDb.updateComment(comment);
  }

  /**
   * update comment's giver email (assume to be an instructor)
   *
   * @param courseId
   * @param oldInstrEmail
   * @param updatedInstrEmail
   */
  public void updateInstructorEmail(
      String courseId, String oldInstrEmail, String updatedInstrEmail) {
    commentsDb.updateInstructorEmail(courseId, oldInstrEmail, updatedInstrEmail);
  }

  /**
   * update comment's recipient email (assume to be a student)
   *
   * @param courseId
   * @param oldStudentEmail
   * @param updatedStudentEmail
   */
  public void updateStudentEmail(
      String courseId, String oldStudentEmail, String updatedStudentEmail) {
    commentsDb.updateStudentEmail(courseId, oldStudentEmail, updatedStudentEmail);
  }

  public void deleteCommentsForInstructor(String courseId, String instructorEmail) {
    commentsDb.deleteCommentsByInstructorEmail(courseId, instructorEmail);
  }

  public void deleteCommentsForStudent(String courseId, String studentEmail) {
    commentsDb.deleteCommentsByStudentEmail(courseId, studentEmail);
  }

  public void deleteCommentsForTeam(String courseId, String teamName) {
    commentsDb.deleteCommentsForTeam(courseId, teamName);
  }

  public void deleteCommentsForSection(String courseId, String sectionName) {
    commentsDb.deleteCommentsForSection(courseId, sectionName);
  }

  public void deleteCommentsForCourse(String courseId) {
    commentsDb.deleteCommentsForCourse(courseId);
  }

  public void deleteCommentAndDocument(CommentAttributes comment) {
    this.deleteComment(comment);
    this.deleteDocument(comment);
  }

  public void deleteComment(CommentAttributes comment) {
    commentsDb.deleteEntity(comment);
  }

  public void deleteDocument(CommentAttributes comment) {
    commentsDb.deleteDocument(comment);
  }

  public List<CommentAttributes> getCommentDrafts(String giverEmail) {
    return commentsDb.getCommentDrafts(giverEmail);
  }

  /**
   * Create or update document for comment
   *
   * @param comment
   */
  public void putDocument(CommentAttributes comment) {
    commentsDb.putDocument(comment);
  }

  public CommentSearchResultBundle searchComment(
      String queryString, List<InstructorAttributes> instructors, String cursorString) {
    return commentsDb.search(queryString, instructors, cursorString);
  }

  private void verifyIsCoursePresent(String courseId, String action)
      throws EntityDoesNotExistException {
    if (!coursesLogic.isCoursePresent(courseId)) {
      throw new EntityDoesNotExistException(
          "Trying to " + action + " comments for a course that does not exist.");
    }
  }

  private void verifyIsInstructorOfCourse(String courseId, String email)
      throws EntityDoesNotExistException {
    InstructorAttributes instructor = instructorsLogic.getInstructorForEmail(courseId, email);
    if (instructor == null) {
      throw new EntityDoesNotExistException(
          "User " + email + " is not a registered instructor for course " + courseId + ".");
    }
  }

  /** ********** Get Comments For an Instructor *********** */

  /**
   * Get comments visible for the given instructor
   *
   * @param instructor
   * @return list of {@link CommentAttributes}
   * @throws EntityDoesNotExistException when the course doesn't exist
   */
  public List<CommentAttributes> getCommentsForInstructor(InstructorAttributes instructor)
      throws EntityDoesNotExistException {
    verifyIsCoursePresent(instructor.courseId, "get");
    verifyIsInstructorOfCourse(instructor.courseId, instructor.email);
    HashSet<String> commentsVisitedSet = new HashSet<String>();

    // When the given instructor is the comment giver,
    List<CommentAttributes> comments =
        getCommentsForGiverAndStatus(instructor.courseId, instructor.email, CommentStatus.FINAL);
    for (CommentAttributes c : comments) {
      preventAppendingThisCommentAgain(commentsVisitedSet, c);
    }

    // When other giver's comments are visible to the given instructor
    List<CommentAttributes> commentsForOtherInstructor =
        getCommentsForCommentViewer(instructor.courseId, CommentParticipantType.INSTRUCTOR);
    removeNonVisibleCommentsForInstructor(commentsForOtherInstructor, commentsVisitedSet, comments);

    java.util.Collections.sort(comments);

    return comments;
  }

  private void removeNonVisibleCommentsForInstructor(
      List<CommentAttributes> commentsForInstructor,
      HashSet<String> commentsVisitedSet,
      List<CommentAttributes> comments) {
    for (CommentAttributes c : commentsForInstructor) {
      removeGiverAndRecipientNameByVisibilityOptions(c, CommentParticipantType.INSTRUCTOR);
      appendComments(c, comments, commentsVisitedSet);
    }
  }

  private List<CommentAttributes> getCommentsForCommentViewer(
      String courseId, CommentParticipantType commentViewerType)
      throws EntityDoesNotExistException {
    verifyIsCoursePresent(courseId, "get");
    return commentsDb.getCommentsForCommentViewer(courseId, commentViewerType);
  }

  private List<CommentAttributes> getCommentsForGiverAndStatus(
      String courseId, String giverEmail, CommentStatus status) throws EntityDoesNotExistException {
    verifyIsCoursePresent(courseId, "get");
    return commentsDb.getCommentsForGiverAndStatus(courseId, giverEmail, status);
  }

  /** ********** Get Comments For a Student *********** */

  /**
   * Get comments visible to the given student
   *
   * @param student
   * @return list of {@link CommentAttributes}
   * @throws EntityDoesNotExistException when the course doesn't exist
   */
  public List<CommentAttributes> getCommentsForStudent(StudentAttributes student)
      throws EntityDoesNotExistException {
    verifyIsCoursePresent(student.course, "get");
    List<StudentAttributes> teammates =
        studentsLogic.getStudentsForTeam(student.team, student.course);
    List<StudentAttributes> studentsInTheSameSection =
        studentsLogic.getStudentsForSection(student.section, student.course);
    List<String> teammatesEmails = getTeammatesEmails(teammates);
    List<String> sectionStudentsEmails = getSectionStudentsEmails(studentsInTheSameSection);
    List<String> teamsInThisSection = getTeamsForSection(studentsInTheSameSection);

    List<CommentAttributes> comments = new ArrayList<CommentAttributes>();
    HashSet<String> commentsVisitedSet = new HashSet<String>();

    // Get comments sent to the given student
    List<CommentAttributes> commentsForStudent =
        getCommentsForReceiver(student.course, CommentParticipantType.PERSON, student.email);
    removeNonVisibleCommentsForStudent(commentsForStudent, commentsVisitedSet, comments);

    // Get comments visible to the given student's teammates
    List<CommentAttributes> commentsForTeam =
        getCommentsForCommentViewer(student.course, CommentParticipantType.TEAM);
    removeNonVisibleCommentsForTeam(
        commentsForTeam, student, teammatesEmails, commentsVisitedSet, comments);

    // Get comments visible to the given student's section
    List<CommentAttributes> commentsForSection =
        getCommentsForCommentViewer(student.course, CommentParticipantType.SECTION);
    removeNonVisibleCommentsForSection(
        commentsForSection,
        student,
        teammatesEmails,
        sectionStudentsEmails,
        teamsInThisSection,
        commentsVisitedSet,
        comments);

    // Get comments visible to the whole course
    List<CommentAttributes> commentsForCourse =
        getCommentsForCommentViewer(student.course, CommentParticipantType.COURSE);
    removeNonVisibleCommentsForCourse(
        commentsForCourse,
        student,
        teammatesEmails,
        sectionStudentsEmails,
        teamsInThisSection,
        commentsVisitedSet,
        comments);

    java.util.Collections.sort(comments);

    return comments;
  }

  private List<String> getTeamsForSection(List<StudentAttributes> studentsInTheSameSection) {
    List<String> teams = new ArrayList<String>();
    for (StudentAttributes stu : studentsInTheSameSection) {
      teams.add(stu.team);
    }
    return teams;
  }

  private List<String> getSectionStudentsEmails(List<StudentAttributes> studentsInTheSameSection) {
    List<String> sectionStudentsEmails = new ArrayList<String>();
    for (StudentAttributes stu : studentsInTheSameSection) {
      sectionStudentsEmails.add(stu.email);
    }
    return sectionStudentsEmails;
  }

  private List<String> getTeammatesEmails(List<StudentAttributes> teammates) {
    List<String> teammatesEmails = new ArrayList<String>();
    for (StudentAttributes teammate : teammates) {
      teammatesEmails.add(teammate.email);
    }
    return teammatesEmails;
  }

  private void removeNonVisibleCommentsForCourse(
      List<CommentAttributes> commentsForCourse,
      StudentAttributes student,
      List<String> teammates,
      List<String> sectionStudentsEmails,
      List<String> teamsInThisSection,
      HashSet<String> commentsVisitedSet,
      List<CommentAttributes> comments) {
    removeNonVisibleCommentsForSection(
        commentsForCourse,
        student,
        teammates,
        sectionStudentsEmails,
        teamsInThisSection,
        commentsVisitedSet,
        comments);

    for (CommentAttributes c : commentsForCourse) {
      if (c.courseId.equals(student.course)) {
        if (c.recipientType == CommentParticipantType.COURSE) {
          removeGiverNameByVisibilityOptions(c, CommentParticipantType.COURSE);
        } else {
          removeGiverAndRecipientNameByVisibilityOptions(c, CommentParticipantType.COURSE);
        }
        appendComments(c, comments, commentsVisitedSet);
      }
    }
  }

  private void removeNonVisibleCommentsForSection(
      List<CommentAttributes> commentsForSection,
      StudentAttributes student,
      List<String> teammatesEmails,
      List<String> sectionStudentsEmails,
      List<String> teamsInThisSection,
      HashSet<String> commentsVisitedSet,
      List<CommentAttributes> comments) {
    removeNonVisibleCommentsForTeam(
        commentsForSection, student, teammatesEmails, commentsVisitedSet, comments);

    for (CommentAttributes c : commentsForSection) {
      // for teammates
      if (c.recipientType == CommentParticipantType.PERSON
          && isCommentRecipientsWithinGroup(sectionStudentsEmails, c)) {
        if (c.showCommentTo.contains(CommentParticipantType.SECTION)) {
          removeGiverAndRecipientNameByVisibilityOptions(c, CommentParticipantType.SECTION);
          appendComments(c, comments, commentsVisitedSet);
        } else {
          preventAppendingThisCommentAgain(commentsVisitedSet, c);
        }
        // for team
      } else if (c.recipientType == CommentParticipantType.TEAM
          && isCommentRecipientsWithinGroup(teamsInThisSection, c)) {
        if (c.showCommentTo.contains(CommentParticipantType.SECTION)) {
          removeGiverNameByVisibilityOptions(c, CommentParticipantType.SECTION);
          appendComments(c, comments, commentsVisitedSet);
        } else {
          preventAppendingThisCommentAgain(commentsVisitedSet, c);
        }
        // for section
      } else if (c.recipientType == CommentParticipantType.SECTION
          && c.recipients.contains(student.section)) {
        if (c.showCommentTo.contains(CommentParticipantType.SECTION)) {
          removeGiverNameByVisibilityOptions(c, CommentParticipantType.SECTION);
          appendComments(c, comments, commentsVisitedSet);
        } else {
          preventAppendingThisCommentAgain(commentsVisitedSet, c);
        }
      }
    }
  }

  private void removeNonVisibleCommentsForTeam(
      List<CommentAttributes> commentsForTeam,
      StudentAttributes student,
      List<String> teammates,
      HashSet<String> commentsVisitedSet,
      List<CommentAttributes> comments) {
    for (CommentAttributes c : commentsForTeam) {
      // for teammates
      if (c.recipientType == CommentParticipantType.PERSON
          && isCommentRecipientsWithinGroup(teammates, c)) {
        if (c.showCommentTo.contains(CommentParticipantType.TEAM)) {
          removeGiverAndRecipientNameByVisibilityOptions(c, CommentParticipantType.TEAM);
          appendComments(c, comments, commentsVisitedSet);
        } else {
          preventAppendingThisCommentAgain(commentsVisitedSet, c);
        }
        // for team
      } else if (c.recipientType == CommentParticipantType.TEAM
          && c.recipients.contains(Sanitizer.sanitizeForHtml(student.team))) {
        if (c.showCommentTo.contains(CommentParticipantType.TEAM)) {
          removeGiverNameByVisibilityOptions(c, CommentParticipantType.TEAM);
          appendComments(c, comments, commentsVisitedSet);
        } else {
          preventAppendingThisCommentAgain(commentsVisitedSet, c);
        }
      }
    }
  }

  private void removeNonVisibleCommentsForStudent(
      List<CommentAttributes> commentsForStudent,
      HashSet<String> commentsVisitedSet,
      List<CommentAttributes> comments) {
    for (CommentAttributes c : commentsForStudent) {
      if (c.showCommentTo.contains(CommentParticipantType.PERSON)) {
        removeGiverNameByVisibilityOptions(c, CommentParticipantType.PERSON);
        appendComments(c, comments, commentsVisitedSet);
      } else {
        preventAppendingThisCommentAgain(commentsVisitedSet, c);
      }
    }
  }

  private void removeGiverNameByVisibilityOptions(
      CommentAttributes c, CommentParticipantType viewerType) {
    if (!c.showGiverNameTo.contains(viewerType)) {
      c.giverEmail = "Anonymous";
    }
  }

  private void removeGiverAndRecipientNameByVisibilityOptions(
      CommentAttributes c, CommentParticipantType viewerType) {
    removeGiverNameByVisibilityOptions(c, viewerType);
    if (!c.showRecipientNameTo.contains(viewerType)) {
      c.recipients = new HashSet<String>();
      c.recipients.add("Anonymous");
    }
  }

  private void appendComments(
      CommentAttributes c,
      List<CommentAttributes> toThisCommentList,
      HashSet<String> commentsVisitedSet) {
    if (!commentsVisitedSet.contains(c.getCommentId().toString())) {
      toThisCommentList.add(c);
      preventAppendingThisCommentAgain(commentsVisitedSet, c);
    }
  }

  private void preventAppendingThisCommentAgain(
      HashSet<String> commentsVisitedSet, CommentAttributes c) {
    commentsVisitedSet.add(c.getCommentId().toString());
  }

  private boolean isCommentRecipientsWithinGroup(List<String> group, CommentAttributes c) {
    for (String recipient : c.recipients) {
      if (group.contains(recipient)) {
        return true;
      }
    }
    return false;
  }

  /** ********** Send Email For Pending Comments *********** */

  /**
   * Get recipient emails for comments with sending state. When pending comments are cleared,
   * they'll become sending comments.
   *
   * @param courseId
   * @return set of emails for recipients who can see the sending comments
   * @throws EntityDoesNotExistException when the course doesn't exist
   */
  public Set<String> getRecipientEmailsForSendingComments(String courseId)
      throws EntityDoesNotExistException {
    List<StudentAttributes> allStudents = new StudentsDb().getStudentsForCourse(courseId);

    CourseRoster roster =
        new CourseRoster(allStudents, new InstructorsDb().getInstructorsForCourse(courseId));

    Map<String, List<StudentAttributes>> teamStudentTable =
        new HashMap<String, List<StudentAttributes>>();
    Map<String, List<StudentAttributes>> sectionStudentTable =
        new HashMap<String, List<StudentAttributes>>();
    populateTeamSectionStudentTables(allStudents, teamStudentTable, sectionStudentTable);

    Set<String> recipientEmailsList =
        populateRecipientEmails(
            courseId, allStudents, roster, teamStudentTable, sectionStudentTable);

    return recipientEmailsList;
  }

  private Set<String> populateRecipientEmails(
      String courseId,
      List<StudentAttributes> allStudents,
      CourseRoster roster,
      Map<String, List<StudentAttributes>> teamStudentTable,
      Map<String, List<StudentAttributes>> sectionStudentTable)
      throws EntityDoesNotExistException {
    Set<String> recipientEmailsList = new HashSet<String>();

    List<CommentAttributes> sendingCommentsList =
        commentsDb.getCommentsForSendingState(courseId, CommentSendingState.SENDING);
    populateRecipientEmailsFromPendingComments(
        sendingCommentsList,
        allStudents,
        roster,
        teamStudentTable,
        sectionStudentTable,
        recipientEmailsList);

    List<FeedbackResponseCommentAttributes> sendingResponseCommentsList =
        frcLogic.getFeedbackResponseCommentsForSendingState(courseId, CommentSendingState.SENDING);
    populateRecipientEmailsFromPendingResponseComments(
        sendingResponseCommentsList, allStudents, roster, teamStudentTable, recipientEmailsList);

    return recipientEmailsList;
  }

  private void populateTeamSectionStudentTables(
      List<StudentAttributes> allStudents,
      Map<String, List<StudentAttributes>> teamStudentTable,
      Map<String, List<StudentAttributes>> sectionStudentTable) {
    for (StudentAttributes student : allStudents) {
      List<StudentAttributes> teammates = teamStudentTable.get(student.team);
      if (teammates == null) {
        teammates = new ArrayList<StudentAttributes>();
        teamStudentTable.put(student.team, teammates);
      }
      teammates.add(student);
      List<StudentAttributes> studentsInTheSameSection = sectionStudentTable.get(student.section);
      if (studentsInTheSameSection == null) {
        studentsInTheSameSection = new ArrayList<StudentAttributes>();
        sectionStudentTable.put(student.section, studentsInTheSameSection);
      }
      studentsInTheSameSection.add(student);
    }
  }

  /**
   * ********** Send Email For Pending Comments : populate recipients emails from Feedback Response
   * Comments ***********
   */
  private void populateRecipientEmailsFromPendingResponseComments(
      List<FeedbackResponseCommentAttributes> sendingResponseCommentsList,
      List<StudentAttributes> allStudents,
      CourseRoster roster,
      Map<String, List<StudentAttributes>> teamStudentTable,
      Set<String> recipientEmailsList) {

    Map<String, FeedbackQuestionAttributes> feedbackQuestionsTable =
        new HashMap<String, FeedbackQuestionAttributes>();
    Map<String, FeedbackResponseAttributes> feedbackResponsesTable =
        new HashMap<String, FeedbackResponseAttributes>();
    Map<String, Set<String>> responseCommentsAddedTable = new HashMap<String, Set<String>>();

    for (FeedbackResponseCommentAttributes frc : sendingResponseCommentsList) {
      FeedbackQuestionAttributes relatedQuestion = getRelatedQuestion(feedbackQuestionsTable, frc);
      FeedbackResponseAttributes relatedResponse = getRelatedResponse(feedbackResponsesTable, frc);

      if (relatedQuestion != null && relatedResponse != null) {
        populateRecipientEmailsForGiver(
            roster,
            teamStudentTable,
            recipientEmailsList,
            responseCommentsAddedTable,
            frc,
            relatedQuestion,
            relatedResponse);
        populateRecipientEmailsForReceiver(
            roster,
            teamStudentTable,
            recipientEmailsList,
            responseCommentsAddedTable,
            frc,
            relatedResponse);
        populateRecipientEmailsForTeamMember(
            roster,
            teamStudentTable,
            recipientEmailsList,
            responseCommentsAddedTable,
            frc,
            relatedResponse);
        populateRecipientEmailsForAllStudents(
            allStudents, recipientEmailsList, responseCommentsAddedTable, frc);
      }
    }
  }

  private void populateRecipientEmailsForAllStudents(
      List<StudentAttributes> allStudents,
      Set<String> recipientEmailsList,
      Map<String, Set<String>> responseCommentsAddedTable,
      FeedbackResponseCommentAttributes frc) {
    if (frc.isVisibleTo(FeedbackParticipantType.STUDENTS)) {
      for (StudentAttributes student : allStudents) {
        addRecipientEmailsToList(
            responseCommentsAddedTable, recipientEmailsList, frc.getId().toString(), student.email);
      }
    }
  }

  private void populateRecipientEmailsForTeamMember(
      CourseRoster roster,
      Map<String, List<StudentAttributes>> teamStudentTable,
      Set<String> recipientEmailsList,
      Map<String, Set<String>> responseCommentsAddedTable,
      FeedbackResponseCommentAttributes frc,
      FeedbackResponseAttributes relatedResponse) {
    if (frc.isVisibleTo(FeedbackParticipantType.RECEIVER_TEAM_MEMBERS)) {
      StudentAttributes studentOfThisEmail = roster.getStudentForEmail(relatedResponse.recipient);
      if (studentOfThisEmail == null) {
        addRecipientEmailsForTeam(
            teamStudentTable,
            recipientEmailsList,
            responseCommentsAddedTable,
            frc.getId().toString(),
            relatedResponse.recipient);
      } else {
        addRecipientEmailsForTeam(
            teamStudentTable,
            recipientEmailsList,
            responseCommentsAddedTable,
            frc.getId().toString(),
            studentOfThisEmail.team);
      }
    }
  }

  private void populateRecipientEmailsForReceiver(
      CourseRoster roster,
      Map<String, List<StudentAttributes>> teamStudentTable,
      Set<String> recipientEmailsList,
      Map<String, Set<String>> responseCommentsAddedTable,
      FeedbackResponseCommentAttributes frc,
      FeedbackResponseAttributes relatedResponse) {
    if (frc.isVisibleTo(FeedbackParticipantType.RECEIVER)) {
      // recipientEmail is email
      if (roster.getStudentForEmail(relatedResponse.recipient) == null) {
        addRecipientEmailsForTeam(
            teamStudentTable,
            recipientEmailsList,
            responseCommentsAddedTable,
            frc.getId().toString(),
            relatedResponse.recipient);
      } else {
        addRecipientEmailsToList(
            responseCommentsAddedTable,
            recipientEmailsList,
            frc.getId().toString(),
            relatedResponse.recipient);
      }
    }
  }

  private void populateRecipientEmailsForGiver(
      CourseRoster roster,
      Map<String, List<StudentAttributes>> teamStudentTable,
      Set<String> recipientEmailsList,
      Map<String, Set<String>> responseCommentsAddedTable,
      FeedbackResponseCommentAttributes frc,
      FeedbackQuestionAttributes relatedQuestion,
      FeedbackResponseAttributes relatedResponse) {
    StudentAttributes giver = roster.getStudentForEmail(relatedResponse.giver);
    if (giver == null) {
      return;
    }

    if (frc.isVisibleTo(FeedbackParticipantType.GIVER)) {
      addRecipientEmailsToList(
          responseCommentsAddedTable,
          recipientEmailsList,
          frc.getId().toString(),
          relatedResponse.giver);
    }

    if (relatedQuestion.giverType == FeedbackParticipantType.TEAMS
        || frc.isVisibleTo(FeedbackParticipantType.OWN_TEAM_MEMBERS)) {
      addRecipientEmailsForTeam(
          teamStudentTable,
          recipientEmailsList,
          responseCommentsAddedTable,
          frc.getId().toString(),
          giver.team);
    }
  }

  private FeedbackResponseAttributes getRelatedResponse(
      Map<String, FeedbackResponseAttributes> feedbackResponsesTable,
      FeedbackResponseCommentAttributes frc) {
    FeedbackResponseAttributes relatedResponse = feedbackResponsesTable.get(frc.feedbackResponseId);
    if (relatedResponse == null) {
      relatedResponse = frLogic.getFeedbackResponse(frc.feedbackResponseId);
      feedbackResponsesTable.put(frc.feedbackResponseId, relatedResponse);
    }
    return relatedResponse;
  }

  private FeedbackQuestionAttributes getRelatedQuestion(
      Map<String, FeedbackQuestionAttributes> feedbackQuestionsTable,
      FeedbackResponseCommentAttributes frc) {
    FeedbackQuestionAttributes relatedQuestion = feedbackQuestionsTable.get(frc.feedbackQuestionId);
    if (relatedQuestion == null) {
      relatedQuestion = fqLogic.getFeedbackQuestion(frc.feedbackQuestionId);
      feedbackQuestionsTable.put(frc.feedbackQuestionId, relatedQuestion);
    }
    return relatedQuestion;
  }

  /**
   * ********** Send Email For Pending Comments : populate recipients emails from Student Comments
   * ***********
   */
  private void populateRecipientEmailsFromPendingComments(
      List<CommentAttributes> sendingCommentsList,
      List<StudentAttributes> allStudents,
      CourseRoster roster,
      Map<String, List<StudentAttributes>> teamStudentTable,
      Map<String, List<StudentAttributes>> sectionStudentTable,
      Set<String> recipientEmailList) {

    Map<String, Set<String>> studentCommentsAddedTable = new HashMap<String, Set<String>>();

    for (CommentAttributes pendingComment : sendingCommentsList) {
      populateRecipientEmailsForPerson(
          recipientEmailList, studentCommentsAddedTable, pendingComment);
      populateRecipientEmailsForTeam(
          recipientEmailList, roster, teamStudentTable, studentCommentsAddedTable, pendingComment);
      populateRecipientEmailsForSection(
          recipientEmailList,
          roster,
          teamStudentTable,
          sectionStudentTable,
          studentCommentsAddedTable,
          pendingComment);
      populateRecipientEmailsForCourse(
          recipientEmailList, allStudents,
          studentCommentsAddedTable, pendingComment);
    }
  }

  private void populateRecipientEmailsForCourse(
      Set<String> recipientEmailList,
      List<StudentAttributes> allStudents,
      Map<String, Set<String>> studentCommentsAddedTable,
      CommentAttributes pendingComment) {
    if (pendingComment.isVisibleTo(CommentParticipantType.COURSE)) {
      for (StudentAttributes student : allStudents) {
        addRecipientEmailsToList(
            studentCommentsAddedTable,
            recipientEmailList,
            pendingComment.getCommentId().toString(),
            student.email);
      }
    }
  }

  private void populateRecipientEmailsForSection(
      Set<String> recipientEmailList,
      CourseRoster roster,
      Map<String, List<StudentAttributes>> teamStudentTable,
      Map<String, List<StudentAttributes>> sectionStudentTable,
      Map<String, Set<String>> studentCommentsAddedTable,
      CommentAttributes pendingComment) {
    String commentId = pendingComment.getCommentId().toString();
    if (pendingComment.isVisibleTo(CommentParticipantType.SECTION)) {
      if (pendingComment.recipientType == CommentParticipantType.PERSON) {
        for (String recipientEmail : pendingComment.recipients) {
          StudentAttributes student = roster.getStudentForEmail(recipientEmail);
          if (student == null) {
            continue;
          }
          addRecipientEmailsForSection(
              sectionStudentTable,
              recipientEmailList,
              studentCommentsAddedTable,
              commentId,
              student.section);
        }
      } else if (pendingComment.recipientType == CommentParticipantType.TEAM) {
        for (String team : pendingComment.recipients) {
          List<StudentAttributes> students = teamStudentTable.get(team);
          if (students == null) {
            continue;
          }
          for (StudentAttributes stu : students) {
            addRecipientEmailsForSection(
                sectionStudentTable,
                recipientEmailList,
                studentCommentsAddedTable,
                commentId,
                stu.section);
          }
        }
      } else if (pendingComment.recipientType == CommentParticipantType.SECTION) {
        for (String section : pendingComment.recipients) {
          addRecipientEmailsForSection(
              sectionStudentTable,
              recipientEmailList,
              studentCommentsAddedTable,
              commentId,
              section);
        }
      }
    } else { // not visible to SECTION
      if (pendingComment.recipientType == CommentParticipantType.PERSON) {
        for (String recipientEmail : pendingComment.recipients) {
          StudentAttributes student = roster.getStudentForEmail(recipientEmail);
          if (student == null) {
            continue;
          }
          preventAddRecipientEmailsForSection(
              teamStudentTable, studentCommentsAddedTable, commentId, student.section);
        }
      } else if (pendingComment.recipientType == CommentParticipantType.TEAM) {
        for (String team : pendingComment.recipients) {
          List<StudentAttributes> students = teamStudentTable.get(team);
          if (students == null) {
            continue;
          }
          for (StudentAttributes stu : students) {
            preventAddRecipientEmailsForSection(
                teamStudentTable, studentCommentsAddedTable, commentId, stu.section);
          }
        }
      } else if (pendingComment.recipientType == CommentParticipantType.SECTION) {
        for (String section : pendingComment.recipients) {
          preventAddRecipientEmailsForSection(
              teamStudentTable, studentCommentsAddedTable,
              commentId, section);
        }
      }
    }
  }

  private void populateRecipientEmailsForTeam(
      Set<String> recipientEmailList,
      CourseRoster roster,
      Map<String, List<StudentAttributes>> teamStudentTable,
      Map<String, Set<String>> studentCommentsAddedTable,
      CommentAttributes pendingComment) {
    String commentId = pendingComment.getCommentId().toString();
    if (pendingComment.isVisibleTo(CommentParticipantType.TEAM)) {
      if (pendingComment.recipientType == CommentParticipantType.PERSON) {
        for (String recipientEmail : pendingComment.recipients) {
          StudentAttributes student = roster.getStudentForEmail(recipientEmail);
          if (student == null) {
            continue;
          }
          addRecipientEmailsForTeam(
              teamStudentTable,
              recipientEmailList,
              studentCommentsAddedTable,
              commentId,
              student.team);
        }
      } else if (pendingComment.recipientType == CommentParticipantType.TEAM) {
        for (String team : pendingComment.recipients) {
          addRecipientEmailsForTeam(
              teamStudentTable, recipientEmailList, studentCommentsAddedTable, commentId, team);
        }
      }
    } else { // not visible to TEAM
      if (pendingComment.recipientType == CommentParticipantType.PERSON) {
        for (String recipientEmail : pendingComment.recipients) {
          StudentAttributes student = roster.getStudentForEmail(recipientEmail);
          if (student == null) {
            continue;
          }
          preventAddRecipientEmailsForTeam(
              teamStudentTable, studentCommentsAddedTable, commentId, student.team);
        }
      } else if (pendingComment.recipientType == CommentParticipantType.TEAM) {
        for (String team : pendingComment.recipients) {
          preventAddRecipientEmailsForTeam(
              teamStudentTable, studentCommentsAddedTable,
              commentId, team);
        }
      }
    }
  }

  private void populateRecipientEmailsForPerson(
      Set<String> recipientEmailList,
      Map<String, Set<String>> studentCommentsAddedTable,
      CommentAttributes pendingComment) {
    String commentId = pendingComment.getCommentId().toString();
    if (pendingComment.isVisibleTo(CommentParticipantType.PERSON)) {
      for (String recipientEmail : pendingComment.recipients) {
        addRecipientEmailsToList(
            studentCommentsAddedTable, recipientEmailList,
            commentId, recipientEmail);
      }
    } else { // not visible to PERSON
      for (String recipientEmail : pendingComment.recipients) {
        preventAddRecipientEmailsToList(studentCommentsAddedTable, commentId, recipientEmail);
      }
    }
  }

  private void addRecipientEmailsToList(
      Map<String, Set<String>> isAddedTable, Set<String> targetTable, String subKey, String key) {
    // prevent re-entry
    Set<String> commentIdsSet = isAddedTable.get(key);
    if (commentIdsSet == null) {
      commentIdsSet = new HashSet<String>();
      isAddedTable.put(key, commentIdsSet);
    }
    if (!commentIdsSet.contains(subKey)) {
      commentIdsSet.add(subKey);
      targetTable.add(key);
    }
  }

  private void addRecipientEmailsForSection(
      Map<String, List<StudentAttributes>> sectionStudentTable,
      Set<String> recipientEmailsList,
      Map<String, Set<String>> responseCommentsAddedTable,
      String commentId,
      String sectionName) {
    List<StudentAttributes> students = sectionStudentTable.get(sectionName);
    if (students == null) {
      return;
    }

    for (StudentAttributes stu : students) {
      addRecipientEmailsToList(
          responseCommentsAddedTable, recipientEmailsList, commentId, stu.email);
    }
  }

  private void addRecipientEmailsForTeam(
      Map<String, List<StudentAttributes>> teamStudentTable,
      Set<String> recipientEmailsList,
      Map<String, Set<String>> responseCommentsAddedTable,
      String commentId,
      String teamName) {
    List<StudentAttributes> students = teamStudentTable.get(teamName);
    if (students == null) {
      return;
    }

    for (StudentAttributes stu : students) {
      addRecipientEmailsToList(
          responseCommentsAddedTable, recipientEmailsList, commentId, stu.email);
    }
  }

  private void preventAddRecipientEmailsToList(
      Map<String, Set<String>> isAddedTable, String subKey, String key) {
    Set<String> commentIdsSet = isAddedTable.get(key);
    if (commentIdsSet == null) {
      commentIdsSet = new HashSet<String>();
      isAddedTable.put(key, commentIdsSet);
    }
    commentIdsSet.add(subKey);
  }

  private void preventAddRecipientEmailsForSection(
      Map<String, List<StudentAttributes>> sectionStudentTable,
      Map<String, Set<String>> isAddedTable,
      String commentId,
      String section) {
    List<StudentAttributes> students = sectionStudentTable.get(section);
    if (students == null) {
      return;
    }

    for (StudentAttributes stu : students) {
      preventAddRecipientEmailsToList(isAddedTable, commentId, stu.email);
    }
  }

  private void preventAddRecipientEmailsForTeam(
      Map<String, List<StudentAttributes>> teamStudentTable,
      Map<String, Set<String>> isAddedTable,
      String commentId,
      String team) {
    List<StudentAttributes> teammates = teamStudentTable.get(team);
    if (teammates == null) {
      return;
    }

    for (StudentAttributes teamMember : teammates) {
      preventAddRecipientEmailsToList(isAddedTable, commentId, teamMember.email);
    }
  }

  @SuppressWarnings("deprecation")
  public List<CommentAttributes> getAllComments() {
    return commentsDb.getAllComments();
  }

  /**
   * Sends notifications to students in course {@code courseId} who have received comments and not
   * yet been notified.
   */
  public void sendCommentNotification(String courseId) {
    Map<String, String> paramMap = new HashMap<String, String>();
    paramMap.put(Const.ParamsNames.EMAIL_COURSE, courseId);
    paramMap.put(Const.ParamsNames.EMAIL_TYPE, EmailType.PENDING_COMMENT_CLEARED.toString());

    TaskQueuesLogic taskQueueLogic = TaskQueuesLogic.inst();
    taskQueueLogic.createAndAddTask(
        Const.SystemParams.EMAIL_TASK_QUEUE, Const.ActionURIs.EMAIL_WORKER, paramMap);
  }
}
 public void deleteFeedbackResponseAndCascade(FeedbackResponseAttributes responseToDelete) {
   frcLogic.deleteFeedbackResponseCommentsForResponse(responseToDelete.getId());
   frDb.deleteEntity(responseToDelete);
 }
public class FeedbackResponsesLogic {

  private static final Logger log = Utils.getLogger();

  private static FeedbackResponsesLogic instance = null;
  private static final StudentsLogic studentsLogic = StudentsLogic.inst();
  private static final FeedbackQuestionsLogic fqLogic = FeedbackQuestionsLogic.inst();
  private static final FeedbackResponseCommentsLogic frcLogic =
      FeedbackResponseCommentsLogic.inst();
  private static final FeedbackResponsesDb frDb = new FeedbackResponsesDb();

  public static FeedbackResponsesLogic inst() {
    if (instance == null) instance = new FeedbackResponsesLogic();
    return instance;
  }

  public void createFeedbackResponse(FeedbackResponseAttributes fra)
      throws InvalidParametersException {
    try {
      frDb.createEntity(fra);
    } catch (Exception EntityAlreadyExistsException) {
      try {
        FeedbackResponseAttributes existingFeedback = new FeedbackResponseAttributes();

        existingFeedback =
            frDb.getFeedbackResponse(fra.feedbackQuestionId, fra.giverEmail, fra.recipientEmail);
        fra.setId(existingFeedback.getId());

        frDb.updateFeedbackResponse(fra);
      } catch (Exception EntityDoesNotExistException) {
        Assumption.fail();
      }
    }
  }

  public FeedbackResponseAttributes getFeedbackResponse(String feedbackResponseId) {
    return frDb.getFeedbackResponse(feedbackResponseId);
  }

  public FeedbackResponseAttributes getFeedbackResponse(
      String feedbackQuestionId, String giverEmail, String recipient) {
    // TODO: check what is this line doing here!!!
    log.warning(feedbackQuestionId);
    return frDb.getFeedbackResponse(feedbackQuestionId, giverEmail, recipient);
  }

  public List<FeedbackResponseAttributes> getFeedbackResponsesForSession(
      String feedbackSessionName, String courseId) {
    return frDb.getFeedbackResponsesForSession(feedbackSessionName, courseId);
  }

  public List<FeedbackResponseAttributes> getFeedbackResponsesForSessionInSection(
      String feedbackSessionName, String courseId, String section) {
    if (section == null) {
      return getFeedbackResponsesForSession(feedbackSessionName, courseId);
    } else {
      return frDb.getFeedbackResponsesForSessionInSection(feedbackSessionName, courseId, section);
    }
  }

  public List<FeedbackResponseAttributes> getFeedbackResponsesForSessionFromSection(
      String feedbackSessionName, String courseId, String section) {
    if (section == null) {
      return getFeedbackResponsesForSession(feedbackSessionName, courseId);
    } else {
      return frDb.getFeedbackResponsesForSessionFromSection(feedbackSessionName, courseId, section);
    }
  }

  public List<FeedbackResponseAttributes> getFeedbackResponsesForSessionToSection(
      String feedbackSessionName, String courseId, String section) {
    if (section == null) {
      return getFeedbackResponsesForSession(feedbackSessionName, courseId);
    } else {
      return frDb.getFeedbackResponsesForSessionToSection(feedbackSessionName, courseId, section);
    }
  }

  public List<FeedbackResponseAttributes> getFeedbackResponsesForSessionWithinRange(
      String feedbackSessionName, String courseId, long range) {
    return frDb.getFeedbackResponsesForSessionWithinRange(feedbackSessionName, courseId, range);
  }

  public List<FeedbackResponseAttributes> getFeedbackResponsesForSessionInSectionWithinRange(
      String feedbackSessionName, String courseId, String section, long range) {
    if (section == null) {
      return getFeedbackResponsesForSessionWithinRange(feedbackSessionName, courseId, range);
    } else {
      return frDb.getFeedbackResponsesForSessionInSectionWithinRange(
          feedbackSessionName, courseId, section, range);
    }
  }

  public List<FeedbackResponseAttributes> getFeedbackResponsesForSessionFromSectionWithinRange(
      String feedbackSessionName, String courseId, String section, long range) {
    if (section == null) {
      return getFeedbackResponsesForSessionWithinRange(feedbackSessionName, courseId, range);
    } else {
      return frDb.getFeedbackResponsesForSessionFromSectionWithinRange(
          feedbackSessionName, courseId, section, range);
    }
  }

  public List<FeedbackResponseAttributes> getFeedbackResponsesForSessionToSectionWithinRange(
      String feedbackSessionName, String courseId, String section, long range) {
    if (section == null) {
      return getFeedbackResponsesForSessionWithinRange(feedbackSessionName, courseId, range);
    } else {
      return frDb.getFeedbackResponsesForSessionToSectionWithinRange(
          feedbackSessionName, courseId, section, range);
    }
  }

  public List<FeedbackResponseAttributes> getFeedbackResponsesForQuestion(
      String feedbackQuestionId) {
    return frDb.getFeedbackResponsesForQuestion(feedbackQuestionId);
  }

  public List<FeedbackResponseAttributes> getFeedbackResponsesForQuestionWithinRange(
      String feedbackQuestionId, long range) {
    return frDb.getFeedbackResponsesForQuestionWithinRange(feedbackQuestionId, range);
  }

  public List<FeedbackResponseAttributes> getFeedbackResponsesForQuestionInSection(
      String feedbackQuestionId, String section) {
    if (section == null) {
      return getFeedbackResponsesForQuestion(feedbackQuestionId);
    }
    return frDb.getFeedbackResponsesForQuestionInSection(feedbackQuestionId, section);
  }

  public List<FeedbackResponseAttributes> getFeedbackResponsesForReceiverForQuestion(
      String feedbackQuestionId, String userEmail) {
    return frDb.getFeedbackResponsesForReceiverForQuestion(feedbackQuestionId, userEmail);
  }

  public List<FeedbackResponseAttributes> getFeedbackResponsesForReceiverForQuestionInSection(
      String feedbackQuestionId, String userEmail, String section) {

    if (section == null) {
      return getFeedbackResponsesForReceiverForQuestion(feedbackQuestionId, userEmail);
    }
    return frDb.getFeedbackResponsesForReceiverForQuestionInSection(
        feedbackQuestionId, userEmail, section);
  }

  public List<FeedbackResponseAttributes> getFeedbackResponsesFromGiverForQuestion(
      String feedbackQuestionId, String userEmail) {
    return frDb.getFeedbackResponsesFromGiverForQuestion(feedbackQuestionId, userEmail);
  }

  public List<FeedbackResponseAttributes> getFeedbackResponsesFromGiverForQuestionInSection(
      String feedbackQuestionId, String userEmail, String section) {

    if (section == null) {
      return getFeedbackResponsesFromGiverForQuestion(feedbackQuestionId, userEmail);
    }
    return frDb.getFeedbackResponsesFromGiverForQuestionInSection(
        feedbackQuestionId, userEmail, section);
  }

  public List<FeedbackResponseAttributes> getFeedbackResponsesForReceiverForCourse(
      String courseId, String userEmail) {
    return frDb.getFeedbackResponsesForReceiverForCourse(courseId, userEmail);
  }

  public List<FeedbackResponseAttributes> getFeedbackResponsesFromGiverForCourse(
      String courseId, String userEmail) {
    return frDb.getFeedbackResponsesFromGiverForCourse(courseId, userEmail);
  }

  /** Get existing feedback responses from student or his team for the given question. */
  public List<FeedbackResponseAttributes> getFeedbackResponsesFromStudentOrTeamForQuestion(
      FeedbackQuestionAttributes question, StudentAttributes student) {
    if (question.giverType == FeedbackParticipantType.TEAMS) {
      return getFeedbackResponsesFromTeamForQuestion(
          question.getId(), question.courseId, student.team);
    } else {
      return frDb.getFeedbackResponsesFromGiverForQuestion(question.getId(), student.email);
    }
  }

  public List<FeedbackResponseAttributes> getViewableFeedbackResponsesForQuestionInSection(
      FeedbackQuestionAttributes question, String userEmail, UserType.Role role, String section)
      throws EntityDoesNotExistException {

    List<FeedbackResponseAttributes> viewableResponses =
        new ArrayList<FeedbackResponseAttributes>();

    // Add responses that the user submitted himself
    addNewResponses(
        viewableResponses,
        getFeedbackResponsesFromGiverForQuestionInSection(question.getId(), userEmail, section));

    // Add responses that user is a receiver of when question is visible to
    // receiver.
    if (question.isResponseVisibleTo(FeedbackParticipantType.RECEIVER)) {
      addNewResponses(
          viewableResponses,
          getFeedbackResponsesForReceiverForQuestionInSection(
              question.getId(), userEmail, section));
    }

    switch (role) {
      case STUDENT:
        addNewResponses(
            viewableResponses,
            // many queries
            getViewableFeedbackResponsesForStudentForQuestion(question, userEmail));
        break;
      case INSTRUCTOR:
        if (question.isResponseVisibleTo(FeedbackParticipantType.INSTRUCTORS)) {
          addNewResponses(
              viewableResponses,
              getFeedbackResponsesForQuestionInSection(question.getId(), section));
        }
        break;
      default:
        Assumption.fail("The role of the requesting use has to be Student or Instructor");
    }

    return viewableResponses;
  }

  public boolean isNameVisibleTo(
      FeedbackQuestionAttributes question,
      FeedbackResponseAttributes response,
      String userEmail,
      UserType.Role role,
      boolean isGiverName,
      CourseRoster roster) {

    if (question == null) {
      return false;
    }

    List<FeedbackParticipantType> showNameTo =
        isGiverName ? question.showGiverNameTo : question.showRecipientNameTo;

    // Giver can always see giver and recipient.(because he answered.)
    if (response.giverEmail.equals(userEmail)) {
      return true;
    }

    for (FeedbackParticipantType type : showNameTo) {
      switch (type) {
        case INSTRUCTORS:
          if (roster.getInstructorForEmail(userEmail) != null && role == UserType.Role.INSTRUCTOR) {
            return true;
          } else {
            break;
          }
        case OWN_TEAM_MEMBERS:
        case OWN_TEAM_MEMBERS_INCLUDING_SELF:
          // Refers to Giver's Team Members
          if (roster.isStudentsInSameTeam(response.giverEmail, userEmail)) {
            return true;
          } else {
            break;
          }
        case RECEIVER:
          // Response to team
          if (question.recipientType == FeedbackParticipantType.TEAMS) {
            if (roster.isStudentInTeam(
                userEmail, /* this is a team name */ response.recipientEmail)) {
              return true;
            }
            // Response to individual
          } else if (response.recipientEmail.equals(userEmail)) {
            return true;
          } else {
            break;
          }
        case RECEIVER_TEAM_MEMBERS:
          // Response to team; recipient = teamName
          if (question.recipientType == FeedbackParticipantType.TEAMS) {
            if (roster.isStudentInTeam(
                userEmail, /* this is a team name */ response.recipientEmail)) {
              return true;
            }
            // Response to individual
          } else if (roster.isStudentsInSameTeam(response.recipientEmail, userEmail)) {
            return true;
          } else {
            break;
          }
        case STUDENTS:
          if (roster.isStudentInCourse(userEmail)) {
            return true;
          } else {
            break;
          }
        default:
          Assumption.fail(
              "Invalid FeedbackPariticipantType for showNameTo in "
                  + "FeedbackResponseLogic.isNameVisible()");
          break;
      }
    }
    return false;
  }

  /**
   * Updates a {@link FeedbackResponse} based on it's {@code id}.<br>
   * If the giver/recipient field is changed, the {@link FeedbackResponse} is updated by recreating
   * the response<br>
   * in order to prevent an id clash if the previous email is reused later on.
   */
  public void updateFeedbackResponse(FeedbackResponseAttributes responseToUpdate)
      throws InvalidParametersException, EntityDoesNotExistException, EntityAlreadyExistsException {

    // Create a copy.
    FeedbackResponseAttributes newResponse = new FeedbackResponseAttributes(responseToUpdate);
    FeedbackResponseAttributes oldResponse = null;
    if (newResponse.getId() == null) {
      oldResponse =
          frDb.getFeedbackResponse(
              newResponse.feedbackQuestionId, newResponse.giverEmail, newResponse.recipientEmail);
    } else {
      oldResponse = frDb.getFeedbackResponse(newResponse.getId());
    }

    if (oldResponse == null) {
      throw new EntityDoesNotExistException(
          "Trying to update a feedback response that does not exist.");
    }

    // Copy values that cannot be changed to defensively avoid invalid
    // parameters.
    newResponse.courseId = oldResponse.courseId;
    newResponse.feedbackSessionName = oldResponse.feedbackSessionName;
    newResponse.feedbackQuestionId = oldResponse.feedbackQuestionId;
    newResponse.feedbackQuestionType = oldResponse.feedbackQuestionType;

    if (newResponse.responseMetaData == null) {
      newResponse.responseMetaData = oldResponse.responseMetaData;
    }
    if (newResponse.giverEmail == null) {
      newResponse.giverEmail = oldResponse.giverEmail;
    }
    if (newResponse.recipientEmail == null) {
      newResponse.recipientEmail = oldResponse.recipientEmail;
    }
    if (newResponse.giverSection == null) {
      newResponse.giverSection = oldResponse.giverSection;
    }
    if (newResponse.recipientSection == null) {
      newResponse.recipientSection = oldResponse.recipientSection;
    }

    if (!newResponse.recipientEmail.equals(oldResponse.recipientEmail)
        || !newResponse.giverEmail.equals(oldResponse.giverEmail)) {
      // Recreate response to prevent possible future id conflict.
      try {
        newResponse.setId(null);
        frDb.createEntity(newResponse);
        frDb.deleteEntity(oldResponse);
      } catch (EntityAlreadyExistsException e) {
        log.warning("Trying to update an existing response to one that already exists.");
        throw new EntityAlreadyExistsException(
            e.getMessage()
                + Const.EOL
                + "Trying to update recipient for response to one that already exists for this giver.");
      }
    } else {
      frDb.updateFeedbackResponse(newResponse);
    }
  }

  /**
   * Updates responses for a student when his team changes. This is done by deleting responses that
   * are no longer relevant to him in his new team.
   */
  public void updateFeedbackResponsesForChangingTeam(
      String courseId, String userEmail, String oldTeam, String newTeam)
      throws EntityDoesNotExistException {

    FeedbackQuestionAttributes question;

    List<FeedbackResponseAttributes> responsesFromUser =
        getFeedbackResponsesFromGiverForCourse(courseId, userEmail);

    for (FeedbackResponseAttributes response : responsesFromUser) {
      question = fqLogic.getFeedbackQuestion(response.feedbackQuestionId);
      if (question.giverType == FeedbackParticipantType.TEAMS
          || question.recipientType == FeedbackParticipantType.OWN_TEAM_MEMBERS
          || question.recipientType == FeedbackParticipantType.OWN_TEAM_MEMBERS_INCLUDING_SELF) {
        frDb.deleteEntity(response);
      }
    }

    List<FeedbackResponseAttributes> responsesToUser =
        getFeedbackResponsesForReceiverForCourse(courseId, userEmail);

    for (FeedbackResponseAttributes response : responsesToUser) {
      question = fqLogic.getFeedbackQuestion(response.feedbackQuestionId);
      if (question.recipientType == FeedbackParticipantType.OWN_TEAM_MEMBERS
          || question.recipientType == FeedbackParticipantType.OWN_TEAM_MEMBERS_INCLUDING_SELF) {
        frDb.deleteEntity(response);
      }
    }

    if (studentsLogic.getStudentsForTeam(oldTeam, courseId).isEmpty()) {
      List<FeedbackResponseAttributes> responsesToTeam =
          getFeedbackResponsesForReceiverForCourse(courseId, oldTeam);
      for (FeedbackResponseAttributes response : responsesToTeam) {
        frDb.deleteEntity(response);
      }
    }
  }

  public void updateFeedbackResponsesForChangingSection(
      String courseId, String userEmail, String oldSection, String newSection)
      throws EntityDoesNotExistException, InvalidParametersException {

    List<FeedbackResponseAttributes> responsesFromUser =
        getFeedbackResponsesFromGiverForCourse(courseId, userEmail);

    for (FeedbackResponseAttributes response : responsesFromUser) {
      response.giverSection = newSection;
      frDb.updateFeedbackResponse(response);
      frcLogic.updateFeedbackResponseCommentsForResponse(response.getId());
    }

    List<FeedbackResponseAttributes> responsesToUser =
        getFeedbackResponsesForReceiverForCourse(courseId, userEmail);

    for (FeedbackResponseAttributes response : responsesToUser) {
      response.recipientSection = newSection;
      frDb.updateFeedbackResponse(response);
      frcLogic.updateFeedbackResponseCommentsForResponse(response.getId());
    }
  }

  public boolean updateFeedbackResponseForChangingTeam(
      StudentEnrollDetails enrollment, FeedbackResponseAttributes response) {

    FeedbackQuestionAttributes question = fqLogic.getFeedbackQuestion(response.feedbackQuestionId);

    boolean isGiverSameForResponseAndEnrollment = response.giverEmail.equals(enrollment.email);
    boolean isReceiverSameForResponseAndEnrollment =
        response.recipientEmail.equals(enrollment.email);

    boolean shouldDeleteByChangeOfGiver =
        (isGiverSameForResponseAndEnrollment
            && (question.giverType == FeedbackParticipantType.TEAMS
                || question.recipientType == FeedbackParticipantType.OWN_TEAM_MEMBERS));
    boolean shouldDeleteByChangeOfRecipient =
        (isReceiverSameForResponseAndEnrollment
            && question.recipientType == FeedbackParticipantType.OWN_TEAM_MEMBERS);

    boolean shouldDeleteResponse = shouldDeleteByChangeOfGiver || shouldDeleteByChangeOfRecipient;

    if (shouldDeleteResponse) {
      frDb.deleteEntity(response);
    }

    return shouldDeleteResponse;
  }

  public void updateFeedbackResponseForChangingSection(
      StudentEnrollDetails enrollment, FeedbackResponseAttributes response)
      throws InvalidParametersException, EntityDoesNotExistException {

    FeedbackResponse feedbackResponse = frDb.getFeedbackResponseEntityOptimized(response);
    boolean isGiverSameForResponseAndEnrollment =
        feedbackResponse.getGiverEmail().equals(enrollment.email);
    boolean isReceiverSameForResponseAndEnrollment =
        feedbackResponse.getRecipientEmail().equals(enrollment.email);

    if (isGiverSameForResponseAndEnrollment) {
      feedbackResponse.setGiverSection(enrollment.newSection);
    }

    if (isReceiverSameForResponseAndEnrollment) {
      feedbackResponse.setRecipientSection(enrollment.newSection);
    }

    frDb.commitOutstandingChanges();

    if (isGiverSameForResponseAndEnrollment || isReceiverSameForResponseAndEnrollment) {
      frcLogic.updateFeedbackResponseCommentsForResponse(response.getId());
    }
  }

  /** Updates responses for a student when his email changes. */
  // TODO: cascade the update to response comments
  public void updateFeedbackResponsesForChangingEmail(
      String courseId, String oldEmail, String newEmail)
      throws InvalidParametersException, EntityDoesNotExistException {

    List<FeedbackResponseAttributes> responsesFromUser =
        getFeedbackResponsesFromGiverForCourse(courseId, oldEmail);

    for (FeedbackResponseAttributes response : responsesFromUser) {
      response.giverEmail = newEmail;
      try {
        updateFeedbackResponse(response);
      } catch (EntityAlreadyExistsException e) {
        Assumption.fail(
            "Feedback response failed to update successfully" + "as email was already in use.");
      }
    }

    List<FeedbackResponseAttributes> responsesToUser =
        getFeedbackResponsesForReceiverForCourse(courseId, oldEmail);

    for (FeedbackResponseAttributes response : responsesToUser) {
      response.recipientEmail = newEmail;
      try {
        updateFeedbackResponse(response);
      } catch (EntityAlreadyExistsException e) {
        Assumption.fail(
            "Feedback response failed to update successfully" + "as email was already in use.");
      }
    }
  }

  public void deleteFeedbackResponseAndCascade(FeedbackResponseAttributes responseToDelete) {
    frcLogic.deleteFeedbackResponseCommentsForResponse(responseToDelete.getId());
    frDb.deleteEntity(responseToDelete);
  }

  public void deleteFeedbackResponsesForQuestionAndCascade(String feedbackQuestionId) {
    List<FeedbackResponseAttributes> responsesForQuestion =
        getFeedbackResponsesForQuestion(feedbackQuestionId);
    for (FeedbackResponseAttributes response : responsesForQuestion) {
      this.deleteFeedbackResponseAndCascade(response);
    }
  }

  public void deleteFeedbackResponsesForStudentAndCascade(String courseId, String studentEmail) {

    String studentTeam = "";
    StudentAttributes student = studentsLogic.getStudentForEmail(courseId, studentEmail);

    if (student != null) {
      studentTeam = student.team;
    }

    List<FeedbackResponseAttributes> responses =
        getFeedbackResponsesFromGiverForCourse(courseId, studentEmail);
    responses.addAll(getFeedbackResponsesForReceiverForCourse(courseId, studentEmail));
    // Delete responses to team as well if student is last person in team.
    if (studentsLogic.getStudentsForTeam(studentTeam, courseId).size() <= 1) {
      responses.addAll(getFeedbackResponsesForReceiverForCourse(courseId, studentTeam));
    }

    for (FeedbackResponseAttributes response : responses) {
      this.deleteFeedbackResponseAndCascade(response);
    }
  }

  /**
   * Adds {@link FeedbackResponseAttributes} in {@code newResponses} that are not already in to
   * {@code existingResponses} to {@code existingResponses}.
   */
  private void addNewResponses(
      List<FeedbackResponseAttributes> existingResponses,
      List<FeedbackResponseAttributes> newResponses) {

    Map<String, FeedbackResponseAttributes> responses =
        new HashMap<String, FeedbackResponseAttributes>();

    for (FeedbackResponseAttributes existingResponse : existingResponses) {
      responses.put(existingResponse.getId(), existingResponse);
    }
    for (FeedbackResponseAttributes newResponse : newResponses) {
      if (!responses.containsKey(newResponse.getId())) {
        responses.put(newResponse.getId(), newResponse);
        existingResponses.add(newResponse);
      }
    }
  }

  private List<FeedbackResponseAttributes> getFeedbackResponsesFromTeamForQuestion(
      String feedbackQuestionId, String courseId, String teamName) {

    List<FeedbackResponseAttributes> responses = new ArrayList<FeedbackResponseAttributes>();
    List<StudentAttributes> studentsInTeam = studentsLogic.getStudentsForTeam(teamName, courseId);

    for (StudentAttributes student : studentsInTeam) {
      responses.addAll(
          frDb.getFeedbackResponsesFromGiverForQuestion(feedbackQuestionId, student.email));
    }

    return responses;
  }

  private List<FeedbackResponseAttributes> getFeedbackResponsesForTeamMembersOfStudent(
      String feedbackQuestionId, StudentAttributes student) {

    List<StudentAttributes> studentsInTeam =
        studentsLogic.getStudentsForTeam(student.team, student.course);

    List<FeedbackResponseAttributes> teamResponses = new ArrayList<FeedbackResponseAttributes>();

    for (StudentAttributes studentInTeam : studentsInTeam) {
      if (studentInTeam.email.equals(student.email)) {
        continue;
      }
      List<FeedbackResponseAttributes> responses =
          frDb.getFeedbackResponsesForReceiverForQuestion(feedbackQuestionId, studentInTeam.email);
      teamResponses.addAll(responses);
    }

    return teamResponses;
  }

  private List<FeedbackResponseAttributes> getViewableFeedbackResponsesForStudentForQuestion(
      FeedbackQuestionAttributes question, String studentEmail) {

    List<FeedbackResponseAttributes> viewableResponses =
        new ArrayList<FeedbackResponseAttributes>();

    StudentAttributes student = studentsLogic.getStudentForEmail(question.courseId, studentEmail);

    if (question.isResponseVisibleTo(FeedbackParticipantType.STUDENTS)) {
      addNewResponses(viewableResponses, getFeedbackResponsesForQuestion(question.getId()));

      // Early return as STUDENTS covers all other student types.
      return viewableResponses;
    }

    if (question.recipientType == FeedbackParticipantType.TEAMS
        && question.isResponseVisibleTo(FeedbackParticipantType.RECEIVER)) {
      addNewResponses(
          viewableResponses,
          getFeedbackResponsesForReceiverForQuestion(question.getId(), student.team));
    }

    if (question.giverType == FeedbackParticipantType.TEAMS
        || question.isResponseVisibleTo(FeedbackParticipantType.OWN_TEAM_MEMBERS)) {
      addNewResponses(
          viewableResponses,
          getFeedbackResponsesFromTeamForQuestion(
              question.getId(), question.courseId, student.team));
    }
    if (question.isResponseVisibleTo(FeedbackParticipantType.RECEIVER_TEAM_MEMBERS)) {
      addNewResponses(
          viewableResponses,
          getFeedbackResponsesForTeamMembersOfStudent(question.getId(), student));
    }

    return viewableResponses;
  }
}