/*
 * This file is part of DebGen Biobank Software developed by ASTRID Research.
 * All rights reserved. Reproduction, modification, use or disclosure
 * to third parties without express authority is forbidden.
 *
 * Copyright ASTRID Research Inc., Hungary, 2009-2011.
 *
 * ASTRID Research
 * Headquaters: Csapo utca 42. Debrecen H-4029 HUNGARY
 * Phone: +36-52-533-173        Fax: +36-52-533-174
 * Web: http://www.astrid.hu    E-mail: info@astrid.hu
 *
 * Project name: DebGen Biobank Software project.
 * URLS:
 * Developers: Istvan Zoltan Nagy (istvan.nagy@astrid.hu)
 */
package hu.astrid.debgen.authentication.servlet;

import elements.Functions;
import hu.astrid.debgen.authentication.domain.DebGenUser;
import hu.astrid.debgen.authentication.exception.AuthenticationFailedException;
import hu.astrid.debgen.authentication.exception.InvalidPasswordException;
import hu.astrid.debgen.authentication.facade.AuthenticationFacade;
import hu.astrid.debgen.exception.ServerSideException;
import hu.astrid.debgen.exception.ValidationFailedException;
import hu.astrid.debgen.server.requestprocessor.ActionParameter;
import hu.astrid.debgen.server.requestprocessor.RequestTokenizer;
import hu.astrid.debgen.server.requestprocessor.exception.FormFillException;
import org.apache.log4j.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * This servlet handles all authentication requests such as login, logout, passchange
 * @author inagy
 */
public class AuthenticationServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    /**
     * The logger
     */
    static Logger logger = Logger.getLogger(AuthenticationServlet.class);

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        logger.debug("doPost() called.");
        ActionParameter actionParameter = ActionParameter.getActionParameter(request);
        logger.debug(actionParameter);
        logger.debug(RequestTokenizer.getRequestData(request));
        String action = actionParameter.getAction();
        try {
            if (action.equals("login")) {
                authenticate(request, response);
            } else if (action.equals("changepassword")) {
                changePassword(request, response);
            } else if (action.equals("savelanguage")) {
                changeLanguage(request, response);
            } else if (action.equals("logout")) {
                logout(request, response);
            } else {
                response.sendRedirect("index.html");
            }
        } catch (Exception ex) {
            request.setAttribute("answer", true);
            request.setAttribute("globalexception", new ServerSideException("A kért erőforrás nem található, vagy a hivatkozás hibás.")); //i18
            request.getRequestDispatcher("index.jsp").forward(request, response);

        }
    }

    /**
     * Authenticates the User.
     * @param request The HttpRequest which contains the login forms data
     * @param response The HttpResponse of this operation
     * @throws Exception When something abnormal happens e.g. DB fail
     */
    public void authenticate(HttpServletRequest request, HttpServletResponse response) throws Exception {
        logger.debug("authenticate() called.");
        String userName = Functions.encodeString(request.getParameter("username"));
        String password = Functions.encodeString(request.getParameter("password"));
        logger.info("Authenticate User[" + userName + "]...");
        DebGenUser user = null;
        request.setAttribute("answer", true);
        if (request.getParameter("username") == null &&
                request.getParameter("password") == null) {
            response.sendRedirect("index.html");
            return;
        }
        try {
            user = new AuthenticationFacade().authenticate(new DebGenUser(userName, Functions.hashMD5(password)));
            request.getSession(true).setAttribute("user", user);
            DebGenUser.checkData(userName, password);
            if (user.isMustChangePass()) {
                request.getSession().setAttribute("passwordchange", true);
            }
        } catch (InvalidPasswordException pex) {
            logger.error(pex);
            request.getSession().setAttribute("passwordchange", true);
            request.getRequestDispatcher("index.jsp").forward(request, response);
            return;
        } catch (AuthenticationFailedException aex) {
            logger.error(aex);
            request.setAttribute("exception", new ServerSideException("A bejelentkezés sikertelen. Nem létezik ilyen felhasználói nevű felhasználó ezzel a jelszóval. Kérem ellenőrizze a felhasználói nevét és jelszavát, majd próbálja újra.")); //i18
            request.getRequestDispatcher("index.jsp").forward(request, response);
            return;
        } catch (Exception ex) {
            logger.error(ex);
            throw ex;
        }
        logger.info("Authenticate User[" + userName + "]...Successful");
        request.setAttribute("renew", "true");
        response.sendRedirect("index.html");
        return;
    }

    /**
     * Logs out the User.
     * @param request The HttpRequest of this operation
     * @param response The HttpResponse of this operation
     * @throws Exception When something abnormal happens e.g. DB fail
     */
    public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException {
        logger.debug("logout() called.");
        request.setAttribute("isresp", true);
        request.getSession(true).removeAttribute("user");
        request.getSession().invalidate();
        response.sendRedirect("index.html");
        return;
    }

    /**
     * Changes the password of the User.
     * @param request The HttpRequest which contains the password change forms data
     * @param response The HttpResponse of this operation
     * @throws Exception When something abnormal happens e.g. DB fail
     */
    public void changePassword(HttpServletRequest request, HttpServletResponse response) throws Exception {
        logger.debug("changePassword() called.");
        DebGenUser user = ActionParameter.getUser(request);
        if (request.getParameter("oldpassword") == null &&
                request.getParameter("newpassword") == null &&
                request.getParameter("newpasswordretry") == null) {
            request.setAttribute("answer", true);
            request.getRequestDispatcher("index.jsp").forward(request, response);
            return;
        }
        String oldPassword = Functions.encodeString(request.getParameter("oldpassword"));
        String newPassword = Functions.encodeString(request.getParameter("newpassword"));
        String newPasswordRetry = Functions.encodeString(request.getParameter("newpasswordretry"));
        String newEmail = Functions.encodeString(request.getParameter("email"));
        String newFullName = Functions.encodeString(request.getParameter("fullname"));

        try {
            new AuthenticationFacade().changePassword(user, oldPassword, newPassword, newPasswordRetry, newFullName, newEmail);
            request.getSession().removeAttribute("passwordchange");
            response.sendRedirect("index.html");
        } catch (FormFillException ex) {
            logger.error(ex);
            request.setAttribute("exception", new ServerSideException(ex));
            request.setAttribute("answer", true);
            request.getRequestDispatcher("index.jsp").forward(request, response);
            return;
        } catch (InvalidPasswordException ex) {
            logger.error(ex);
            request.setAttribute("exception", new ServerSideException(ex));
            request.setAttribute("answer", true);
            request.getRequestDispatcher("index.jsp").forward(request, response);
            return;
        }catch (ValidationFailedException ex) {
            logger.error(ex);
            request.setAttribute("exception", new ServerSideException(ex));
            request.setAttribute("answer", true);
            request.getRequestDispatcher("index.jsp").forward(request, response);
            return;
        }catch (Exception ex) {
            logger.error(ex);
            throw ex;
        }
    }

    private void changeLanguage(HttpServletRequest request, HttpServletResponse response) throws Exception {
        logger.debug("changeLanguage() called.");
        request.setAttribute("answer", true);
        try {
            Long id = 0L;
            DebGenUser user = ActionParameter.getUser(request);
            user.setLanguageCode(Functions.encodeString(request.getParameter("languageCode")));
            new AuthenticationFacade().changeLanguage(user);
            response.sendRedirect("language.html");
        } catch (Exception ex) {
            logger.error(ex);
            throw ex;
        }
    }
}
