private static ArrayList<SurveyAnswer> convertToSurveyAnswers(
      String[] answers, SurveyQuestion question) throws SurveyParseException {
    ArrayList<SurveyAnswer> surveyAnswers = new ArrayList<SurveyAnswer>();
    SurveyAnswerFactory answerFactory = new SurveyAnswerFactory();
    SurveyAnswer answerObj;
    for (String answer : answers) {
      answerObj = answerFactory.getSurveyAnswer(question.getQuestionType(), answer);

      if (answerObj == null) return null;
      else surveyAnswers.add(answerObj);
    }
    return surveyAnswers;
  }
  /** @return the next url to go to, excluding contextPath */
  public static ModelAndView execute(
      HttpServletRequest request,
      String documentId,
      TapestryPHRSurvey currentSurvey,
      PHRSurvey templateSurvey)
      throws Exception {
    ModelAndView m = new ModelAndView();
    final String questionId = request.getParameter("questionid");
    String direction = request.getParameter("direction");
    String observerNotes = request.getParameter("observernote");

    if (direction == null) direction = "forward";

    if (documentId == null) {
      logger.error("no selected survey? documentId=" + documentId);
      m.setViewName("failed");
      return m;
    }

    String[] answerStrs = request.getParameterValues("answer");

    String nextQuestionId = questionId;
    // if requested survey does not exist
    if (currentSurvey == null) {
      logger.error("Cannot find requested survey. documentId=" + documentId);
      m.setViewName("failed");
      return m;
    }
    // if requested survey is completed
    if (currentSurvey.isComplete()) logger.error("trying to complete already completed survey?");

    boolean saved = false;

    // if starting/continuing survey, clear session
    if (questionId == null) {
      // if just starting/continuing(from before) the survey, direct to last question
      String lastQuestionId;

      if (currentSurvey.getQuestions().size() == 0) {
        boolean moreQuestions = addNextQuestion(null, currentSurvey, templateSurvey);
        if (!moreQuestions) {
          logger.error("Survey has no questions?");
          m.setViewName("failed");
          return m;
        }
      }

      if (currentSurvey.isComplete()) { // if complete show first question		
        lastQuestionId = currentSurvey.getQuestions().get(0).getId();
        m.addObject("hideObservernote", true);
      } else { // if not complete show next question
        lastQuestionId =
            currentSurvey.getQuestions().get(currentSurvey.getQuestions().size() - 1).getId();
        // logic for displaying Observer Notes button
        if (isFirstQuestionId(lastQuestionId, '0')) m.addObject("hideObservernote", true);
        else m.addObject("hideObservernote", false);
      }
      m.addObject("survey", currentSurvey);
      m.addObject("templateSurvey", templateSurvey);
      m.addObject("questionid", lastQuestionId);
      m.addObject("resultid", documentId);

      m.setViewName("/surveys/show_survey");

      return m;
    } // end of questionId == null;

    String errMsg = null;

    // if continuing survey (just submitted an answer)
    if (questionId != null && direction.equalsIgnoreCase("forward")) {
      if (currentSurvey
              .getQuestionById(questionId)
              .getQuestionType()
              .equals(SurveyQuestion.ANSWER_CHECK)
          && answerStrs == null) answerStrs = new String[0];

      if (answerStrs != null
          && (currentSurvey
                  .getQuestionById(questionId)
                  .getQuestionType()
                  .equals(SurveyQuestion.ANSWER_CHECK)
              || !answerStrs[0].equals(""))) {
        SurveyQuestion question = currentSurvey.getQuestionById(questionId);
        SurveyQuestion questionWithoutObserverNotes = currentSurvey.getQuestionById(questionId);

        // keep answers without obserbernotes for validation
        //				ArrayList<SurveyAnswer> answersWithoutObserverNotes =
        // convertToSurveyAnswers(answerStrs, questionWithoutObserverNotes);
        //
        //				//add observernotes into answer when there is no condition or non-number type input
        //				List<SurveyDirectionStatement> logicStatements = question.getNextQuestionLogic();
        //				String type = question.getQuestionType();

        String questionText = question.getQuestionText();

        if (!Utils.isNullOrEmpty(questionText)) {
          String separator = "/observernote/ ";
          StringBuffer sb = new StringBuffer();
          sb.append(questionText);
          sb.append(separator);
          sb.append(observerNotes);

          questionText = sb.toString();
          question.setQuestionText(questionText);
        }

        //				if (!Utils.isNullOrEmpty(type) && (!type.equalsIgnoreCase("number")) &&
        // (logicStatements.size() <= 1))
        //				{
        //					if (answerStrs.length == 1)
        //					{
        //						String content = answerStrs[0];
        //						String separator = "/observernote/ ";
        //						StringBuffer sb = new StringBuffer();
        //						sb.append(content);
        //						sb.append(separator);
        //						sb.append(observerNotes);
        //						answerStrs[0] = sb.toString();
        //					}
        //				}

        ArrayList<SurveyAnswer> answers = convertToSurveyAnswers(answerStrs, question);

        boolean goodAnswerFormat = true;
        if (answers == null) goodAnswerFormat = false;

        // check each answer for validation
        // if answer passes validation
        //			if (goodAnswerFormat && question.validateAnswers(answersWithoutObserverNotes))
        if (goodAnswerFormat && question.validateAnswers(answers)) {
          boolean moreQuestions;
          // see if the user went back (if current question the last question in user's question
          // profile)
          if (!currentSurvey
              .getQuestions()
              .get(currentSurvey.getQuestions().size() - 1)
              .equals(question)) {
            ArrayList<SurveyAnswer> existingAnswers =
                currentSurvey.getQuestionById(questionId).getAnswers();
            // if user hit back, and then forward, and answer wasn't changed
            if (StringUtils.join(answerStrs, ", ").equals(StringUtils.join(existingAnswers, ", "))
                || currentSurvey.isComplete()) {
              logger.debug("user hit back and went forward, no answer was changed");
              moreQuestions = true;
              // if the user hit "back" and changed the answer - remove all questions after it
            } else {
              ArrayList<SurveyQuestion> tempquestions =
                  new ArrayList<
                      SurveyQuestion>(); // Create a temp array list to transfer answered questions

              // remove all future answers
              logger.debug("user hit back and changed an answer");
              // clear all questions following it
              int currentSurveySize =
                  currentSurvey.getQuestions().size(); // stores number of questions
              int currentQuestionIndex =
                  currentSurvey.getQuestions().indexOf(question); // gets the current question index

              for (int i = currentQuestionIndex + 1; i < currentSurveySize; i++) {
                tempquestions.add(currentSurvey.getQuestions().get(currentQuestionIndex + 1));
                currentSurvey
                    .getQuestions()
                    .remove(
                        currentQuestionIndex
                            + 1); // goes through quesitons list and removes each question after it
              }
              // save answers modified/input by user into question
              question.setAnswers(answers);
              saved = true;
              // add new question
              moreQuestions = addNextQuestion(questionId, currentSurvey, templateSurvey);

              // check if old index and new index contain same questions in the same list
              int sizeofcurrentquestionslist =
                  currentSurvey
                      .getQuestions()
                      .size(); // Size of new getQuestions aftre removing future questions

              if (currentSurvey
                  .getQuestions()
                  .get(sizeofcurrentquestionslist - 1)
                  .getId()
                  .equals(tempquestions.get(0).getId())) {
                currentSurvey.getQuestions().remove(sizeofcurrentquestionslist - 1);
                for (int y = 0; y < tempquestions.size(); y++)
                  currentSurvey.getQuestions().add(tempquestions.get(y));
                moreQuestions = addNextQuestion(questionId, currentSurvey, templateSurvey);
              }
              // if same then replace temp list with new list
              // if not then add the one new item.
            }
            // if user didn't go back, and requesting the next question
          } else {
            logger.debug("user hit forward, and requested the next question");
            question.setAnswers(answers);
            saved = true;
            moreQuestions = addNextQuestion(questionId, currentSurvey, templateSurvey);
          }
          // finished survey
          if (!moreQuestions) {
            if (!currentSurvey.isComplete()) {
              SurveyAction.updateSurveyResult(currentSurvey);

              m.addObject("survey_completed", true);
              m.addObject("survey", currentSurvey);
              m.addObject("templateSurvey", templateSurvey);
              m.addObject("questionid", questionId);
              m.addObject("resultid", documentId);
              m.addObject("message", "SURVEY FINISHED - Please click END SURVEY");
              m.addObject("hideObservernote", false);
              m.setViewName("/surveys/show_survey");
              return m;
            } else {
              m.addObject("survey", currentSurvey);
              m.addObject("templateSurvey", templateSurvey);
              m.addObject("questionid", questionId);
              m.addObject("resultid", documentId);
              m.addObject("message", "End of Survey");
              m.addObject("hideObservernote", false);
              m.setViewName("/surveys/show_survey");
              return m;
            }
          }
          int questionIndex = currentSurvey.getQuestionIndexbyId(questionId);
          nextQuestionId = currentSurvey.getQuestions().get(questionIndex + 1).getId();
          logger.debug("Next question id: " + nextQuestionId);

          // save to indivo
          if (saved && questionIndex % SAVE_INTERVAL == 0 && !currentSurvey.isComplete())
            SurveyAction.updateSurveyResult(currentSurvey);

          // if answer fails validation
        } // end of validation answers
        else {
          m.addObject("survey", currentSurvey);
          m.addObject("templateSurvey", templateSurvey);
          m.addObject("questionid", questionId);
          m.addObject("resultid", documentId);

          if (question.getRestriction() != null
              && question.getRestriction().getInstruction() != null)
            m.addObject("message", question.getRestriction().getInstruction());
          m.addObject("hideObservernote", false);
          m.setViewName("/surveys/show_survey");
          return m;
        }
        // if answer not specified, and hit forward
      } else errMsg = "You must supply an answer";
    } // end of forward action
    else if (direction.equalsIgnoreCase("backward")) {
      int questionIndex = currentSurvey.getQuestionIndexbyId(questionId);
      if (questionIndex > 0)
        nextQuestionId = currentSurvey.getQuestions().get(questionIndex - 1).getId();
    }

    // backward to the description page(before the first qustion)
    if ((questionId != null)
        && ("backward".equals(direction))
        && (isFirstQuestionId(questionId, '0'))) m.addObject("hideObservernote", true);
    else m.addObject("hideObservernote", false);

    m.addObject("survey", currentSurvey);
    m.addObject("templateSurvey", templateSurvey);
    m.addObject("questionid", nextQuestionId);
    m.addObject("resultid", documentId);
    if (errMsg != null) m.addObject("message", errMsg);

    m.setViewName("/surveys/show_survey");
    return m;
  }