package org.dspace.app.webui.servlet.cas;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.sql.SQLException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sourceforge.fenixedu.integration.client.FenixClient;
import net.sourceforge.fenixedu.integration.client.FenixClientException;
import net.sourceforge.fenixedu.integration.client.UserInformation;

import org.apache.log4j.Logger;
import org.dspace.app.webui.servlet.DSpaceServlet;
import org.dspace.app.webui.util.Authenticate;
import org.dspace.app.webui.util.JSPManager;
import org.dspace.authorize.AuthorizeException;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;

import edu.yale.its.tp.cas.client.CASAuthenticationException;
import edu.yale.its.tp.cas.client.CASReceipt;
import edu.yale.its.tp.cas.client.ProxyTicketValidator;

/**
 * 
 * @author naat
 * 
 */
public class CASLoginServlet extends DSpaceServlet {
    /** log4j logger */
    private static Logger log = Logger.getLogger(CASLoginServlet.class);

    protected void doDSGet(Context context, HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException, SQLException, AuthorizeException {

        boolean abort = false;

        try {
            CASReceipt receipt = (CASReceipt) getCASReceipt(request.getParameter("ticket"));
            String username = receipt.getUserName();

            UserInformation userInformation = null;
            try {
                userInformation = FenixClient.getUserInformation(username);
            } catch (FenixClientException e) {
                JSPManager.showJSP(request, response, "/login/cas-incorrect.jsp");
                abort = true;
                return;
            }

            if (userInformation.getUniqueUsername() == null) {
                request.setAttribute("uniqueUsernameRequired", true);
                JSPManager.showJSP(request, response, "/login/cas-incorrect.jsp");
                abort = true;
                return;
            }

            if (userInformation.getEmail() == null) {
                request.setAttribute("emailIsRequired", true);
                JSPManager.showJSP(request, response, "/login/cas-incorrect.jsp");
                abort = true;
                return;
            }

            // Locate the eperson
            EPerson eperson = EPerson.findByNetid(context, userInformation.getUniqueUsername());

            EPerson personWithSameEmail = EPerson.findByEmail(context, userInformation.getEmail());

            if (personWithSameEmail != null) {

                boolean emailIsAlreadyInUse = true;

                if ((eperson != null) && (personWithSameEmail.getID() == eperson.getID())) {
                    emailIsAlreadyInUse = false;
                }

                if (emailIsAlreadyInUse == true) {
                    request.setAttribute("emailIsAlreadyInUse", true);
                    JSPManager.showJSP(request, response, "/login/cas-incorrect.jsp");
                    abort = true;
                    return;
                }
            }

            context.setIgnoreAuthorization(true);
            if (eperson == null) {

                // Create the eperson because the user was able to login in CAS,
                // since we trust in CAS we know this user
                // is valid
                eperson = EPerson.create(context);
                eperson.setEmail(userInformation.getEmail());
                eperson.setNetid(userInformation.getUniqueUsername());
                eperson.setCanLogIn(true);
                eperson.setRequireCertificate(false);
                eperson.setSelfRegistered(false);
                Authenticate.getSiteAuth().initEPerson(context, request, eperson);
                eperson.update();

            } else {
                eperson.setEmail(userInformation.getEmail());
                eperson.update();
            }

            // / context.commit();
            context.setIgnoreAuthorization(false);

            if (eperson.canLogIn()) {
                // Logged in OK.
                Authenticate.loggedIn(context, request, eperson);

                // resume previous request
                Authenticate.resumeInterruptedRequest(request, response);
            } else {
                JSPManager.showJSP(request, response, "/login/cas-incorrect.jsp");
                abort = true;
            }
        } catch (CASAuthenticationException e) {
            log.info("CAS authentication failed", e);
            JSPManager.showJSP(request, response, "/login/cas-incorrect.jsp");
            abort = true;
        } finally {
            if (abort == true) {
                context.abort();
            } else {
                context.commit();
            }
        }

    }

    private CASReceipt getCASReceipt(final String casTicket) throws CASAuthenticationException,
            UnsupportedEncodingException {
        CASReceipt receipt = null;

        final String casValidateUrl = ConfigurationManager.getProperty("cas.validateUrl");
        final String casServiceUrl = URLEncoder.encode(ConfigurationManager
                .getProperty("cas.serviceUrl"), "UTF-8");

        ProxyTicketValidator pv = new ProxyTicketValidator();
        pv.setCasValidateUrl(casValidateUrl);
        pv.setServiceTicket(casTicket);
        pv.setService(casServiceUrl);
        pv.setRenew(false);

        receipt = CASReceipt.getReceipt(pv);

        return receipt;
    }
}
