/* 
* Copyright 2016 Agencia Estatal de Administración Tibutaria
*
* Licencia con arreglo a la EUPL, Versión 1.1 o –en cuanto
* sean aprobadas por la Comisión Europea– versiones
* posteriores de la EUPL (la «Licencia»);
* Solo podrá usarse esta obra si se respeta la Licencia.
* Puede obtenerse una copia de la Licencia en:
*  
* https://joinup.ec.europa.eu/software/page/eupl
*  
* Salvo cuando lo exija la legislación aplicable o se acuerde
* por escrito, el programa distribuido con arreglo a la
* Licencia se distribuye «TAL CUAL», SIN GARANTÍAS NI CONDICIONES
* DE NINGÚN TIPO, ni expresasni implícitas.
*
* Véase la Licencia en el idioma concreto que rige los permisos y 
* limitaciones que establece la Licencia.
*/ 

package gestor;

import gestor.datos.*;
import gestor.utiles.*;
import java.util.logging.Level;
import sockets.*;

public class Comunicaciones {

   //<editor-fold desc="Constantes">
    // Mensajes recibidos
    public static final int CONEXION_ACEPTADA = 401;
    public static final int MSG_NUMERO_CANDIDATOS = 402;
    public static final int MSG_REGISTRO_CANDIDATOS = 403;
    public static final int MSG_REGISTRO_COLAS = 404;
    public static final int MSG_NUEVO_CANDIDATO = 405;
    public static final int MSG_MODIFICACION_CANDIDATO = 406;
    public static final int MSG_CAMBIO_ESTADO_MESA = 407;
    public static final int MSG_CAMBIO_NUMERO_MESAS = 408;
    public static final int MSG_REGISTRO_HUECOS = 409;
    public static final int MSG_CAMBIO_TURNO = 410;
    public static final int MSG_MONITOR_DESCONECTADO = 411;
    public static final int MSG_FORZAR_MANUAL = 412;
    public static final int MSG_MONITORES_CONECTADOS = 413;
    public static final int MSG_ESTIMACION = 414;
    public static final int MSG_CIERRE_DE_COLA = 415;
    public static final int MSG_HUECO_OCUPADO = 416;
    public static final int MSG_OCUPAR_HUECO = 417;
    public static final int MSG_MODIFICACION_CANDIDATO_NOPRESENTE = 418;
    public static final int MSG_HUECOS_POR_COLA = 419;
    public static final int MSG_MENSAJE_DEL_ADMINISTRADOR = 420;
    public static final int MSG_MENSAJE_DEL_OPERADOR = 421;
    public static final int MSG_LISTAR_HUECOS = 423;
    public static final int MSG_LISTA_SALAS = 424;
    public static final int MSG_LISTA_PUESTOS = 425;
    public static final int MSG_PREGUNTAR_HORA = 426;
    public static final int MSG_RANGO_HUECOS = 427;

    public static final int MSG_DATOS_TICKET = 111;
    public static final int MSG_COMIENZO_ENVIO_COLAS = 114;
    public static final int MSG_CIERRE_URGENTE = 80;
    // Mensajes enviados
    public static final int CONEXION = 401;
    public static final int SOLICITO_CAMBIO_AUTOMATICO = 402;
    public static final int ENVIO_MANUAL_SIGUIENTE = 403;
    public static final int ENVIO_MANUAL_A_MESA = 404;
    public static final int SOLICITO_HORA = 405;
    public static final int SOLICITO_MONITORES = 406;
    public static final int ENVIAR_TABLA_CANDIDATOS = 411;
    public static final int ENVIO_NUEVO_CANDIDATO = 412;
    public static final int ENVIO_MODIFICACION_CANDIDATO = 413;
    public static final int ENVIO_CAMBIO_COLA_O_MESA = 414;
    public static final int SOLICITO_DATOS_TICKET = 415;
    public static final int ENVIO_NUEVO_CANDIDATO_NOPRESENTE = 416;
    public static final int ENVIAR_TABLA_PUESTOS = 417;

    public static final int MENSAJE_A_ADMINISTRADOR = 420;
    public static final int MENSAJE_A_MESA = 421;
    public static final int MSG_MENSAJE_RECIBIDO = 422;
    public static final int MENSAJE_A_OPERADORES = 423;
    public static final int ENVIO_HORA = 426;
    public static final int MSG_CAMBIO_AUTOMATICO = 110;
    //</editor-fold>
    MessageSocket sock;
    public static Comunicaciones comm;
    final String sep = "|";
    public volatile boolean procesarDeInmediato = false;

    Configuracion conf;
    SocketUDP udp = null;

    public Comunicaciones() {
        comm = this;
        conf = Configuracion.instanciaUnica();
        if (!conf.nombreServidor.equals("")) {
            try {
                udp = new SocketUDP(conf.nombreServidor, conf.puertoIpServidor);
            } catch (Exception exc) {
            }
        }
    }

    public boolean abrir() {
        sock = new MessageSocket();
        sock.setProcesaMensajes(true);
        if (conf.usandoUDP) {
            String ip = udp.buscarServidorEnLaRed(3000);
            if (!ip.equals("")) {
                sock.setHost(ip);
                sock.setPuerto(Configuracion.instanciaUnica().puertoIpServidor);
            } else {
                return false;
            }
        } else {
            sock.setHost(Configuracion.instanciaUnica().ipServidor);
            sock.setPuerto(Configuracion.instanciaUnica().puertoIpServidor);
        }
        sock.open();
        if (!sock.abierto() && !conf.usandoUDP && !conf.ipServidor.equals(conf.ipServidorSec)) {
            sock.setHost(conf.ipServidorSec);
            sock.setPuerto(conf.puertoIpServidorSec);
            sock.open();
        }
        if (sock.abierto()) {
            sock.addMessageSocketListener(new MessageSocketListener() {

                @Override
                public void mensajeRecibido(MensajeRecibidoEvent ev) {
                    final int codigo = ev.getCodigo();
                    final String msj = ev.getMensaje();
                    Runnable runnable = () -> {
                        mensajeDelServidor(codigo, msj);
                    };
                    try {
                        if (procesarDeInmediato) {
                            mensajeDelServidor(codigo, msj);
                            procesarDeInmediato = false;
                        } else {
                            javax.swing.SwingUtilities.invokeLater(runnable);
                        }
                    } catch (Exception exc) {
                    }
                }

                @Override
                public void errorSocket(MensajeRecibidoEvent ev) {
                    errorEnSocket(ev.getMensaje());
                }

                @Override
                public void buferRecibido(BuferRecibidoEvent evt) {
                }
            });
            return true;
        }
        return false;
    }

    void mensajeDelServidor(int codigo, String mensaje) {
        switch (codigo) {
            case CONEXION_ACEPTADA:
                Global.main.conexionAceptada(new Mensaje(mensaje));
                break;
            case MSG_NUMERO_CANDIDATOS:
                Global.main.iniciaCargaCandidatos(mensaje);
                break;
            case MSG_REGISTRO_CANDIDATOS:
                Global.main.nuevoRegistroCandidatos(mensaje);
                break;
            case MSG_REGISTRO_HUECOS:
                Global.main.nuevoRegistroHuecos(mensaje);
                break;
            case MSG_OCUPAR_HUECO:
                Global.main.huecos.eliminar(mensaje);
                break;
            case MSG_HUECO_OCUPADO:
                Global.main.huecoOcupado(mensaje);
                break;
            case MSG_HUECOS_POR_COLA:
                Global.main.incorporarHuecos(mensaje);
                break;
            case MSG_COMIENZO_ENVIO_COLAS:
                Global.main.iniciarEnvioDeColas();
                break;
            case MSG_REGISTRO_COLAS:
                Global.main.nuevoRegistroColas(mensaje);
                break;
            case MSG_CIERRE_DE_COLA:
                Global.main.cambiarEstadoCola(mensaje);
                break;
            case MSG_NUEVO_CANDIDATO:
                Global.main.nuevoCandidato(mensaje);
                break;
            case MSG_MODIFICACION_CANDIDATO:
                Global.main.cambiaEstadoCandidato(mensaje);
                break;
            case MSG_MODIFICACION_CANDIDATO_NOPRESENTE:
                Global.main.nuevoCandidatoNoPresente(mensaje);
                break;
            case MSG_ESTIMACION:
                Global.main.cargaEstimacionCandidatos(mensaje);
                break;
            case MSG_CAMBIO_ESTADO_MESA:
                if (Global.principal != null) {
                    Global.principal.cambioEstadoMesa(mensaje);
                } else {
                    Global.main.mensajesPendientes.add(mensaje);
                }
                break;
            case MSG_CAMBIO_NUMERO_MESAS:
                Global.principal.cambioNumeroMesas(mensaje);
                break;
            case MSG_CAMBIO_TURNO:
                Global.main.turno = mensaje;
                Global.main.turnoVisible = mensaje;
                Global.principal.ponerTituloVentana();
                TablaCandidatos.getTablaCandidatos().cambiaTurno();
                if (Global.principal.formCandidatos != null) {
                    Global.principal.formCandidatos.refrescarDatos(false);
                }
                Global.principal.refrescarDatos(false);
                break;
            case MSG_MONITOR_DESCONECTADO:
                Global.principal.monitorDesconectado("Se ha desconectado el monitor " + mensaje
                        + "\nEl sistema pasa a MODO MANUAL");
                break;
            case MSG_FORZAR_MANUAL:
                Global.principal.monitorDesconectado("PROBLEMAS CON LOS MONITORES\nEl sistema pasa a modo MANUAL");
                break;
            case MSG_CAMBIO_AUTOMATICO:
                Global.modoAutomatico = !mensaje.equals("Manual");
                if (Global.principal != null) {
                    Global.principal.pasoAAutomatico(Global.modoAutomatico);
                }
                break;
            case MSG_MONITORES_CONECTADOS:
                Global.principal.confirmarModoAutomatico(mensaje);
                break;
            case MSG_MENSAJE_DEL_ADMINISTRADOR:
                Global.principal.mensajeDelAdministrador(mensaje);
                break;
            case MSG_MENSAJE_DEL_OPERADOR:
                Global.principal.mensajeDelOperador(mensaje);
                break;
            case MSG_MENSAJE_RECIBIDO:
                javax.swing.JOptionPane.showMessageDialog(null, "EL MENSAJE HA SIDO RECIBIDO");
                break;
            case MSG_DATOS_TICKET:
                Global.principal.mostrarDatosTicket(mensaje);
                break;
            case MSG_CIERRE_URGENTE:
                Global.main.cerrarAplicacion();
                break;
            case MSG_LISTAR_HUECOS:
                gestor.datos.TablaHuecos.getTablaHuecos().listarHuecos();
                break;
            case MSG_LISTA_SALAS:
                gestor.datos.TablaPuestos.getTablaPuestos().cargarSalas(mensaje);
                break;
            case MSG_LISTA_PUESTOS:
                gestor.datos.TablaPuestos.getTablaPuestos().cargarPuestos(mensaje);
                Global.principal.puestosCargados();
                break;
            case MSG_PREGUNTAR_HORA:
                Global.main.enviarHora();
                break;
            case MSG_RANGO_HUECOS:
                gestor.datos.TablaHuecos.getTablaHuecos().cargarRangoHuecos(mensaje);
                break;
            default:
                Main.log.log(Level.WARNING, "Mensaje no identificado: {0}\n{1}", new Object[]{codigo, mensaje});
                break;
        }
    }

    void errorEnSocket(String mensaje) {
        if (mensaje.startsWith("Connection")) {
            Global.principal.avisoDesconexion();
        }
    }

    public void confirmarLecturaMensaje(String origen) {
        enviar(MSG_MENSAJE_RECIBIDO, origen);
    }

    public void enviar(int codigo, Object... vars) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < vars.length; i++) {
            sb.append(vars[i].toString());
            if (i + 1 < vars.length) {
                sb.append(sep);
            }
        }
        sock.enviar(sb.toString(), codigo);
    }

    public void enviar(int codigo) {
        sock.enviar(codigo + "\n");
    }

}
