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

    cursor = results.getCursor();

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

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

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

    sortInstructorResultList();

    return this;
  }
  // Search in index for a query
  private CursorPage<DProduct, String> searchInIndexWithQuery(
      com.google.appengine.api.search.Query query, Index index) {

    CursorPage<DProduct, String> cursorPage = null;

    try {
      // Query the index.
      Results<ScoredDocument> results = index.search(query);

      // Collect all the primary keys
      Collection<String> ids = new ArrayList<String>();
      for (ScoredDocument document : results) {
        ids.add(document.getId());
      }

      if (ids.size() != 0) {
        // We got results, get the places from datastore
        Iterator<DProduct> dProductIterator = queryByPrimaryKeys(null, ids).iterator();

        Collection<DProduct> dProducts = new ArrayList<DProduct>(ids.size());
        while (dProductIterator.hasNext()) {
          dProducts.add(dProductIterator.next());
        }

        // Build a cursor page
        cursorPage = new CursorPage<DProduct, String>();
        cursorPage.setCursorKey(results.getCursor().toWebSafeString());
        cursorPage.setItems(dProducts);
      }
    } catch (SearchException e) {
      if (StatusCode.TRANSIENT_ERROR.equals(e.getOperationResult().getCode())) {
        LOG.error("Search index failed");
        // TODO: Error handling missing
      }
      throw new SearchException("Searching index failed");
    }

    return cursorPage;
  }
  /**
   * Produce a FeedbackResponseCommentSearchResultBundle from the Results<ScoredDocument>
   * collection. The list of InstructorAttributes is used to filter out the search result.
   */
  public FeedbackResponseCommentSearchResultBundle fromResults(
      Results<ScoredDocument> results, List<InstructorAttributes> instructors) {
    if (results == null) {
      return this;
    }

    // get instructor's information
    instructorEmails = new HashSet<String>();
    instructorCourseIdList = new HashSet<String>();
    for (InstructorAttributes ins : instructors) {
      instructorEmails.add(ins.email);
      instructorCourseIdList.add(ins.courseId);
    }

    cursor = results.getCursor();
    List<ScoredDocument> filteredResults = filterOutCourseId(results, instructors);
    for (ScoredDocument doc : filteredResults) {
      // get FeedbackResponseComment from results
      FeedbackResponseCommentAttributes comment =
          JsonUtils.fromJson(
              doc.getOnlyField(Const.SearchDocumentField.FEEDBACK_RESPONSE_COMMENT_ATTRIBUTE)
                  .getText(),
              FeedbackResponseCommentAttributes.class);
      if (frcLogic.getFeedbackResponseComment(comment.getId()) == null) {
        frcLogic.deleteDocument(comment);
        continue;
      }
      comment.sendingState = CommentSendingState.SENT;
      List<FeedbackResponseCommentAttributes> commentList =
          comments.get(comment.feedbackResponseId);
      if (commentList == null) {
        commentList = new ArrayList<FeedbackResponseCommentAttributes>();
        comments.put(comment.feedbackResponseId, commentList);
      }
      commentList.add(comment);

      // get related response from results
      FeedbackResponseAttributes response =
          JsonUtils.fromJson(
              doc.getOnlyField(Const.SearchDocumentField.FEEDBACK_RESPONSE_ATTRIBUTE).getText(),
              FeedbackResponseAttributes.class);
      if (frLogic.getFeedbackResponse(response.getId()) == null) {
        frcLogic.deleteDocument(comment);
        continue;
      }
      List<FeedbackResponseAttributes> responseList = responses.get(response.feedbackQuestionId);
      if (responseList == null) {
        responseList = new ArrayList<FeedbackResponseAttributes>();
        responses.put(response.feedbackQuestionId, responseList);
      }
      if (!isAdded.contains(response.getId())) {
        isAdded.add(response.getId());
        responseList.add(response);
      }

      // get related question from results
      FeedbackQuestionAttributes question =
          JsonUtils.fromJson(
              doc.getOnlyField(Const.SearchDocumentField.FEEDBACK_QUESTION_ATTRIBUTE).getText(),
              FeedbackQuestionAttributes.class);
      if (fqLogic.getFeedbackQuestion(question.getId()) == null) {
        frcLogic.deleteDocument(comment);
        continue;
      }
      List<FeedbackQuestionAttributes> questionList = questions.get(question.feedbackSessionName);
      if (questionList == null) {
        questionList = new ArrayList<FeedbackQuestionAttributes>();
        questions.put(question.feedbackSessionName, questionList);
      }
      if (!isAdded.contains(question.getId())) {
        isAdded.add(question.getId());
        questionList.add(question);
      }

      // get related session from results
      FeedbackSessionAttributes session =
          JsonUtils.fromJson(
              doc.getOnlyField(Const.SearchDocumentField.FEEDBACK_SESSION_ATTRIBUTE).getText(),
              FeedbackSessionAttributes.class);
      if (fsLogic.getFeedbackSession(session.getSessionName(), session.getCourseId()) == null) {
        frcLogic.deleteDocument(comment);
        continue;
      }
      if (!isAdded.contains(session.getFeedbackSessionName())) {
        isAdded.add(session.getFeedbackSessionName());
        sessions.put(session.getSessionName(), session);
      }

      // get giver and recipient names
      String responseGiverName =
          extractContentFromQuotedString(
              doc.getOnlyField(Const.SearchDocumentField.FEEDBACK_RESPONSE_GIVER_NAME).getText());
      responseGiverTable.put(response.getId(), getFilteredGiverName(response, responseGiverName));

      String responseRecipientName =
          extractContentFromQuotedString(
              doc.getOnlyField(Const.SearchDocumentField.FEEDBACK_RESPONSE_RECEIVER_NAME)
                  .getText());
      responseRecipientTable.put(
          response.getId(), getFilteredRecipientName(response, responseRecipientName));

      String commentGiverName =
          extractContentFromQuotedString(
              doc.getOnlyField(Const.SearchDocumentField.FEEDBACK_RESPONSE_COMMENT_GIVER_NAME)
                  .getText());
      commentGiverTable.put(
          comment.getId().toString(),
          getFilteredCommentGiverName(response, comment, commentGiverName));
      numberOfCommentFound++;
    }

    for (List<FeedbackQuestionAttributes> questions : this.questions.values()) {
      Collections.sort(questions);
    }

    for (List<FeedbackResponseAttributes> responses : this.responses.values()) {
      FeedbackResponseAttributes.sortFeedbackResponses(responses);
    }

    for (List<FeedbackResponseCommentAttributes> responseComments : this.comments.values()) {
      FeedbackResponseCommentAttributes.sortFeedbackResponseCommentsByCreationTime(
          responseComments);
    }

    return this;
  }