package com.fitbank.uci.server.fit;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;

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.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 UCIFitbankLocal extends Controlador {
    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(EJB_JNDI);

        if (aux == null) {
            throw new UCIException("PARAM-0012", "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;
    }

    private Context getInitialContext() throws Exception {
        return new InitialContext();
    }

    @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(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;
        }

        StringTokenizer st = new StringTokenizer(pParameters, "#");
        List<String> l = new ArrayList<String>();

        while (st.hasMoreElements()) {
            l.add((String) st.nextElement());
        }
        if (l.size() != 1) {
            throw new UCIException("TRAN-0000", "ERROR DE CONFIGURACION");
        }

        ParameterDetail d = m.get(EJB_JNDI);

        d.setValue(l.get(0));
        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);
            this.setLastInputMessage(response.toString());
        } catch (Throwable e) {
            Detail detail = (Detail) pMessage;

            DataAccess.initSession();

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

            response.setResponse(eh.manage());
        }

        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);
    }
}
