package com.fitbank.web.servlets;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;

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

import com.fitbank.util.CaseInsensitiveMap;
import com.fitbank.util.Debug;
import com.fitbank.util.Servicios;
import com.fitbank.web.EntornoWeb;
import com.fitbank.web.ManejoExcepcion;
import com.fitbank.web.Proceso;
import com.fitbank.web.RevisarSeguridad;
import com.fitbank.web.annotations.Handler;
import com.fitbank.web.data.PedidoWeb;
import com.fitbank.web.data.RespuestaWeb;
import com.fitbank.web.exceptions.ErrorWeb;
import com.fitbank.web.procesos.Registro;

/**
 * Clase Procesador. Servlet que procesa los Pedidos Web.
 * 
 * @author FitBank JT, CI
 * @version 2.0
 */
public class Procesador extends HttpServlet {

    private static final long serialVersionUID = 2L;

    private static final Map<String, Proceso> procesos = new CaseInsensitiveMap<Proceso>();

    private static String mode = "";

    static {
        mode = System.getProperty("fitbank.test.mode", "");
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        Locale.setDefault(new Locale(ResourceBundle.getBundle("config")
                .getString("locale")));

        for (Proceso proceso : Servicios.load(Proceso.class)) {
            Handler handler = proceso.getClass().getAnnotation(Handler.class);

            if (handler != null) {
                Debug.debug("Registrando " + handler.value() + " ["
                        + proceso.getClass().getName() + "]");
                procesos.put(handler.value(), proceso);
            } else {
                Debug.info("La clase " + proceso.getClass().getName()
                        + " no tiene anotacion @Handler");
            }
        }

        super.init(config);
    }

    @Override
    protected void service(HttpServletRequest httpServletRequest,
            HttpServletResponse httpServletResponse) throws ServletException,
            IOException {
        try {
            httpServletRequest.setCharacterEncoding("UTF-8");
        } catch (UnsupportedEncodingException ex) {
            // No debería fallar, si no hay soporte de utf-8 estamos mal
            throw new RuntimeException(ex);
        }

        PedidoWeb pedido = null;
        RespuestaWeb respuesta = null;

        Proceso proceso = null;
        try {
            EntornoWeb.init(httpServletRequest);
            pedido = new PedidoWeb(httpServletRequest, httpServletResponse);

            // Obtener proceso
            proceso = procesos.get(pedido.getTipoPedido());

            if (proceso == null) {
                throw new ErrorWeb("No existe manejador para el proceso: "
                        + pedido.getTipoPedido());
            }

            if (proceso.getClass().isAnnotationPresent(RevisarSeguridad.class)) {
                revisarSeguridad();
            }

            Registro.crearRegistro(pedido.getTipoPedido());
            Registro.getRegistro().salvarRequest(httpServletRequest);
            EntornoWeb.getContexto().getPaginacion().setPaginacion(pedido);

            // Enviar pedido al proceso elegido
            respuesta = proceso.procesar(pedido);

            if (respuesta != null) {
                respuesta.escribir();
            } else {
                throw new ErrorWeb("No hay respuesta!");
            }
        } catch (Throwable t) {
            try {
                Registro.getRegistro().setEstado(
                        Registro.Estado.ERROR.toString());
                Registro.getRegistro().salvarDatosActuales(pedido.getTransporteDB());

                respuesta = ManejoExcepcion.procesar(proceso, pedido,
                        respuesta, httpServletResponse, t);

                respuesta.escribir();
            } catch (Throwable t1) {
                Debug.error("ERROR TOTAL", t1);
                Debug.error("ERROR ORIGINAL", t);
            }
        }

        Registro.getRegistro().salvarResponse(httpServletResponse);
    }

    public void revisarSeguridad() throws SecurityException {
        if (!EntornoWeb.existeUsuario()) {
            throw new SecurityException("No hay usuario");
        }
    }

    public static String getMode() {
        return mode;
    }

    public static void setMode(String mode) {
        Procesador.mode = mode;
    }

}
