gt:             for (int i = 0; i < numOfConstSumOptions; i++) {
context: package teammates.common.datatransfer.questions;
  
  import java.text.DecimalFormat;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.Comparator;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Map.Entry;
  import java.util.Set;
  import java.util.TreeMap;
  
  import teammates.common.datatransfer.FeedbackSessionResultsBundle;
  import teammates.common.datatransfer.attributes.FeedbackQuestionAttributes;
  import teammates.common.datatransfer.attributes.FeedbackResponseAttributes;
  import teammates.common.util.Assumption;
  import teammates.common.util.Const;
  import teammates.common.util.HttpRequestHelper;
  import teammates.common.util.SanitizationHelper;
  import teammates.common.util.StringHelper;
  import teammates.common.util.Templates;
  import teammates.common.util.Templates.FeedbackQuestion.FormTemplates;
  import teammates.common.util.Templates.FeedbackQuestion.Slots;
  import teammates.common.util.FieldValidator;
  import teammates.logic.core.FeedbackQuestionsLogic;
  import teammates.ui.template.InstructorFeedbackResultsResponseRow;
  
  public class FeedbackConstantSumQuestionDetails extends FeedbackQuestionDetails {
      private int numOfConstSumOptions;
      private List<String> constSumOptions;
      private boolean distributeToRecipients;
      private boolean pointsPerOption;
      private boolean forceUnevenDistribution;
      private int points;
  
      public FeedbackConstantSumQuestionDetails() {
          super(FeedbackQuestionType.CONSTSUM);
  
          this.numOfConstSumOptions = 0;
          this.constSumOptions = new ArrayList<String>();
          this.distributeToRecipients = false;
          this.pointsPerOption = false;
          this.points = 100;
          this.forceUnevenDistribution = false;
      }
  
      public FeedbackConstantSumQuestionDetails(String questionText,
              List<String> constSumOptions,
              boolean pointsPerOption, int points, boolean unevenDistribution) {
          super(FeedbackQuestionType.CONSTSUM, questionText);
  
          this.numOfConstSumOptions = constSumOptions.size();
          this.constSumOptions = constSumOptions;
          this.distributeToRecipients = false;
          this.pointsPerOption = pointsPerOption;
          this.points = points;
          this.forceUnevenDistribution = unevenDistribution;
  
      }
  
      @Override
      public boolean extractQuestionDetails(
              Map<String, String[]> requestParameters,
              FeedbackQuestionType questionType) {
  
          String distributeToRecipientsString = null;
          String pointsPerOptionString = null;
          String pointsString = null;
          String pointsForEachOptionString = null;
          String pointsForEachRecipientString = null;
          String forceUnevenDistributionString = null;
          boolean distributeToRecipients = false;
          boolean pointsPerOption = false;
          boolean forceUnevenDistribution = false;
          int points = 0;
  
          distributeToRecipientsString =
                  HttpRequestHelper.getValueFromParamMap(requestParameters,
                                                         Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMTORECIPIENTS);
          pointsPerOptionString =
                  HttpRequestHelper.getValueFromParamMap(requestParameters,
                                                         Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMPOINTSPEROPTION);
          pointsString =
                  HttpRequestHelper.getValueFromParamMap(requestParameters,
                                                         Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMPOINTS);
          pointsForEachOptionString =
                  HttpRequestHelper.getValueFromParamMap(requestParameters,
                                                         Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMPOINTSFOREACHOPTION);
          pointsForEachRecipientString =
                  HttpRequestHelper.getValueFromParamMap(requestParameters,
                                                         Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMPOINTSFOREACHRECIPIENT);
  
          Assumption.assertNotNull("Null points in total", pointsString);
          Assumption.assertNotNull("Null points for each option", pointsForEachOptionString);
          Assumption.assertNotNull("Null points for each recipient", pointsForEachRecipientString);
          forceUnevenDistributionString =
                  HttpRequestHelper.getValueFromParamMap(requestParameters,
                                                         Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMDISTRIBUTEUNEVENLY);
  
          distributeToRecipients = "true".equals(distributeToRecipientsString);
          pointsPerOption = "true".equals(pointsPerOptionString);
          if (pointsPerOption) {
              points = distributeToRecipients ? Integer.parseInt(pointsForEachRecipientString)
                                              : Integer.parseInt(pointsForEachOptionString);
          } else {
              points = Integer.parseInt(pointsString);
          }
          forceUnevenDistribution = "on".equals(forceUnevenDistributionString);
  
          if (distributeToRecipients) {
              this.setConstantSumQuestionDetails(pointsPerOption, points, forceUnevenDistribution);
          } else {
              String numConstSumOptionsCreatedString =
                      HttpRequestHelper.getValueFromParamMap(requestParameters,
                                                             Const.ParamsNames.FEEDBACK_QUESTION_NUMBEROFCHOICECREATED);
              Assumption.assertNotNull("Null number of choice for ConstSum", numConstSumOptionsCreatedString);
              int numConstSumOptionsCreated = Integer.parseInt(numConstSumOptionsCreatedString);
  
              for (int i = 0; i < numConstSumOptionsCreated; i++) {
                  String constSumOption =
                          HttpRequestHelper.getValueFromParamMap(
                                  requestParameters, Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMOPTION + "-" + i);
                  if (constSumOption != null && !constSumOption.trim().isEmpty()) {
                      constSumOptions.add(constSumOption);
                      numOfConstSumOptions++;
                  }
              }
              this.setConstantSumQuestionDetails(constSumOptions, pointsPerOption, points, forceUnevenDistribution);
          }
          return true;
      }
  
      private void setConstantSumQuestionDetails(
              List<String> constSumOptions, boolean pointsPerOption,
              int points, boolean unevenDistribution) {
  
          this.numOfConstSumOptions = constSumOptions.size();
          this.constSumOptions = constSumOptions;
          this.distributeToRecipients = false;
          this.pointsPerOption = pointsPerOption;
          this.points = points;
          this.forceUnevenDistribution = unevenDistribution;
  
      }
  
      private void setConstantSumQuestionDetails(boolean pointsPerOption,
              int points, boolean unevenDistribution) {
  
          this.numOfConstSumOptions = 0;
          this.constSumOptions = new ArrayList<String>();
          this.distributeToRecipients = true;
          this.pointsPerOption = pointsPerOption;
          this.points = points;
          this.forceUnevenDistribution = unevenDistribution;
      }
  
      @Override
      public String getQuestionTypeDisplayName() {
          if (distributeToRecipients) {
              return Const.FeedbackQuestionTypeNames.CONSTSUM_RECIPIENT;
          }
          return Const.FeedbackQuestionTypeNames.CONSTSUM_OPTION;
      }
  
      @Override
      public String getQuestionWithExistingResponseSubmissionFormHtml(
              boolean sessionIsOpen, int qnIdx, int responseIdx, String courseId,
              int totalNumRecipients,
              FeedbackResponseDetails existingResponseDetails) {
  
          FeedbackConstantSumResponseDetails existingConstSumResponse =
                  (FeedbackConstantSumResponseDetails) existingResponseDetails;
          StringBuilder optionListHtml = new StringBuilder();
          String optionFragmentTemplate = FormTemplates.CONSTSUM_SUBMISSION_FORM_OPTIONFRAGMENT;
  
          if (distributeToRecipients) {
              String optionFragment =
                      Templates.populateTemplate(optionFragmentTemplate,
                              Slots.QUESTION_INDEX, Integer.toString(qnIdx),
                              Slots.RESPONSE_INDEX, Integer.toString(responseIdx),
                              Slots.OPTION_INDEX, "0",
                              Slots.DISABLED, sessionIsOpen ? "" : "disabled",
                              Slots.CONSTSUM_OPTION_VISIBILITY, "style=\"display:none\"",
                              Slots.MARGIN_LEFT, "",
                              Slots.CONSTSUM_OPTION_POINT, existingConstSumResponse.getAnswerString(),
                              Slots.FEEDBACK_RESPONSE_TEXT, Const.ParamsNames.FEEDBACK_RESPONSE_TEXT,
                              Slots.CONSTSUM_OPTION_VALUE, "");
              optionListHtml.append(optionFragment).append(Const.EOL);
          } else {
              for (int i = 0; i < constSumOptions.size(); i++) {
                  String optionFragment =
                          Templates.populateTemplate(optionFragmentTemplate,
                                  Slots.QUESTION_INDEX, Integer.toString(qnIdx),
                                  Slots.RESPONSE_INDEX, Integer.toString(responseIdx),
                                  Slots.OPTION_INDEX, Integer.toString(i),
                                  Slots.DISABLED, sessionIsOpen ? "" : "disabled",
                                  Slots.MARGIN_LEFT, "margin-left-auto",
                                  Slots.CONSTSUM_OPTION_VISIBILITY, "",
                                  Slots.CONSTSUM_OPTION_POINT,
                                          Integer.toString(existingConstSumResponse.getAnswerList().get(i)),
                                  Slots.FEEDBACK_RESPONSE_TEXT, Const.ParamsNames.FEEDBACK_RESPONSE_TEXT,
                                  Slots.CONSTSUM_OPTION_VALUE, SanitizationHelper.sanitizeForHtml(constSumOptions.get(i)));
                  optionListHtml.append(optionFragment).append(Const.EOL);
              }
          }
  
          return Templates.populateTemplate(
                  FormTemplates.CONSTSUM_SUBMISSION_FORM,
                  Slots.CONSTSUM_SUBMISSION_FORM_OPTION_FRAGMENT, optionListHtml.toString(),
                  Slots.QUESTION_INDEX, Integer.toString(qnIdx),
                  Slots.RESPONSE_INDEX, Integer.toString(responseIdx),
                  Slots.CONSTSUM_OPTION_VISIBILITY, distributeToRecipients ? "style=\"display:none\"" : "",
                  Slots.CONSTSUM_TO_RECIPIENTS_VALUE, Boolean.toString(distributeToRecipients),
                  Slots.CONSTSUM_POINTS_PER_OPTION_VALUE, Boolean.toString(pointsPerOption),
                  Slots.CONSTSUM_NUM_OPTION_VALUE, Integer.toString(constSumOptions.size()),
                  Slots.CONSTSUM_POINTS_VALUE, Integer.toString(points),
                  Slots.CONSTSUM_UNEVEN_DISTRIBUTION_VALUE, Boolean.toString(forceUnevenDistribution),
                  Slots.CONSTSUM_TO_RECIPIENTS, Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMTORECIPIENTS,
                  Slots.CONSTSUM_POINTS_PER_OPTION, Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMPOINTSPEROPTION,
                  Slots.CONSTSUM_NUM_OPTION, Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMNUMOPTION,
                  Slots.CONSTSUM_PARAM_POINTS, Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMPOINTS,
                  Slots.CONSTSUM_PARAM_POINTSFOREACHOPTION, Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMPOINTSFOREACHOPTION,
                  Slots.CONSTSUM_PARAM_POINTSFOREACHRECIPIENT,
                          Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMPOINTSFOREACHRECIPIENT,
                  Slots.CONSTSUM_PARAM_DISTRIBUTE_UNEVENLY, Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMDISTRIBUTEUNEVENLY
                  );
      }
  
      @Override
      public String getQuestionWithoutExistingResponseSubmissionFormHtml(
              boolean sessionIsOpen, int qnIdx, int responseIdx, String courseId, int totalNumRecipients) {
  
          StringBuilder optionListHtml = new StringBuilder();
          String optionFragmentTemplate = FormTemplates.CONSTSUM_SUBMISSION_FORM_OPTIONFRAGMENT;
  
          if (distributeToRecipients) {
              String optionFragment =
                      Templates.populateTemplate(optionFragmentTemplate,
                              Slots.QUESTION_INDEX, Integer.toString(qnIdx),
                              Slots.RESPONSE_INDEX, Integer.toString(responseIdx),
                              Slots.OPTION_INDEX, "0",
                              Slots.DISABLED, sessionIsOpen ? "" : "disabled",
                              Slots.MARGIN_LEFT, "",
                              Slots.CONSTSUM_OPTION_VISIBILITY, "style=\"display:none\"",
                              Slots.CONSTSUM_OPTION_POINT, "",
                              Slots.FEEDBACK_RESPONSE_TEXT, Const.ParamsNames.FEEDBACK_RESPONSE_TEXT,
                              Slots.CONSTSUM_OPTION_VALUE, "");
              optionListHtml.append(optionFragment).append(Const.EOL);
          } else {
              for (int i = 0; i < constSumOptions.size(); i++) {
                  String optionFragment =
                          Templates.populateTemplate(optionFragmentTemplate,
                                  Slots.QUESTION_INDEX, Integer.toString(qnIdx),
                                  Slots.RESPONSE_INDEX, Integer.toString(responseIdx),
                                  Slots.OPTION_INDEX, Integer.toString(i),
                                  Slots.DISABLED, sessionIsOpen ? "" : "disabled",
                                  Slots.MARGIN_LEFT, "margin-left-auto",
                                  Slots.CONSTSUM_OPTION_VISIBILITY, "",
                                  Slots.CONSTSUM_OPTION_POINT, "",
                                  Slots.FEEDBACK_RESPONSE_TEXT, Const.ParamsNames.FEEDBACK_RESPONSE_TEXT,
                                  Slots.CONSTSUM_OPTION_VALUE, SanitizationHelper.sanitizeForHtml(constSumOptions.get(i)));
                  optionListHtml.append(optionFragment).append(Const.EOL);
              }
          }
  
          return Templates.populateTemplate(
                  FormTemplates.CONSTSUM_SUBMISSION_FORM,
                  Slots.CONSTSUM_SUBMISSION_FORM_OPTION_FRAGMENT, optionListHtml.toString(),
                  Slots.QUESTION_INDEX, Integer.toString(qnIdx),
                  Slots.RESPONSE_INDEX, Integer.toString(responseIdx),
                  Slots.CONSTSUM_OPTION_VISIBILITY, distributeToRecipients ? "style=\"display:none\"" : "",
                  Slots.CONSTSUM_TO_RECIPIENTS_VALUE, Boolean.toString(distributeToRecipients),
                  Slots.CONSTSUM_POINTS_PER_OPTION_VALUE, Boolean.toString(pointsPerOption),
                  Slots.CONSTSUM_NUM_OPTION_VALUE, Integer.toString(constSumOptions.size()),
                  Slots.CONSTSUM_POINTS_VALUE, Integer.toString(points),
                  Slots.CONSTSUM_UNEVEN_DISTRIBUTION_VALUE, Boolean.toString(forceUnevenDistribution),
                  Slots.CONSTSUM_TO_RECIPIENTS, Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMTORECIPIENTS,
                  Slots.CONSTSUM_POINTS_PER_OPTION, Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMPOINTSPEROPTION,
                  Slots.CONSTSUM_NUM_OPTION, Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMNUMOPTION,
                  Slots.CONSTSUM_PARAM_POINTS, Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMPOINTS,
                  Slots.CONSTSUM_PARAM_POINTSFOREACHOPTION, Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMPOINTSFOREACHOPTION,
                  Slots.CONSTSUM_PARAM_POINTSFOREACHRECIPIENT,
                          Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMPOINTSFOREACHRECIPIENT,
                  Slots.CONSTSUM_PARAM_DISTRIBUTE_UNEVENLY, Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMDISTRIBUTEUNEVENLY
                  );
      }
  
      @Override
      public String getQuestionSpecificEditFormHtml(int questionNumber) {
          StringBuilder optionListHtml = new StringBuilder();
          String optionFragmentTemplate = FormTemplates.CONSTSUM_EDIT_FORM_OPTIONFRAGMENT;
          for (int i = 0; i < numOfConstSumOptions; i++) {
              String optionFragment =
                      Templates.populateTemplate(optionFragmentTemplate,
                              Slots.ITERATOR, Integer.toString(i),
                              Slots.CONSTSUM_OPTION_VALUE, SanitizationHelper.sanitizeForHtml(constSumOptions.get(i)),
                              Slots.CONSTSUM_PARAM_OPTION, Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMOPTION);
  
              optionListHtml.append(optionFragment).append(Const.EOL);
          }
  
          return Templates.populateTemplate(
                  FormTemplates.CONSTSUM_EDIT_FORM,
                  Slots.CONSTSUM_EDIT_FORM_OPTION_FRAGMENT, optionListHtml.toString(),
                  Slots.QUESTION_NUMBER, Integer.toString(questionNumber),
                  Slots.NUMBER_OF_CHOICE_CREATED, Const.ParamsNames.FEEDBACK_QUESTION_NUMBEROFCHOICECREATED,
                  Slots.CONSTSUM_NUMBER_OF_OPTIONS, Integer.toString(numOfConstSumOptions),
                  Slots.CONSTSUM_TO_RECIPIENTS_VALUE, Boolean.toString(distributeToRecipients),
                  Slots.CONSTSUM_SELECTED_POINTS_PER_OPTION, pointsPerOption ? "selected" : "",
                  Slots.CONSTSUM_OPTION_TABLE_VISIBILITY, distributeToRecipients ? "style=\"display:none\"" : "",
                  Slots.CONSTSUM_POINTS, points == 0 ? "100" : Integer.toString(points),
                  Slots.OPTION_DISPLAY, distributeToRecipients ? "style=\"display:none\"" : "",
                  Slots.RECIPIENT_DISPLAY, distributeToRecipients ? "" : "style=\"display:none\"",
                  Slots.PER_OPTION_CHECKED, !distributeToRecipients && pointsPerOption ? "checked" : "",
                  Slots.PER_RECIPIENT_CHECKED, distributeToRecipients && pointsPerOption ? "checked" : "",
                  Slots.OPTION_RECIPIENT_DISPLAY_NAME, distributeToRecipients ? "recipient" : "option",
                  Slots.CONSTSUM_TOOLTIP_POINTS,
                          distributeToRecipients ? Const.Tooltips.FEEDBACK_QUESTION_CONSTSUMPOINTS_RECIPIENT
                                                 : Const.Tooltips.FEEDBACK_QUESTION_CONSTSUMPOINTS_OPTION,
                  Slots.CONSTSUM_TOOLTIP_POINTS_PER_OPTION, Const.Tooltips.FEEDBACK_QUESTION_CONSTSUMPOINTSFOREACHOPTION,
                  Slots.CONSTSUM_TOOLTIP_POINTS_PER_RECIPIENT,
                          Const.Tooltips.FEEDBACK_QUESTION_CONSTSUMPOINTSFOREACHRECIPIENT,
                  Slots.CONSTSUM_DISTRIBUTE_UNEVENLY, forceUnevenDistribution ? "checked" : "",
                  Slots.CONSTSUM_TO_RECIPIENTS, Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMTORECIPIENTS,
                  Slots.CONSTSUM_POINTS_PER_OPTION, Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMPOINTSPEROPTION,
                  Slots.CONSTSUM_PARAM_POINTS, Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMPOINTS,
                  Slots.CONSTSUM_PARAM_POINTSFOREACHOPTION, Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMPOINTSFOREACHOPTION,
                  Slots.CONSTSUM_PARAM_POINTSFOREACHRECIPIENT,
                          Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMPOINTSFOREACHRECIPIENT,
                  Slots.CONSTSUM_PARAM_DISTRIBUTE_UNEVENLY, Const.ParamsNames.FEEDBACK_QUESTION_CONSTSUMDISTRIBUTEUNEVENLY);
  
      }
  
      @Override
      public String getNewQuestionSpecificEditFormHtml() {
          // Add two empty options by default
          this.numOfConstSumOptions = 2;
          this.constSumOptions.add("");
          this.constSumOptions.add("");
  
          return "<div id=\"constSumForm\">"
                    + this.getQuestionSpecificEditFormHtml(-1)
               + "</div>";
      }
  
      @Override
      public String getQuestionAdditionalInfoHtml(int questionNumber,
              String additionalInfoId) {
          StringBuilder optionListHtml = new StringBuilder();
          String optionFragmentTemplate = FormTemplates.MSQ_ADDITIONAL_INFO_FRAGMENT;
          StringBuilder additionalInfo = new StringBuilder();
  
          if (distributeToRecipients) {
              additionalInfo.append(getQuestionTypeDisplayName()).append("<br>");
          } else if (numOfConstSumOptions > 0) {
              optionListHtml.append("<ul style=\"list-style-type: disc;margin-left: 20px;\" >");
  