// 
// 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.
// 

using System;
using System.Collections.Generic;
using System.Text;
using gestor.utiles;
using minigestor.datos;
using ateneo.sockets;

namespace minigestor
{
    public enum MSG_RECIBIDO
    {
        CONEXION_ACEPTADA = 401,
        NUMERO_CANDIDATOS = 402,
        REGISTRO_CANDIDATOS = 403,
        REGISTRO_COLAS = 404,
        NUEVO_CANDIDATO = 405,
        MODIFICACION_CANDIDATO = 406,
        CAMBIO_ESTADO_MESA = 407,
        CAMBIO_NUMERO_MESAS = 408,
        CAMBIO_TURNO = 410
    }

    public enum COD_ENVIADO
    {
        CONEXION = 401,
        SOLICITO_CAMBIO_AUTOMATICO = 402,
        ENVIO_MANUAL_SIGUIENTE = 403,
        ENVIO_MANUAL_A_MESA = 404,
        ENVIAR_TABLA_CANDIDATOS = 411,
        ENVIO_NUEVO_CANDIDATO = 412,
        
        ENVIO_MODIFICACION_CANDIDATO = 413,
    }

    public class Comunicaciones
    {
        private MessageSocket socket;
        private SocketUDP udp;
        MiniGestor gestor;
        delegate void MensajeDelServidor(int codigo, string msj);
        MensajeDelServidor mensajeDelegate;
        MensajeDelServidor errorDelegate;
        public string host {
            get { return socket.host; }
        }
        public int puerto {
            get { return socket.puerto; }
        }

        public Comunicaciones(MiniGestor gestor) {
            this.gestor = gestor;
            mensajeDelegate = new MensajeDelServidor(mensajeDelServidor);
            errorDelegate = new MensajeDelServidor(errorEnSocket);
        }

        public bool conectar() {
            socket = new MessageSocket();
            if (!abrir(true)) {
                abrir(false);
            }
            if (socket.abierto) {
                socket.mensajeRecibido += new MensajeRecibidoEventHandler(socket_mensajeRecibido);
                socket.errorSocket += new ErrorSocketEventHandler(socket_errorSocket);
                return true;
            }
            return false;
        }

        void socket_errorSocket(object sender, MensajeRecibidoArgs e) {
            try {
                if (gestor != null && gestor.principal != null) {
                    gestor.principal.Invoke(errorDelegate, new Object[] { e.codigo, e.mensaje });
                }
            } catch (Exception) { }
        }

        public bool abrir(bool principal) {
            if (!Configuracion.instanciaUnica.usandoUDP) {
                if (principal) {
                    socket.host = Configuracion.instanciaUnica.ipServidor;
                    socket.puerto = Configuracion.instanciaUnica.puertoIpServidor;
                } else {
                    socket.host = Configuracion.instanciaUnica.ipServidorSec;
                    socket.puerto = Configuracion.instanciaUnica.puertoIpServidorSec;
                }
            } else {
                udp = new SocketUDP(Configuracion.instanciaUnica.nombreServidor, Configuracion.instanciaUnica.puertoIpServidor);
                string ip = udp.buscarServidorEnLaRed(1500);
                if (ip != "") {
                    socket.host = ip;
                    socket.puerto = Configuracion.instanciaUnica.puertoIpServidor;
                } else {
                    return false;
                }
                udp.close();
            }
            return socket.open();
        }

        public bool abierto {
            get { return socket.abierto; }
        }

        public void errorEnSocket(int codigo, string msg) {
            gestor.principal.Close();
        }

        void socket_mensajeRecibido(object sender, MensajeRecibidoArgs e) {
            gestor.principal.Invoke(mensajeDelegate, new Object[] { e.codigo, e.mensaje });
        }

        void mensajeDelServidor(int iCodigo, string mensaje) {
            MSG_RECIBIDO codigo = (MSG_RECIBIDO)iCodigo;
            switch (codigo) {
                case MSG_RECIBIDO.CONEXION_ACEPTADA:
                    gestor.conexionAceptada(mensaje);
                    break;
                case MSG_RECIBIDO.NUMERO_CANDIDATOS:
                    gestor.iniciaCargaCandidatos(mensaje);
                    break;
                case MSG_RECIBIDO.REGISTRO_CANDIDATOS:
                    gestor.nuevoRegistroCandidatos(mensaje);
                    break;
                case MSG_RECIBIDO.REGISTRO_COLAS:
                    gestor.nuevoRegistroColas(mensaje);
                    break;
                case MSG_RECIBIDO.NUEVO_CANDIDATO:
                    gestor.nuevoCandidato(mensaje);
                    break;
                case MSG_RECIBIDO.MODIFICACION_CANDIDATO:
                    gestor.cambiaEstadoCandidato(mensaje);
                    break;
                case MSG_RECIBIDO.CAMBIO_ESTADO_MESA:
                    gestor.cambioEstadoMesa(mensaje);
                    break;
                case MSG_RECIBIDO.CAMBIO_TURNO:
                    gestor.turno = mensaje;
                    TablaCandidatos.getTablaCandidatos().cambiaTurno();
                    break;
                default:
                    break;
            }
        }

        internal void desconectar() {
            socket.close();
        }

        public void enviar(COD_ENVIADO codigo, params string[] msgs) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < msgs.Length; i++) {
                sb.Append(msgs[i]).Append('|');
            }
            sb.Length = sb.Length - 1;
            socket.enviar(sb.ToString(), (int)codigo);
        }
    }
}
