package massone.web.controllers.common;

import org.infohazard.maverick.flow.ControllerContext;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.beanutils.BeanUtils;

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

import massone.web.filters.PersistenceFilter;
import net.sf.hibernate.Session;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.Transaction;

import java.lang.reflect.InvocationTargetException;

public abstract class AbstractController implements Controller {

    private static Log log = LogFactory.getLog(AbstractController.class);

    protected abstract void initialize() throws Exception;
    protected abstract String execute() throws Exception;

    protected ControllerContext controllerContext;

    private String destination;

    public String go(ControllerContext controllerContext) throws ServletException {

        try {
            this.controllerContext = controllerContext;
            return this.go();
        } catch (Exception e) {
            throw new ServletException(e);
        }

    }

    protected String go() throws Exception {

        log.info("AbstractController.go() started.");

        log.debug("Storing destination.");
        this.destination = this.getRequest().getRequestURI();

        if (this.getRequest().getQueryString() != null) {
            this.destination += "?" + this.getRequest().getQueryString();
        }
        log.debug("Destination stored.");

        log.debug("Setting up model.");
        this.getContext().setModel(this);
        log.debug("Model now contains 'this'.");

        try {
            log.debug("Populating Controller with BeanUtils.");
            BeanUtils.populate(this, this.getRequest().getParameterMap());
            BeanUtils.populate(this, this.getContext().getParams());
            log.debug("Populating Controller with BeanUtils finished.");
        } catch (IllegalAccessException e) {
            log.warn("Populating Controller with BeanUtils failed (IllegalAccessException).");
        } catch (InvocationTargetException e) {
            log.warn("Populating Controller with BeanUtils failed (InvocationTargetException).");
        }

        log.info("AbstractController.go() ended.");

        return this.preprocess();
    }

    protected String preprocess() throws Exception {
        return this.validate();
    }

    protected String validate() throws Exception {
        return this.authenticate();
    }

    protected String authenticate() throws Exception {
        return this.authorize();
    }

    protected String authorize() throws Exception {
        this.initialize();
        return this.execute();
    }

    public String getDestination() {
        return this.destination;
    }

    public ControllerContext getContext() {
        return this.controllerContext;
    }

    public HttpServletRequest getRequest() {
        return this.getContext().getRequest();
    }

    public HttpServletResponse getResponse() {
        return this.getContext().getResponse();
    }

    public HttpSession getSession() {
        return this.getRequest().getSession(true);
    }

    protected Session getHibernateSession() throws HibernateException {
        return PersistenceFilter.getSession();
    }

    protected SessionFactory getHibernateSessionFactory() throws HibernateException {
        return PersistenceFilter.getSessionFactory();
    }

    protected  void rollbackTransaction(Transaction tx) throws HibernateException {
        PersistenceFilter.rollback(tx);
    }

}
