// 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 testEditResponse() {
    ______TS("edit responses");

    FeedbackQuestionAttributes fq =
        BackDoor.getFeedbackQuestion("IESFPTCourse", "First feedback session", 1);
    FeedbackResponseAttributes fr =
        BackDoor.getFeedbackResponse(
            fq.getId(), "*****@*****.**", "*****@*****.**");

    assertEquals("Student 1 self feedback.", fr.getResponseDetails().getAnswerString());

    submitPage =
        loginToInstructorEditStudentFeedbackPage(
            "IESFPTCourseinstr", "*****@*****.**", "session1InIESFPTCourse");

    // Full HTML verification already done in InstructorFeedbackSubmitPageUiTest
    submitPage.verifyHtmlMainContent("/InstructorEditStudentFeedbackPageOpen.html");

    submitPage.fillResponseTextBox(1, 0, "Good design");
    submitPage.clickSubmitButton();
    assertEquals(submitPage.getStatus(), Const.StatusMessages.FEEDBACK_RESPONSES_SAVED);

    fq = BackDoor.getFeedbackQuestion("IESFPTCourse", "First feedback session", 1);

    fr =
        BackDoor.getFeedbackResponse(
            fq.getId(), "*****@*****.**", "*****@*****.**");

    assertEquals("Good design", fr.getResponseDetails().getAnswerString());
  }
  private void repairResponsesForQuestion(
      FeedbackQuestionAttributes question,
      boolean needRepairGiverSection,
      boolean needRepairRecipientSection)
      throws InvalidParametersException, EntityAlreadyExistsException, EntityDoesNotExistException {
    List<FeedbackResponseAttributes> responses =
        logic.getFeedbackResponsesForQuestion(question.getId());
    for (FeedbackResponseAttributes response : responses) {
      boolean needUpdateResponse = false;
      String originalGiverSection = "";
      String originalRecipientSection = "";
      if (needRepairGiverSection) {
        StudentAttributes student = logic.getStudentForEmail(question.courseId, response.giver);
        if (!response.giverSection.equals(student.section)) {
          originalGiverSection = response.giverSection;
          response.giverSection = student.section;
          needUpdateResponse = true;
        }
      }

      if (needRepairRecipientSection) {
        if (isTeamRecipient(question.recipientType)) {
          String recipientSection =
              logic.getStudentsForTeam(response.recipient, question.courseId).get(0).section;
          if (!recipientSection.equals(response.recipientSection)) {
            originalRecipientSection = response.recipientSection;
            response.recipientSection = recipientSection;
            needUpdateResponse = true;
          }
        } else {
          StudentAttributes student =
              logic.getStudentForEmail(question.courseId, response.recipient);
          if (!response.recipientSection.equals(student.section)) {
            originalRecipientSection = response.recipientSection;
            response.recipientSection = student.section;
            needUpdateResponse = true;
          }
        }
      }

      if (needUpdateResponse) {
        System.out.println(
            "Repairing giver section:"
                + originalGiverSection
                + "-->"
                + response.giverSection
                + " receiver section:"
                + originalRecipientSection
                + "-->"
                + response.recipientSection);
        logic.updateFeedbackResponse(response);
      }
    }
  }
  private static FeedbackSessionRow getFeedbackSessionRow(FeedbackSessionResultsBundle bundle) {
    List<QuestionTable> questionTables = new ArrayList<QuestionTable>();
    FeedbackSessionAttributes session = bundle.feedbackSession;
    Map<FeedbackQuestionAttributes, List<FeedbackResponseAttributes>> questionToResponsesMap =
        bundle.getQuestionResponseMap();
    for (FeedbackQuestionAttributes question : questionToResponsesMap.keySet()) {
      List<ResponseRow> responseRows = new ArrayList<ResponseRow>();
      List<FeedbackResponseAttributes> responses = questionToResponsesMap.get(question);
      for (FeedbackResponseAttributes response : responses) {
        List<FeedbackResponseComment> feedbackResponseCommentRows =
            new ArrayList<FeedbackResponseComment>();
        List<FeedbackResponseCommentAttributes> responseComments =
            bundle.responseComments.get(response.getId());
        for (FeedbackResponseCommentAttributes responseComment : responseComments) {
          FeedbackResponseComment feedbackResponseCommentRow =
              new FeedbackResponseComment(responseComment, responseComment.giverEmail);
          feedbackResponseCommentRows.add(feedbackResponseCommentRow);
        }
        String giverName = bundle.getGiverNameForResponse(response);
        String giverTeamName = bundle.getTeamNameForEmail(response.giverEmail);
        giverName = bundle.appendTeamNameToName(giverName, giverTeamName);

        String recipientName = bundle.getRecipientNameForResponse(response);
        String recipientTeamName = bundle.getTeamNameForEmail(response.recipientEmail);
        recipientName = bundle.appendTeamNameToName(recipientName, recipientTeamName);

        String responseText =
            response.getResponseDetails().getAnswerHtml(question.getQuestionDetails());

        ResponseRow responseRow =
            new ResponseRow(giverName, recipientName, responseText, feedbackResponseCommentRows);
        responseRows.add(responseRow);
      }
      int questionNumber = question.questionNumber;
      String questionText = bundle.getQuestionText(question.getId());
      String additionalInfo =
          question.getQuestionDetails().getQuestionAdditionalInfoHtml(question.questionNumber, "");
      QuestionTable questionTable =
          new QuestionTable(questionNumber, questionText, additionalInfo, responseRows);
      questionTables.add(questionTable);
    }

    FeedbackSessionRow sessionRow =
        new FeedbackSessionRow(session.feedbackSessionName, session.courseId, questionTables);

    return sessionRow;
  }
  /**
   * 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 void testAddResponse() {
    ______TS("test new response");

    submitPage.fillResponseTextBox(2, 0, "4");
    submitPage.clickSubmitButton();
    assertEquals(submitPage.getStatus(), Const.StatusMessages.FEEDBACK_RESPONSES_SAVED);

    FeedbackQuestionAttributes fq =
        BackDoor.getFeedbackQuestion("IESFPTCourse", "First feedback session", 2);
    FeedbackResponseAttributes fr =
        BackDoor.getFeedbackResponse(
            fq.getId(), "*****@*****.**", "*****@*****.**");

    assertEquals("4", fr.getResponseDetails().getAnswerString());

    // Full HTML verification already done in InstructorFeedbackSubmitPageUiTest
    submitPage.verifyHtmlMainContent("/InstructorEditStudentFeedbackPageModified.html");
  }
  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();
      }
    }
  }
 /**
  * Creates a single FeedbackSessionResultsBundle object which comprises a single feedback session,
  * a single question, a single response and a single response comment
  */
 private static FeedbackSessionResultsBundle getSingleFeedbackSessionResultsBundle(
     CourseRoster roster) {
   FeedbackSessionAttributes session = dataBundle.feedbackSessions.get("session1InCourse1");
   FeedbackResponseAttributes response = dataBundle.feedbackResponses.get("response1ForQ1S1C1");
   response.setId("1");
   List<FeedbackResponseAttributes> responses = Arrays.asList(response);
   Map<String, FeedbackQuestionAttributes> relevantQuestions =
       new HashMap<String, FeedbackQuestionAttributes>();
   FeedbackQuestionAttributes question =
       dataBundle.feedbackQuestions.get("qn1InSession1InCourse1");
   question.setId("1");
   relevantQuestions.put(question.getId(), question);
   Map<String, String> emailNameTable = new HashMap<String, String>();
   Map<String, String> emailLastNameTable = new HashMap<String, String>();
   Map<String, String> emailTeamNameTable = new HashMap<String, String>();
   Map<String, boolean[]> visibilityTable = new HashMap<String, boolean[]>();
   Map<String, List<FeedbackResponseCommentAttributes>> responseComments =
       new HashMap<String, List<FeedbackResponseCommentAttributes>>();
   emailNameTable.put(sampleStudent.email, sampleStudent.name);
   emailLastNameTable.put(sampleStudent.email, sampleStudent.lastName);
   emailTeamNameTable.put(sampleStudent.email, sampleStudent.team);
   boolean[] visibility = {true, true};
   visibilityTable.put(response.getId(), visibility);
   FeedbackSessionResponseStatus responseStatus = new FeedbackSessionResponseStatus();
   responseStatus.emailNameTable.put(sampleStudent.email, sampleStudent.name);
   responseStatus.emailTeamNameTable.put(sampleStudent.email, sampleStudent.team);
   FeedbackResponseCommentAttributes responseComment =
       dataBundle.feedbackResponseComments.get("comment1FromT1C1ToR1Q1S1C1");
   List<FeedbackResponseCommentAttributes> responseCommentsList = Arrays.asList(responseComment);
   responseComments.put(response.getId(), responseCommentsList);
   boolean isComplete = true;
   return new FeedbackSessionResultsBundle(
       session,
       responses,
       relevantQuestions,
       emailNameTable,
       emailLastNameTable,
       emailTeamNameTable,
       visibilityTable,
       responseStatus,
       roster,
       responseComments,
       isComplete);
 }
  /**
   * If the {@code response} is an existing response, check that the questionId and responseId that
   * it has is in {@code data.bundle.questionResponseBundle}
   *
   * @param response a response which has non-null id
   */
  private boolean isExistingResponseValid(FeedbackResponseAttributes response) {

    String questionId = response.feedbackQuestionId;
    FeedbackQuestionAttributes question = data.bundle.getQuestionAttributes(questionId);

    if (!data.bundle.questionResponseBundle.containsKey(question)) {
      // question id is invalid
      return false;
    }

    List<FeedbackResponseAttributes> existingResponses =
        data.bundle.questionResponseBundle.get(question);
    List<String> existingResponsesId = new ArrayList<String>();
    for (FeedbackResponseAttributes existingResponse : existingResponses) {
      existingResponsesId.add(existingResponse.getId());
    }

    if (!existingResponsesId.contains(response.getId())) {
      // response id is invalid
      return false;
    }

    return true;
  }
 private void saveResponse(FeedbackResponseAttributes response)
     throws EntityDoesNotExistException {
   if (response.getId() != null) {
     // Delete away response if any empty fields
     if (response.responseMetaData.getValue().isEmpty() || response.recipientEmail.isEmpty()) {
       logic.deleteFeedbackResponse(response);
       return;
     }
     try {
       logic.updateFeedbackResponse(response);
       hasValidResponse = true;
     } catch (EntityAlreadyExistsException | InvalidParametersException e) {
       setStatusForException(e);
     }
   } else if (!response.responseMetaData.getValue().isEmpty()
       && !response.recipientEmail.isEmpty()) {
     try {
       logic.createFeedbackResponse(response);
       hasValidResponse = true;
     } catch (EntityAlreadyExistsException | InvalidParametersException e) {
       setStatusForException(e);
     }
   }
 }
  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());
    }
  }
  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());
    }
  }
  @Override
  protected ActionResult execute() throws EntityDoesNotExistException {
    courseId = getRequestParamValue(Const.ParamsNames.COURSE_ID);
    feedbackSessionName = getRequestParamValue(Const.ParamsNames.FEEDBACK_SESSION_NAME);
    Assumption.assertPostParamNotNull(Const.ParamsNames.COURSE_ID, courseId);
    Assumption.assertPostParamNotNull(Const.ParamsNames.FEEDBACK_SESSION_NAME, feedbackSessionName);

    setAdditionalParameters();
    verifyAccesibleForSpecificUser();

    String userEmailForCourse = getUserEmailForCourse();
    String userTeamForCourse = getUserTeamForCourse();
    String userSectionForCourse = getUserSectionForCourse();
    data = new FeedbackSubmissionEditPageData(account, student);
    data.bundle = getDataBundle(userEmailForCourse);
    Assumption.assertNotNull(
        "Feedback session " + feedbackSessionName + " does not exist in " + courseId + ".",
        data.bundle);

    checkAdditionalConstraints();

    setStatusToAdmin();

    if (!isSessionOpenForSpecificUser(data.bundle.feedbackSession)) {
      isError = true;
      statusToUser.add(
          new StatusMessage(
              Const.StatusMessages.FEEDBACK_SUBMISSIONS_NOT_OPEN, StatusMessageColor.WARNING));
      return createSpecificRedirectResult();
    }

    int numOfQuestionsToGet = data.bundle.questionResponseBundle.size();
    for (int questionIndx = 1; questionIndx <= numOfQuestionsToGet; questionIndx++) {
      String totalResponsesForQuestion =
          getRequestParamValue(
              Const.ParamsNames.FEEDBACK_QUESTION_RESPONSETOTAL + "-" + questionIndx);

      if (totalResponsesForQuestion == null) {
        continue; // question has been skipped (not displayed).
      }

      List<FeedbackResponseAttributes> responsesForQuestion =
          new ArrayList<FeedbackResponseAttributes>();
      String questionId =
          HttpRequestHelper.getValueFromParamMap(
              requestParameters, Const.ParamsNames.FEEDBACK_QUESTION_ID + "-" + questionIndx);
      FeedbackQuestionAttributes questionAttributes = data.bundle.getQuestionAttributes(questionId);
      if (questionAttributes == null) {
        statusToUser.add(
            new StatusMessage(
                "The feedback session or questions may have changed while you were submitting. "
                    + "Please check your responses to make sure they are saved correctly.",
                StatusMessageColor.WARNING));
        isError = true;
        log.warning(
            "Question not found. (deleted or invalid id passed?) id: "
                + questionId
                + " index: "
                + questionIndx);
        continue;
      }

      FeedbackQuestionDetails questionDetails = questionAttributes.getQuestionDetails();

      int numOfResponsesToGet = Integer.parseInt(totalResponsesForQuestion);
      String qnId = "";

      Set<String> emailSet = data.bundle.getRecipientEmails(questionAttributes.getId());
      emailSet.add("");
      emailSet = StringHelper.recoverFromSanitizedText(emailSet);

      ArrayList<String> responsesRecipients = new ArrayList<String>();
      List<String> errors = new ArrayList<String>();

      for (int responseIndx = 0; responseIndx < numOfResponsesToGet; responseIndx++) {
        FeedbackResponseAttributes response =
            extractFeedbackResponseData(
                requestParameters, questionIndx, responseIndx, questionAttributes);

        if (response.feedbackQuestionType != questionAttributes.questionType) {
          errors.add(
              String.format(
                  Const.StatusMessages.FEEDBACK_RESPONSES_WRONG_QUESTION_TYPE, questionIndx));
        }

        qnId = response.feedbackQuestionId;

        boolean isExistingResponse = response.getId() != null;
        // test that if editing an existing response, that the edited response's id
        // came from the original set of existing responses loaded on the submission page
        if (isExistingResponse && !isExistingResponseValid(response)) {
          errors.add(
              String.format(Const.StatusMessages.FEEDBACK_RESPONSES_INVALID_ID, questionIndx));
          continue;
        }

        responsesRecipients.add(response.recipientEmail);
        // if the answer is not empty but the recipient is empty
        if (response.recipientEmail.isEmpty() && !response.responseMetaData.getValue().isEmpty()) {
          errors.add(
              String.format(
                  Const.StatusMessages.FEEDBACK_RESPONSES_MISSING_RECIPIENT, questionIndx));
        }

        if (response.responseMetaData.getValue().isEmpty()) {
          // deletes the response since answer is empty
          saveResponse(response);
        } else {
          response.giverEmail =
              questionAttributes.giverType.isTeam() ? userTeamForCourse : userEmailForCourse;
          response.giverSection = userSectionForCourse;
          responsesForQuestion.add(response);
        }
      }

      List<String> questionSpecificErrors =
          questionDetails.validateResponseAttributes(
              responsesForQuestion, data.bundle.recipientList.get(qnId).size());
      errors.addAll(questionSpecificErrors);

      if (!emailSet.containsAll(responsesRecipients)) {
        errors.add(
            String.format(Const.StatusMessages.FEEDBACK_RESPONSE_INVALID_RECIPIENT, questionIndx));
      }

      if (errors.isEmpty()) {
        for (FeedbackResponseAttributes response : responsesForQuestion) {
          saveResponse(response);
        }
      } else {
        List<StatusMessage> errorMessages = new ArrayList<StatusMessage>();

        for (String error : errors) {
          errorMessages.add(new StatusMessage(error, StatusMessageColor.DANGER));
        }

        statusToUser.addAll(errorMessages);
        isError = true;
      }
    }

    if (!isError) {
      statusToUser.add(
          new StatusMessage(
              Const.StatusMessages.FEEDBACK_RESPONSES_SAVED, StatusMessageColor.SUCCESS));
    }

    if (isUserRespondentOfSession()) {
      appendRespondant();
    } else {
      removeRespondant();
    }

    return createSpecificRedirectResult();
  }
  private FeedbackResponseAttributes extractFeedbackResponseData(
      Map<String, String[]> requestParameters,
      int questionIndx,
      int responseIndx,
      FeedbackQuestionAttributes feedbackQuestionAttributes) {

    FeedbackQuestionDetails questionDetails = feedbackQuestionAttributes.getQuestionDetails();
    FeedbackResponseAttributes response = new FeedbackResponseAttributes();

    // This field can be null if the response is new
    response.setId(
        HttpRequestHelper.getValueFromParamMap(
            requestParameters,
            Const.ParamsNames.FEEDBACK_RESPONSE_ID + "-" + questionIndx + "-" + responseIndx));

    response.feedbackSessionName =
        HttpRequestHelper.getValueFromParamMap(
            requestParameters, Const.ParamsNames.FEEDBACK_SESSION_NAME);
    Assumption.assertNotNull("Null feedback session name", response.feedbackSessionName);

    response.courseId =
        HttpRequestHelper.getValueFromParamMap(requestParameters, Const.ParamsNames.COURSE_ID);
    Assumption.assertNotNull("Null feedback courseId", response.courseId);

    response.feedbackQuestionId =
        HttpRequestHelper.getValueFromParamMap(
            requestParameters, Const.ParamsNames.FEEDBACK_QUESTION_ID + "-" + questionIndx);
    Assumption.assertNotNull("Null feedbackQuestionId", response.feedbackQuestionId);
    Assumption.assertEquals(
        "feedbackQuestionId Mismatch",
        feedbackQuestionAttributes.getId(),
        response.feedbackQuestionId);

    response.recipientEmail =
        HttpRequestHelper.getValueFromParamMap(
            requestParameters,
            Const.ParamsNames.FEEDBACK_RESPONSE_RECIPIENT
                + "-"
                + questionIndx
                + "-"
                + responseIndx);
    Assumption.assertNotNull("Null feedback recipientEmail", response.recipientEmail);

    String feedbackQuestionType =
        HttpRequestHelper.getValueFromParamMap(
            requestParameters, Const.ParamsNames.FEEDBACK_QUESTION_TYPE + "-" + questionIndx);
    Assumption.assertNotNull("Null feedbackQuestionType", feedbackQuestionType);
    response.feedbackQuestionType = FeedbackQuestionType.valueOf(feedbackQuestionType);

    FeedbackParticipantType recipientType = feedbackQuestionAttributes.recipientType;
    if (recipientType == FeedbackParticipantType.INSTRUCTORS
        || recipientType == FeedbackParticipantType.NONE) {
      response.recipientSection = Const.DEFAULT_SECTION;
    } else if (recipientType == FeedbackParticipantType.TEAMS) {
      response.recipientSection =
          StudentsLogic.inst().getSectionForTeam(courseId, response.recipientEmail);
    } else if (recipientType == FeedbackParticipantType.STUDENTS) {
      StudentAttributes student = logic.getStudentForEmail(courseId, response.recipientEmail);
      response.recipientSection = (student == null) ? Const.DEFAULT_SECTION : student.section;
    } else {
      response.recipientSection = getUserSectionForCourse();
    }

    // This field can be null if the question is skipped
    String[] answer =
        HttpRequestHelper.getValuesFromParamMap(
            requestParameters,
            Const.ParamsNames.FEEDBACK_RESPONSE_TEXT + "-" + questionIndx + "-" + responseIndx);

    if (!questionDetails.isQuestionSkipped(answer)) {
      FeedbackResponseDetails responseDetails =
          FeedbackResponseDetails.createResponseDetails(
              answer,
              questionDetails.questionType,
              questionDetails,
              requestParameters,
              questionIndx,
              responseIndx);
      response.setResponseDetails(responseDetails);
    } else {
      response.responseMetaData = new Text("");
    }

    return response;
  }
 public void deleteFeedbackResponseAndCascade(FeedbackResponseAttributes responseToDelete) {
   frcLogic.deleteFeedbackResponseCommentsForResponse(responseToDelete.getId());
   frDb.deleteEntity(responseToDelete);
 }
  /**
   * 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);
    }
  }