package edu.hawaii.ics415.problem3.fieldcheck.control;

import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Cookie;
import edu.hawaii.ics415.problem3.fieldcheck.Account;
import edu.hawaii.ics415.problem3.fieldcheck.AccountException;
import edu.hawaii.ics415.problem3.fieldcheck.util.ServletUtility;

/**
 * The central servlet that serves as the controller in the MVC pattern for JSP
 * page dispatching.
 *
 * @author   Takuya Yamashita
 */
public class Controller extends HttpServlet {

  /**
   * @param request               The servlet request object.
   * @param response              The servlet response object.
   * @exception ServletException  If problems occur with the request or rsponse.
   * @exception IOException       If problems occur during request forwarding.
   */
  public void doPost(HttpServletRequest request, HttpServletResponse response)
       throws ServletException, IOException {
    //gets commandName from request object.
    String commandName = (String) request.getParameter("CommandName");
    RequestDispatcher dispatcher;

    // if commandName is null, which means request from anywhere except pussing check form button
    // in the problem3.jsp
    if (commandName == null) {

      // resets the errorMessage is empty string for the JSTL.
      request.setAttribute("errorMessage", "");
      // leave all first, last, dob, ssn no star mark.
      setNonStarMark(request);
      // gets each latest value, then set the value into the request object.
      request.setAttribute("firstName", getLatestValue(request, "firstName"));
      request.setAttribute("lastName", getLatestValue(request, "lastName"));
      request.setAttribute("dateOfBirth", getLatestValue(request, "dateOfBirth"));
      request.setAttribute("ssn", getLatestValue(request, "ssn"));

      // set the disptchar to the problem3.jsp, then forward it.
      dispatcher = getServletContext().getRequestDispatcher("/problem3.jsp");
      dispatcher.forward(request, response);
    }
    // if the commandName is "Add", then, sets cookies and try to check the valid characters
    // inside the account object. If all the field is valid, then, forward to Success.jps page.
    else if (commandName.equals("Add")) {
      request.setAttribute("errorMessage", "");
      setNonStarMark(request);

      // get string vlues from request object with names.
      String firstName = (String) request.getParameter("firstName");
      String lastName = (String) request.getParameter("lastName");
      String dateOfBirth = (String) request.getParameter("dateOfBirth");
      String ssn = (String) request.getParameter("ssn");

      // sets alls the values into the cookie.
      setNamesInCookie(request, response, firstName, lastName, dateOfBirth, ssn);
      // sets the latest value to the request object with name as a key.
      request.setAttribute("firstName", getLatestValue(request, "firstName"));
      request.setAttribute("lastName", getLatestValue(request, "lastName"));
      request.setAttribute("dateOfBirth", getLatestValue(request, "dateOfBirth"));
      request.setAttribute("ssn", getLatestValue(request, "ssn"));

      // chekc all the filed is valid inside the account object. the excepion is thrown
      // if an invalid character exists.
      try {
        Account account = new Account(firstName, lastName, dateOfBirth, ssn);
      }
      catch (AccountException e) {
        // finds a specific error message, then set a star mark if the message is found.
        setStarMark(request, e.getMessage());
        request.setAttribute("errorMessage", e.getMessage());
        dispatcher = getServletContext().getRequestDispatcher("/problem3.jsp");
        dispatcher.forward(request, response);
        return;
      }
      dispatcher = getServletContext().getRequestDispatcher("/Success.jsp");
      // Now forward the updated request object on to the page that will be returned to the user.
      dispatcher.forward(request, response);
    }
  }


  /**
   * Dispatches to doPost for processing.
   *
   * @param request               The servlet request.
   * @param response              The servlet response.
   * @exception ServletException  If problems during request/response
   *      processing.
   * @exception IOException       If problems during the forward to the JSP
   *      page.
   */
  public void doGet(HttpServletRequest request, HttpServletResponse response)
       throws ServletException, IOException {
    doPost(request, response);
  }

  /**
   * Provides the way to check which of cookie's values or the value in the
   * request object is the latest value.
   *
   * @param request  The request object from which the value is retrieved with
   *      the name.
   * @param name     The name as a key by with the value is retrieved.
   * @return         The latest value.
   */
  private String getLatestValue(HttpServletRequest request, String name) {

    // If request.getCookies() is null, then returns empty string. Otherwise, returns
    // the value in the cookies retrieving with the name so that the cookieValue holds either value.
    String cookieValue = ServletUtility.getCookie(request.getCookies(), name, "");
    // retrievs the value from the request object with the name as a key.
    String value = (String) request.getAttribute(name);

    // if the value from the request holds a value, return the value.
    if (value != null) {
      return value;
    }
    else {
      return cookieValue;
    }
  }

  /**
   * Sets the starMark attribute of the Controller object if each error message
   * is found in the errorMessage variable. This means that the star mark show
   * up in each JSTL tag in the jsp page if the exception, which deal with
   * invalid character, is thrown.
   *
   * @param request       The request object in which the star mark is set as an
   *      attribute.
   * @param errorMessage  The stirng to store the error message.
   */
  private void setStarMark(HttpServletRequest request, String errorMessage) {
    if (errorMessage.indexOf("First") != -1) {
      request.setAttribute("firstNameStar", "*");
    }
    if (errorMessage.indexOf("Last") != -1) {
      request.setAttribute("lastNameStar", "*");
    }
    if (errorMessage.indexOf("SSN") != -1) {
      request.setAttribute("ssnStar", "*");
    }
    if (errorMessage.indexOf("Date") != -1) {
      request.setAttribute("dateOfBirthStar", "*");
    }
  }

  /**
   * Sets the nonStarMark attribute of the Controller object. Every field in the
   * problem3.jsp is set as empty string so that any message does not show the
   * tag in the jsp page.
   *
   * @param request  The request object in which the attributes are set.
   */
  private void setNonStarMark(HttpServletRequest request) {
    request.setAttribute("firstNameStar", "");
    request.setAttribute("lastNameStar", "");
    request.setAttribute("ssnStar", "");
    request.setAttribute("dateOfBirthStar", "");
  }


  /**
   * Provides the way to set all the fields into cookies respectively at one
   * time.
   *
   * @param request      The request object in which all the fileds are set
   * @param response     The response object in which a cookie is set
   * @param firstName    The firstName attribute to be set in the request object
   * @param lastName     The lastName attribute to be set in the request object
   * @param dateOfBirth  The dateOfBirth attribute to be set in the request
   *      object
   * @param ssn          The ssn attribute to be set in the request object
   */
  private void setNamesInCookie(HttpServletRequest request, HttpServletResponse response,
      String firstName, String lastName, String dateOfBirth, String ssn) {
    // if firstName is not null, then set the firstName into the cookie.
    if (firstName != null) {
      setNameInCookie(request, response, "firstName", firstName);
    }
    // if the firstname is null, then set the empty string into the cookie.
    else {
      setNameInCookie(request, response, "firstName", "");
    }
    if (lastName != null) {
      setNameInCookie(request, response, "lastName", lastName);
    }
    else {
      setNameInCookie(request, response, "lastName", "");
    }
    if (dateOfBirth != null) {
      setNameInCookie(request, response, "dateOfBirth", dateOfBirth);
    }
    else {
      setNameInCookie(request, response, "dateOfBirth", "");
    }
    if (ssn != null) {
      setNameInCookie(request, response, "ssn", ssn);
    }
    else {
      setNameInCookie(request, response, "ssn", "");
    }
  }


  /**
   * Provides the wayt to set a value queried form the name in the rquest object
   * into the cookie. In addtion, set the expire date is 3600 seconds for the
   * demonstration.
   *
   * @param request   The request object in which the value is set.
   * @param response  The response object in which the cookie is set.
   * @param name      The name by which the value is queried from the request
   *      object.
   * @param value     The value to be stored in the cookie
   */
  private void setNameInCookie(HttpServletRequest request, HttpServletResponse response,
      String name, String value) {
    request.setAttribute(name, value);

    Cookie cookie = new Cookie(name, value);

    cookie.setMaxAge(3600);
    // sets the expiration time as 3600 seconds.
    response.addCookie(cookie);
  }
}