package com.twilio.survey.controllers;

import com.twilio.survey.Server;
import com.twilio.survey.models.IncomingCall;
import com.twilio.survey.models.Question;
import com.twilio.survey.models.Response;
import com.twilio.survey.models.SurveyService;
import com.twilio.survey.models.Survey;

import com.twilio.sdk.verbs.Gather;
import com.twilio.sdk.verbs.Hangup;
import com.twilio.sdk.verbs.Record;
import com.twilio.sdk.verbs.Say;
import com.twilio.sdk.verbs.TwiMLException;
import com.twilio.sdk.verbs.TwiMLResponse;

import freemarker.cache.ClassTemplateLoader;
import freemarker.template.Configuration;

import spark.ModelAndView;
import spark.Route;
import spark.Spark;
import spark.template.freemarker.FreeMarkerEngine;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;

public class SurveyController {
  private static SurveyService surveys = new SurveyService(Server.config.getMongoURI());
  private static FreeMarkerEngine templateEngine;

  // Configure and attach FreeMarker template engine to the class variable for easy access in route
  // definitions.
  public static void initializeTemplateEngine() {
    templateEngine = new FreeMarkerEngine();
    Configuration freeMarkerConfig = new Configuration();
    freeMarkerConfig.setTemplateLoader(new ClassTemplateLoader(SurveyService.class, "/"));
    templateEngine.setConfiguration(freeMarkerConfig);
  };

  // Render landing page.
  public static Route index = (req, res) -> {
    initializeTemplateEngine();

    // Create template keys/values
      Map<String, Object> templateValues = new HashMap<>();
      templateValues.put("greeting", "Ahoy hoy!");

      return templateEngine.render(new ModelAndView(templateValues, "index.ftl"));
    };

  // Main interview loop.
  public static Route interview = (request, response) -> {
    IncomingCall call = new IncomingCall(parseBody(request.body()));
    TwiMLResponse twiml = new TwiMLResponse();
    Survey existingSurvey = surveys.getSurvey(call.getFrom());
    if (call.getInput() == null) {
      twiml.append(new Say("An error occurred. Please try again."));
      twiml.append(new Hangup());
    } else if (existingSurvey == null) {
      Survey survey = surveys.createSurvey(call.getFrom());
      twiml.append(new Say("Thanks for taking our survey."));
      continueSurvey(survey, twiml);
    } else if (!existingSurvey.isDone()) {
      existingSurvey.appendResponse(new Response(call.getInput()));
      surveys.updateSurvey(existingSurvey);
      continueSurvey(existingSurvey, twiml);
    } else {
      twiml.append(new Say("Your responses have been recorded. Thank you for your time!"));
    }
    return twiml.toXML();
  };

  // Helper methods
  private static String continueSurvey(Survey survey, TwiMLResponse twiml) throws TwiMLException {
    Question q = Server.config.getQuestions()[survey.getIndex()];
    Say say = new Say(q.getText());
    twiml.append(say);
    switch (q.getType()) {
      case "text":
        Say textInstructions =
            new Say("Your response will be recorded after the tone. "
                + "Once you have finished recording, press the #.");
        twiml.append(textInstructions);
        Record text = new Record();
        text.setFinishOnKey("#");
        twiml.append(text);
        break;
      case "boolean":
        Say boolInstructions =
        new Say("Press 1 to respond 'true,' and press 2 to respond 'false.'");
    twiml.append(boolInstructions);
        Gather booleanGather = new Gather();
        booleanGather.setNumDigits(1);
        twiml.append(booleanGather);
        break;
      case "number":
        Say numInstructions =
        new Say("Enter the number on your keypad, followed by the #.");
    twiml.append(numInstructions);
        Gather numberGather = new Gather();
        numberGather.setNumDigits(3);
        twiml.append(numberGather);
        break;
    }
    return twiml.toXML();
  }

  public static Map<String, String> parseBody(String body) throws UnsupportedEncodingException {
    String[] unparsedParams = body.split("&");
    Map<String, String> parsedParams = new HashMap<String, String>();
    for (int i = 0; i < unparsedParams.length; i++) {
      String[] param = unparsedParams[i].split("=");
      if (param.length == 2) {
        parsedParams
            .put(URLDecoder.decode(param[0], "utf-8"), URLDecoder.decode(param[1], "utf-8"));
      } else if (param.length == 1) {
        parsedParams.put(URLDecoder.decode(param[0], "utf-8"), "");
      }
    }
    return parsedParams;
  }
}

@@ -2055,153 +2055,8 @@
  if 
-(call.getInput() == null) %7B%0A      twiml.append(new Say(%22An error occurred. Please try again.%22));%0A      twiml.append(new Hangup());%0A    %7D else if 
 (exi
@@ -2600,29 +2600,31 @@
 methods%0A  pr
-ivate
+otected
  static Stri
@@ -2715,16 +2715,23 @@
 estion q
+uestion
  = Serve
@@ -2797,16 +2797,23 @@
 ew Say(q
+uestion
 .getText
@@ -2853,16 +2853,23 @@
 witch (q
+uestion
 .getType
@@ -3344,24 +3344,28 @@
 'false.'%22);%0A
+    
     twiml.ap
@@ -3570,32 +3570,24 @@
 structions =
-%0A       
  new Say(%22En
@@ -3635,24 +3635,28 @@
 y the #.%22);%0A
+    
     twiml.ap

Create test for interview handler.