package com.fitbank.uci.server.fit;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;

import com.fitbank.common.exception.ExceptionHandler;
import com.fitbank.dto.management.Detail;
import com.fitbank.facade.ejb.FitFacade;
import com.fitbank.facade.ejb.FitFacadeHome;
import com.fitbank.uci.client.UCILogger;
import com.fitbank.uci.common.UCIException;
import com.fitbank.uci.core.fit.FitbankSender;
import com.fitbank.uci.server.ConnectionProcesor;
import com.fitbank.uci.server.Controlador;
import com.fitbank.uci.server.manager.DataAccess;
import com.fitbank.uci.server.manager.DeviceEventTypes;
import com.fitbank.uci.server.manager.ParameterDetail;

public class UCIFitbank extends Controlador {
    private static final String URL = "url";

    private static final String USER = "user";

    private static final String PASSWORD = "password";

    private static final String RMI_INITIAL_CONTEXT = "rmiIC";

    private static final String EJB_JNDI = "ejb_jndi";

    private Map<String, ParameterDetail> parameters;

    private FitFacadeHome facadeHome = null;

    private boolean connected = false;

    private Context ctx = null;

    @Override
    public void disconnect() throws Exception {
        this.ctx.close();
        this.facadeHome = null;
        this.addMessage("Se cierra la conexion con el EJB " + this.parameters.get(EJB_JNDI).getValue(),
                        DeviceEventTypes.DISCONNECT);
    }

    @Override
    public String formatParameters(Map<String, String> pParameters) throws Exception {
        String data = "";
        String aux = pParameters.get(URL);

        if ((aux == null) || (aux.compareTo("") == 0)) {
            throw new UCIException(ERROR_FORMAT_CODE, "URL: VALOR REQUERIDO");
        }
        data += "#" + aux;
        aux = pParameters.get(USER);
        if (aux == null) {
            throw new UCIException(ERROR_FORMAT_CODE, "USER: VALOR REQUERIDO");
        }
        data += "#" + aux;
        aux = pParameters.get(PASSWORD);
        if (aux == null) {
            throw new UCIException(ERROR_FORMAT_CODE, "PASSWORD: VALOR REQUERIDO");
        }
        data += "#" + aux;
        aux = pParameters.get(RMI_INITIAL_CONTEXT);
        if (aux == null) {
            throw new UCIException(ERROR_FORMAT_CODE, "INITIAL CONTEXT: VALOR REQUERIDO");
        }
        data += "#" + aux;
        aux = pParameters.get(EJB_JNDI);
        if (aux == null) {
            throw new UCIException(ERROR_FORMAT_CODE, "JNDI DEL EJB");
        }
        data += "#" + aux;
        return data;
    }

    @Override
    public String getDescription() throws Exception {
        return "Controlador de Acceso a FITBANK";
    }

    @Override
    public String getExtraData() {
        Map<String, Integer> m = FitbankSender.getTCount();
        Integer i = null;

        synchronized (m) {
            i = m.get(this.name);
        }
        if (i == null) {
            i = 0;
        }
        return "Mensajes en vuelo " + i;
    }

    @SuppressWarnings( { UNCHECKED, "PMD.ReplaceHashtableWithMap" })
    private Context getInitialContext() throws Exception {
        Hashtable env = new Hashtable();

        env.put(Context.INITIAL_CONTEXT_FACTORY, this.parameters.get(RMI_INITIAL_CONTEXT).getValue());
        env.put(Context.SECURITY_PRINCIPAL, this.parameters.get(USER).getValue());
        env.put(Context.SECURITY_CREDENTIALS, this.parameters.get(PASSWORD).getValue());
        env.put(Context.PROVIDER_URL, this.parameters.get(URL).getValue());
        env.put("dedicated.rmicontext", "true");

        return new InitialContext(env);
    }

    @Override
    public String getStatus() throws Exception {
        return (this.facadeHome != null) ? "UP" : "DOWN";
    }

    private Map<String, ParameterDetail> initParameters() throws Exception {
        Map<String, ParameterDetail> m = new HashMap<String, ParameterDetail>();
        ParameterDetail d = new ParameterDetail(URL, "URL de Conexi�n", String.class, true);

        m.put(d.getName(), d);
        d = new ParameterDetail(USER, "Usuario", String.class, true);
        m.put(d.getName(), d);
        d = new ParameterDetail(PASSWORD, "Password", String.class, true);
        m.put(d.getName(), d);
        d = new ParameterDetail(RMI_INITIAL_CONTEXT, "RMI Initial Context", String.class, true);
        m.put(d.getName(), d);
        d = new ParameterDetail(EJB_JNDI, "JNDI del EJB de conexion a FIT", String.class, true);
        m.put(d.getName(), d);
        return m;
    }

    @Override
    public boolean isConnected() throws Exception {
        return this.connected;
    }

    @Override
    public boolean isStarted() throws Exception {
        return (this.facadeHome != null);
    }

    @Override
    public Map<String, ParameterDetail> parseParametes(String pParameters) throws Exception {
        Map<String, ParameterDetail> m = this.initParameters();

        if ((pParameters == null) || (pParameters.compareTo("") == 0)) {
            return m;
        }

        List<String> l = this.parseString(pParameters);

        if (l.size() != 5) {
            throw new UCIException("TRAN-0000", "ERROR DE CONFIGURACION");
        }

        ParameterDetail d = m.get(URL);

        d.setValue(l.get(0));
        d = m.get(USER);
        d.setValue(l.get(1));
        d = m.get(PASSWORD);
        d.setValue(l.get(2));
        d = m.get(RMI_INITIAL_CONTEXT);
        d.setValue(l.get(3));
        d = m.get(EJB_JNDI);
        d.setValue(l.get(4));
        return m;
    }

    @Override
    public Serializable receiveMessage() throws Exception {
        throw new UCIException("8171", "El controlador no permite la recepci�n de Mensajes");
    }

    @Override
    public void sendMessage(Serializable pMessage, Properties pProperties) throws Exception {
        Detail response = (Detail) pMessage;

        try {
            FitFacade facade = this.facadeHome.create();

            this.setLastOutputMessage(pMessage.toString());
            response = facade.process((Detail) pMessage);
        } catch (Throwable e) {
            UCILogger.getInstance().throwing(e);

            Detail detail = (Detail) pMessage;

            DataAccess.initSession();

            ExceptionHandler eh = new ExceptionHandler(e,
                            ((detail == null) || (detail.getLanguage() == null)) ? "es" : detail.getLanguage());

            response.setResponse(eh.manage());
        }
        this.setLastInputMessage(response.toString());

        ConnectionProcesor cp = new ConnectionProcesor(response, this);

        cp.run();
    }

    @Override
    public void setParameters(String pParameters) throws Exception {
        this.parameters = this.parseParametes(pParameters);
    }

    @Override
    public void shutdown() throws Exception {
        this.disconnect();
    }

    @Override
    public void startup() throws Exception {
        this.ctx = this.getInitialContext();
        this.facadeHome = (FitFacadeHome) PortableRemoteObject.narrow(this.ctx.lookup(this.parameters.get(EJB_JNDI).getValue()),
                        FitFacadeHome.class);

        FitFacade f = this.facadeHome.create();

        f.createSessionFactory();
        this.connected = true;
        this.addMessage("Se establece la conexion con el EJB " + this.parameters.get(EJB_JNDI).getValue(),
                        DeviceEventTypes.CONNECT);
    }
}
