@Override
 public Response startConversation() throws NotFoundException {
   String conversationId = conversationManager.getNewConversationId();
   List<Question> topQuestions = topQuestionsStore.getTopQuestions();
   tracking.displayedTopQuestions(conversationId, topQuestions);
   return getOkResponse(new Greeting(conversationId, topQuestions));
 }
 @Override
 public Response getTopQuestions(String conversationId) throws NotFoundException {
   List<Question> topQuestions = topQuestionsStore.getTopQuestions();
   tracking.redisplayedTopQuestions(conversationId, topQuestions);
   return getOkResponse(new TopQuestionsResponse(topQuestions));
 }
  @Override
  public Response askQuestion(String conversationId, MessageRequest message)
      throws NotFoundException {
    logger.entry(message.getMessage());

    if (message.getReferrer() != null) {
      if (message.getReferrer().getSource() == SourceEnum.REFINEMENT
          && message.getReferrer().getMessageId() == null) {
        return getBadRequestResponse(
            "messageId required when referrer source is " + SourceEnum.REFINEMENT);
      }
      if (message.getReferrer().getSource() == null) {
        return getBadRequestResponse("referrer source required when referrer is set");
      }
    }

    if (message.getMessage().length() > MAX_QUESTION_LENGTH) {
      return getBadRequestResponse(
          MessageKey.AQWQAC14004E_question_too_long_1.getMessage(message.getMessage())
              .getFormattedMessage());
    }

    if (service == null) {
      return error(MessageKey.AQWQAC14001E_error_selection_correct_classifier.getMessage());
    }

    List<NLClassifier> classifiers = service.getClassifiers();
    if (classifiers.isEmpty()) {
      return error(MessageKey.AQWQAC14002E_no_classifier_instances.getMessage());
    }

    NLClassifier classifier = null;
    for (NLClassifier potentialClassifier : classifiers) {
      if (potentialClassifier.getStatus().equals(Status.AVAILABLE)) {
        classifier = potentialClassifier;
        break;
      }
    }

    if (classifier == null) {
      return error(MessageKey.AQWQAC14003E_no_available_classifiers.getMessage());
    }

    NLClassiferClassifyResponse classifyResponse = classifier.classify(message.getMessage());

    List<Answer> answers = new ArrayList<Answer>();
    for (NLClassifiedClass classifiedClass : classifyResponse.getClasses()) {
      try {
        answers.add(resolver.resolve(classifiedClass));
      } catch (ResolutionException e) {
        logger.warn(MessageKey.AQWQAC12100W_could_not_resolve_answer_1.getMessage(e.getMessage()));
      }
    }

    List<Answer> previousAnswers = responseCache.get(conversationId);
    responseCache.put(conversationId, answers);

    // If there was no referrer, or if it's a top question, cache this response
    if (message.getReferrer() != null) {
      Answer knownAnswer = null;
      // This is either a refinement question (did you mean) or a top question, so force the correct
      // answer to the top
      if (message.getReferrer().getSource() == SourceEnum.TOP_QUESTION) {
        try {
          knownAnswer = topQuestionsStore.getAnswer(message.getMessage());
        } catch (QuestionNotFoundException | ResolutionException e) {
          logger.warn(MessageKey.AQWQAC12003W_question_not_in_top_question_store.getMessage(), e);
        }
      }
      if (message.getReferrer().getSource() == SourceEnum.REFINEMENT) {
        if (previousAnswers.size() > 0) {
          // Find the refinement question in our previously cached list
          for (Answer previousAnswer : previousAnswers) {
            if (previousAnswer.getCanonicalQuestion().equals(message.getMessage())) {
              knownAnswer = previousAnswer;
              break;
            }
          }
        }
        if (knownAnswer == null) {
          logger.warn(
              MessageKey.AQWQAC12004W_question_not_in_response_cache_1.getMessage(
                  message.getMessage()));
        }
      }
      if (knownAnswer != null) {
        pushAnswerToTop(knownAnswer, answers);
      }
    }

    if (answers.size() > 0) {
      answers = categorizer.categorize(answers);
    }

    String previousMessageId = null;
    if (message.getReferrer() != null) {
      // This is a refinement/suggestion to a high confidence incorrect or low confidence answer.
      // Keep track of the question/response that got us here.
      previousMessageId = message.getReferrer().getMessageId();
    }

    InputMode mode = message.getReferrer() == null ? InputMode.TYPED : InputMode.CLICKED;
    String messageId =
        tracking.questionAsked(
            conversationId, previousMessageId, message.getMessage(), mode, answers);

    return getOkResponse(new MessageResponse(messageId, message.getMessage(), answers));
  }