/* 
* 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 servidor;

import java.io.*;
import java.text.*;
import java.util.*;
import java.sql.*;
import java.util.Date;
import java.util.logging.*;
import java.util.regex.*;
import javax.swing.JOptionPane;
import org.quickserver.net.server.*;
import org.quickserver.util.xmlreader.*;
import servidor.comunicaciones.*;
import servidor.datos.*;
import servidor.datos.base.*;
import servidor.utiles.*;
import servidor.utiles.ProgramadorTareas;

public final class ServidorMain {

    //<editor-fold desc="1. Variables">
    public String version = "3";
    public String release = "0000";
    String nombreServidor = "Servidor ATENEO DGI";
    int ventanaDiasTransmision = 5;
    java.applet.AudioClip clip = null;
    public static Logger log;
    public QuickServer servidor;
    BroadcastServidor bbc;
    private servidor.http.ServidorHttp servidorHttp;
    GestorColas gestorColas;
    Configuracion configuracion;
    Parametros args;
    PseudoConsola consola;
    public Metronomo metronomo = new Metronomo();
    String turno;
    public LogGenerico logMensajesSalientes;
    public String logConsola;
    public String logResucitables;
    public SincronizacionHoraria sincronizador = new SincronizacionHoraria(3);
    public ProgramadorTareas listaHoy;
    private Pattern rexTok;
    Pinger pinger;
    public boolean guardarMensajes = false;
    public LogGenerico logMensajes = null;
    private boolean modoComandoPreparado = false;

    public String getTurno() {
        return turno;
    }

    public void setTurno(String nuevoTurno) {
        turno = nuevoTurno;
        System.out.println("** CAMBIADO TURNO A " + (turno.equals("M") ? "MAÑANA" : "TARDE") + " **");
    }

    //</editor-fold>
    public ServidorMain() {
        Global.main = this;
        consola = new PseudoConsola();
        consola.setSize(600, 500);
        consola.setLocationRelativeTo(null);
        prepararLogging();
        configuracion = Configuracion.getConfiguracion();
        if (!configuracion.cargar("ConfiguracionServidor.ini")) {
            JOptionPane.showMessageDialog(null, "ERROR AL CARGAR configuracionServidor.ini");
            System.exit(-1);
        }
        // permitir varios servidores en la misma máquina
        // esto requiere muchos ajustes en la configuracion...
        if (!configuracion.permitirEjecucionSimultanea) {
            ServidorMain.checkServidorYaArrancado();
        }
        //consola.setTitle(consola.getTitle());

        consola.setVisible(true);
        if (configuracion.codigoCentro.equals("")) {
            JOptionPane.showMessageDialog(null,
                    "Falta el CODIGO de ADMINISTRACIÓN en ConfiguracionServidor.ini\n"
                    + "NO SE PUEDE CONTINUAR", "ERROR FATAL", JOptionPane.ERROR_MESSAGE);
            System.exit(-1);
        }
        if (configuracion.codigoCentro.length() != 5) {
            JOptionPane.showMessageDialog(null,
                    "El CODIGO de ADMINISTRACIÓN en ConfiguracionServidor.ini debe tener 5 digitos\n"
                    + "NO SE PUEDE CONTINUAR", "ERROR FATAL", JOptionPane.ERROR_MESSAGE);
            System.exit(-1);
        }
        rexTok = Pattern.compile("['\"]([^'\"]*)['\"]|([^\\s\\,]+)");
    }

    public PseudoConsola getConsola() {
        return consola;
    }

    void actualizar() {
//      if (configuracion.URLActualizacion.equals("")) {
//         System.err.println("ATENCIÓN - ConfiguracionServidor.ini:");
//         System.out.println("   URLActualizacion no está definido.");
//         System.out.println("   Se continua la ejecución sin actualizar.");
//         System.out.println("");
//         return;
//      } else {
//         ActualizadorATENEO dxml = new ActualizadorATENEO(configuracion.URLActualizacion, configuracion.codigoCentro);
//      }
    }

    void iniciar() {
        if (BaseDatos.bd() == null) {
            return;
        }

        sincronizador.sincronizar();
        calculaTurno();

        if (!configuracion.nombreServidor.equals("")) {
            bbc = new BroadcastServidor();
            System.out.println("Comprobando otros servidores en ejecución");
            if (bbc.existeAnterior(configuracion.nombreServidor)) {
                javax.swing.JOptionPane.showMessageDialog(null, "Servidor ATENEO '" + configuracion.nombreServidor + "' en " + bbc.ipEncontrada);
                cerrarAplicacionSinEsperar();
            }
            bbc.iniciar();
        }
        // asegurar que la version de las tablas se ajusta a lo esperado...

        ActualizadorEstructuraBD aebd = new ActualizadorEstructuraBD();
        aebd.comprobarTablas();
        comprobarIdServidor();

        gestorColas = new GestorColas();

        prepararBaseDatos();

        arrancarQuickServer();

        prepararTransmisiones();

        //TODO Eliminar esta linea
        arrancarServidorHttp();

        System.out.println("Base de datos activa " + configuracion.BaseDatosAte);
        System.out.println(" ");
        if (configuracion.modoSinGestor) {
            System.err.println("Funcionando SIN GESTOR (gestor en los operadores)");
            configuracion.gestionHuecosActivada = false;
            configuracion.resucitar = false;
            configuracion.estimarRetrasos = false;
        } else {
            System.err.println("Funcionando CON GESTOR (Recepcionista)");
        }
        if (configuracion.modoColaCero) {
            System.err.println("AutoenvioColaCero Activado Cola = " + configuracion.colaCero);

        }

        System.out.println(" ");
        gestorColas.arranca();

        metronomo.setLapsoTimerPrincipal(configuracion.tiempoBucle);
        listaHoy = new ProgramadorTareas();
        metronomo.arrancarTimerPrincipal();
        prepararTareas();

        modoComandoPreparado = true;
        gestorColas.tablaColas.cerrarColaAutoenvio();
    }

    void comprobarIdServidor() {
        String TEXTO_CONF_SIN_IDSERVIDOR = "ATENCIÓN\n"
                + "No se ha podido obtener el identificador de servidor en la b.d. Ateneo.\n"
                + "Ello es necesario para diferenciar las transmisiones de datos  cuando hay más de un servidor con el mismo código de oficina.\n"
                + "Si actualmente no hay más servidores transmitiendo en la oficina identificar con un '1'.\n"
                + "Si actualmente hay algún otro servidor transmitiendo en la oficina identificar con el numeral correspondiente; '2','3'...\n"
                + "Si se trata de un servidor que no debe transmitir (pruebas, formación...) identificar con un '0'.\n"
                + "Este identificador podrá ser modificado posteriormente desde la utilidad ConfiguraServidor.jar.\n";

        ConfiguracionEnBd cebd = new ConfiguracionEnBd();
        if (!cebd.IdServidorPresente()) {
            javax.swing.JOptionPane.showMessageDialog(null, TEXTO_CONF_SIN_IDSERVIDOR);
            cerrarAplicacionSinEsperar();
        }
        Global.idServidor = cebd.getIdServidor();
    }

    void prepararLogging() {
        java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("ddMMyyyy");
        String cadenaFecha = sdf.format(new Date());

        //LogMensajes
        logMensajes = new LogGenerico("Forense_" + cadenaFecha + ".log", "mensajes");

        try {
            File logdir = new File("logs\\");
            if (!logdir.exists()) {
                logdir.mkdir();
            }
            log = Logger.getLogger("Logger");
            FileHandler fh = new FileHandler("logs\\servidor.log", 10000, 5);
            fh.setFormatter(new SimpleFormatter());
            log.addHandler(fh);
            log.setLevel(Level.FINEST);
        } catch (Exception exc) {
            JOptionPane.showMessageDialog(null, "No se ha podido iniciar el proceso de LOG");
            System.exit(-1);
        }
        // Preparar log Consola (borrando los de mas de 20 dias)
        Global.borrarLogsAntiguos("logs", "logConsola", 20);
        Global.borrarLogsAntiguos("logs", "logResucitables", 5);
        logConsola = "logs\\logConsola_" + cadenaFecha + ".log";
        logResucitables = "logResucitables_" + cadenaFecha + ".log";        
    }

    public static void logException(String s, Exception ex) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        ex.printStackTrace(pw);
        log.log(Level.CONFIG, "{0}\r\n{1}", new Object[]{s, sw.toString()});
    }

    public void prepararBaseDatos() {
        BaseDatos bd = BaseDatos.bd();
        if (bd == null) {
            JOptionPane.showMessageDialog(null, "No se pudo abrir la base de datos del programa\n"
                    + "Asegurese de que los ficheros se encuentran en la misma carpeta que el programa");
            System.exit(-1);
        }
        comprobacionInicialTablas();
        Global.tablaPuestos = new TablaPuestos();
        Global.tablaPuestos.cargarTabla();
    }

    void comprobacionInicialTablas() {
        BaseDatos bd = BaseDatos.bd();
        //limpiarTransmisiones();
        try {
            java.sql.Timestamp hoy = new java.sql.Timestamp(System.currentTimeMillis());
            TablaAcciones acciones = gestorColas.tablaAcciones;
            if (acciones.count() > 0) {
                RegistroAcciones reg = acciones.registro(0);
                String turnoGrabado = reg.getTurno();
                java.sql.Timestamp fecha = reg.getHoraUltimoMovimiento();
                if (distintoDia(fecha, hoy) || !turnoGrabado.equals(turno)) {
                    gestorColas.LimpiarTablaAccionesPorTurno();
                    reiniciarContadoresColas();
                    gestorColas.tablaColas.reabrirColasCerradas();
                } else {
//                    int mayorNumeroMesa = acciones.mayorNumeroMesa();
//                    if (mayorNumeroMesa > configuracion.numeroMesas) {
//                        configuracion.numeroMesas = mayorNumeroMesa;
//                    }
                    acciones.ponerTodosACero();
                    acciones.recargar();
                }
            }
            TablaCandidatos candidatos = gestorColas.tablaCandidatos;
            String filtro = "HoraCita < " + Fecha.formatoFechaSQLCorto(hoy);
            bd.borrarTabla("Huecos", filtro);
            if (candidatos.count() > 0) {
                bd.depurarTablaCandidatos();
                String campos = "Nif, Nombre, HoraCita, Estado, HoraCalculada, HoraAtendido, HoraPresente,  "
                        + "HoraCalculada2, Turno, CitaMultiple, NumeroTicket, Cola, Operador, HoraFinalizado, "
                        + "codigoEstadistico, citaVinculada, codigoGestor, NIU, Mesa, "
                        + "HoraPresente2, NombreCola, GHuecos, DNIe, Centro, Origen, CP, Notas";

                // String filtro = "HoraCita < " + Fecha.formatoFechaSQLCorto(hoy);
                bd.MoverTabla("Candidatos", "HistoricoCandidatos", campos, filtro);
                bd.borrarTabla("Candidatos", filtro);   // borrar los registros de la BD

                // bd.borrarTabla("Huecos", filtro);
                candidatos.borrarTabla();   // borrar los registros en memoria

                candidatos.recargar();

                actualizarMediasTiempo();
                //limpiarTransmisiones();
            }
            gestorColas.tablaHuecos.recargar();
            gestorColas.tablaMsjGestores.limpiar();
            gestorColas.tablaProductos.limpiar();
        } catch (Exception er) {
            log.log(Level.SEVERE, "ERROR en el proceso de Actualizacion de tablas: {0}", er.getMessage());
        }
    }

    void prepararTransmisiones() {
//      TransmisorAteneo.Transmisor trans = new TransmisorAteneo.Transmisor(BaseDatos.bd());
//      trans.setCodigoCentro(configuracion.codigoCentro);
//      Global.trans = trans;
    }

    void limpiarTransmisiones() {
        try {
            Calendar calendar = Calendar.getInstance(); //obtiene la fecha de hoy
            calendar.add(Calendar.DATE, -30); //el -3 indica que se le restaran 3 dias
            String fechasql = Fecha.formatoFechaSQLCorto(calendar.getTime());
            BaseDatos bd = BaseDatos.bd();
            String sql = "DELETE  FROM TRANSMISIONES WHERE fecha < " + fechasql;
            bd.SQL(sql);
        } catch (Exception exc) {
            // a la porra
        }
    }

    void actualizarMediasTiempo() {
        try {
            BaseDatos bd = BaseDatos.bd();
            String sqlMedias = "UPDATE Colas Set tiempoMedio=tiempo FROM"
                    + "(SELECT Cola, FLOOR(AVG(DATEDIFF(s, HoraAtendido, HoraFinalizado)) * 1.15)"
                    + " AS tiempo"
                    + " FROM (SELECT Cola, HoraAtendido, HoraFinalizado"
                    + "     FROM dbo.HistoricoCandidatos"
                    + "     WHERE HoraFinalizado > DATEADD(wk, - 2, GETDATE()) AND"
                    + "     DATEDIFF(s, HoraAtendido, HoraFinalizado) > 180) subconsulta"
                    + "     GROUP BY Cola) as medias"
                    + " WHERE Colas.Cola = medias.cola";
            bd.SQL(sqlMedias);
        } catch (Exception exc) {
            // a la porra
        }
    }

    boolean distintoDia(Timestamp f1, Timestamp f2) {
        GregorianCalendar c1 = new GregorianCalendar();
        c1.setTimeInMillis(f1.getTime());
        GregorianCalendar c2 = new GregorianCalendar();
        c2.setTimeInMillis(f2.getTime());
        return c1.get(Calendar.DAY_OF_YEAR) != c2.get(Calendar.DAY_OF_YEAR);
    }

    public void reiniciarContadoresColas() {
        try {
            BaseDatos.bd().SQL("UPDATE colas SET numero = 0");
            gestorColas.tablaColas.recargar();
        } catch (Exception exc) {
            log.log(Level.WARNING, "ERROR al poner a CERO los contadores de las colas:\n{0}", exc.getMessage());
        }
    }

    public static void checkServidorYaArrancado() {
        InstanciaUnica iu = new InstanciaUnica("ServidorAteneo");
        if (iu.isAppActive()) {
            System.exit(1);
        }
    }

    void arrancarQuickServer() {
        try {
            servidor = new QuickServer();
            QuickServerConfig qsConfig = new QuickServerConfig();

            ServerMode serverMode = new ServerMode();
            // Aqui configuramos el modo 'non-blocking''. CAMBIADO. Volvemos a socket sincronos...
            serverMode.setBlocking(true);
            qsConfig.setServerMode(serverMode);

            qsConfig.setPort(configuracion.ipPort);
            qsConfig.setBindAddr(java.net.InetAddress.getLocalHost().getHostAddress());
            qsConfig.setName(nombreServidor + " " + version + "." + release);
            qsConfig.setTimeout(-1);
            qsConfig.setClientEventHandler("servidor.comunicaciones.ManejadorCliente");
            qsConfig.setClientCommandHandler("servidor.comunicaciones.ManejadorCliente");
            qsConfig.setClientData("servidor.comunicaciones.DatosCliente");

            servidor.initServer(qsConfig);
            servidor.setLoggingLevel(Level.WARNING);
            servidor.startServer();
        } catch (Exception e) {
            String txt = "Error en el servidor " + e.getMessage();
            log.severe(txt);
            JOptionPane.showMessageDialog(null, txt);
            System.exit(-1);
        }
    }

    public void calculaTurno() {
        GregorianCalendar hoy = new GregorianCalendar();
        Date ahora = new Date();
        if (ahora.before(configuracion.horaTurnoTarde)) {  // a partir de las 3 es turno TARDE
            turno = "M";
        } else {
            turno = "T";
        }
    }

    public void prepararTareas() {
        tarea_recibirCandidatosIntranet();
        // tarea_enviarResultadosIntranet();
        tarea_crearTareaLiberarMemoria();
        //listaHoy.crearTareaPlanificacion("00:30:01");
        listaHoy.crearTareaTurno(configuracion.horaTurnoTarde);
        listaHoy.crearTareaCierre(); // comportamiento especial. Ver codigo

//      if (!comprobarSiEjecutado("backup", "M")) {
//         listaHoy.crearTareaBackup("08:00:00");
//      }
        if (!comprobarSiEjecutado("backup", "T")) {
            listaHoy.crearTareaBackup("22:30:00");
        }
        for (Configuracion.ScriptUsuario su : Configuracion.getConfiguracion().scriptsUsuario) {
            String scriptName = su.path.toLowerCase();
            if (scriptName.equals("releertablas")) {
                listaHoy.crearTareaReleer(su.hora);
            } else if (scriptName.startsWith("depura") && !scriptName.contains(".")) {
                configurarDepuracion("SI");
                configuracion.modoDepuracion = true;
            } else {
                listaHoy.crearTareaScriptUsuario(su.hora, su.path, su.params);
            }
        }
    }

    public void tarea_recibirCandidatosIntranet() {
        Date horaI = Fecha.ajusteAleatorioHora(Fecha.convertirHora(configuracion.horaEjecucionRecepcion), 5);
        listaHoy.crearTareaGenerarCitas(horaI);
        listaHoy.crearTareaReleer(horaI);
    }

    public void tarea_crearTareaLiberarMemoria() {
        //Date horaI = Fecha.ajusteAleatorioHora(Fecha.convertirHora("01:30:00"), 5);
        Date horaI = Fecha.convertirHora("01:00:00");
        if (configuracion.ajustarMemoriaSQL) {
            listaHoy.crearTareaLiberarMemoria(horaI);
        }
    }

    boolean esteServidorTransmite() {
        return false;
    }

    public boolean comprobarSiEjecutado(String programa, String parametros) {
        Date fecha = Fecha.convertirHora("00:00:01");
        return BaseDatos.bd().comprobarTransmisiones(programa, parametros, fecha);
    }

    public void tarea_enviarResultadosIntranet() {

    }

    public void cerrarAplicacion() {
        try {
            listaHoy.ejecutarTareasPendientesObligatorias();
            Global.sleep(3000);
            esperarTareasPendientes();
            System.out.println("Ejecutadas tareas pendientes");
            Global.modoAutomatico = false;
            System.out.println("Paso a Modo Manual");
            configuracion.apagarOperadoresFantasma = false;
            System.out.println("Desactivo comprobacion 'fantasmas'");
            servidorHttp.stop();
            servidor.stopServer();
            System.out.println("QuickServer detenido");
            gestorColas.esperarAColaVacia();
            System.out.println("Cola de mensajes vacia");
            BaseDatos.bd().cerrar();
            System.out.println("Base de Datos cerrada");
            metronomo.pararTimerPrincipal();
            consola.guardarPendiente(logConsola);
            System.out.println("Consola guardada");
        } catch (Exception exc) {
            log.info("Error cerrando la aplicación");
        }
        //LogMensajes
        logMensajes.cerrar();

        System.out.println("FIN DEL PROCESO");
        Global.sleep(3000);
        System.exit(0);
    }

    public void cerrarAplicacionSinEsperar() {
        try {
            servidor.stopServer();
            BaseDatos.bd().cerrar();
            consola.guardarPendiente(logConsola);
        } catch (Exception exc) {
        }
        logMensajes.cerrar();
        System.exit(0);
    }

    void apagarClientes() {
        gestorColas.apagarClientes();
    }

    public void cierreYApertura() {
        esperarTareasPendientes();
        apagarClientes();
        if (!BaseDatos.bd().recuperacionActivada) {
            gestorColas.tablaHuecos.borrarTabla();
        }
        EjecutarExterno.reiniciarMedianteScript();
    }

    public void reiniciar() {
        esperarTareasPendientes();
        EjecutarExterno.reiniciarMedianteScript("10000");
    }

    void esperarTareasPendientes() {
        if (listaHoy.hayTareasEnEjecucion()) {
            System.err.println("Hay tareas programadas en ejecución");
            listaHoy.mostrarTareasEnEjecucion();
            System.err.println("Se cancelarán transcurridos 10 minutos.");
            System.err.println("Esperando a que terminen.");
            consola.refrescaVisor();
        }
        int tiempoAcumulado = 0;
        int tiempoBucle = 1000;
        while (listaHoy.hayTareasEnEjecucion()) {
            consola.refrescaVisor();
            Global.sleep(tiempoBucle);
            tiempoAcumulado += tiempoBucle;
            if (tiempoAcumulado >= 600000) {
                System.err.println("** No se terminaron las tareas:");
                listaHoy.mostrarTareasEnEjecucion();
                break;
            }
        }
    }

    class codOrden {

        public int code = 9999;
        public String[] params;
    }

    public void mensajeExterno(String txt) {
        consola.textoExterno(txt);
    }

    void preprocesaOrden(String comando, codOrden co) {
        final String[] ordenes = {"QUIT", "EXIT", "SALI", "LIST", "RELE", "CRC", "RESE", "CARG",
            "TURN", "VERS", "AYUD", "HELP", "?", "TEST", "MATA", "DESA", "ESTA", "IMPR", "COLA",
            "PING", "RUN1", "RUNT", "HUEC", "ACTI", "DEPU", "HORA"
        };
        ArrayList<String> atok = new ArrayList<>();
        Matcher match = rexTok.matcher(comando);
        while (match.find()) {
            atok.add((match.group(1) == null ? match.group(0) : match.group(1)));
        }
        if (atok.size() == 1) {
            atok.add("");
        }
        String[] tok = atok.toArray(new String[1]);
        for (int i = 0; i < ordenes.length; i++) {
            if (tok[0].startsWith(ordenes[i])) {
                co.code = i;
                break;
            }
        }
        co.params = tok;
    }

    public boolean procesaComando(String comando) {
        if (!modoComandoPreparado) {
            System.out.println("Consola aún no disponible. Espere unos segundos y repita comando");
            return false;
        }
        codOrden co = new codOrden();
        preprocesaOrden(comando, co);
        switch (co.code) {
            case 0:  //  QUIT, EXIT Ó SALIR
            case 1:
            case 2:
                cerrarAplicacion();
                break;
            case 3:  // LISTAR (OPERADORES GESTORES MONITORES ADMINISTRADORES RESUCITABLES COLAS)
                gestorColas.listar(co.params[1]);
                break;
            case 4:  // RELEER TABLAS
                gestorColas.autoMensaje(MensajeInterno.MSG_REFRESCA_TABLAS);
                break;
            case 5:  // CRC RECALCULO   ** ya no hace falta **
                //MensajeCargador.resetCrc();
                break;
            case 6:  // RESET CONTADOR TICKETS

                if (co.params[1].startsWith("CONT")) {
                    reiniciarContadoresColas();
                    System.out.println("Contadores de Colas a CERO");
                }
                break;
            case 7:  // CARGAR MESAS (CAPACIDADES)

                if (co.params[1].startsWith("MESA")) {
                    gestorColas.autoMensaje(MensajeInterno.MSG_REFRESCA_TABLAPUESTOS);
                }
                break;
            case 8:  // TURNO M Ó T

                if (co.params[1].equals("M") || co.params[1].equals("T")) {
                    gestorColas.autoMensaje(MensajeInterno.MSG_CAMBIO_TURNO + co.params[1]);
                } else {
                    System.out.println("ERROR: ESPECIFIQUE TURNO M Ó T");
                }
                break;
            case 9:    // VERSION
                mostrarEstado();
                break;
            case 10:
            case 11:
            case 12:    // HELP, AYUDA Ó ?
                mostrarAyuda();
                break;
            case 13:    // TEST (VARIABLE)

                if (configuracion.modoTest) {
                    String mensaje = "";
                    if (co.params.length > 1) {
                        for (int i = 1; i < co.params.length; i++) {
                            mensaje += co.params[i] + "|";
                        }
                    }
                    gestorColas.autoMensaje(MensajeInterno.MSG_EJECUTA_TEST + mensaje);
                } else {
                    System.out.println("ERROR. COMANDO NO IMPLEMENTADO");
                }
                break;
            case 14:    // MATAR (OPERADORES)

                if (co.params[1].equals("TODOS")) {
                    gestorColas.autoMensaje(MensajeInterno.MSG_MATAR_OPERADORES + "ADIOS");
                } else if (co.params[1].startsWith("ADMI")) {
                    gestorColas.autoMensaje(MensajeInterno.MSG_MATAR_ADMINISTRADOR + co.params[2]);
                } else if (co.params[1].startsWith("MONI")) {
                    gestorColas.autoMensaje(MensajeInterno.MSG_MATAR_MONITORES);
                } else {
                    gestorColas.autoMensaje(MensajeInterno.MSG_MATAR_OPERADOR + co.params[1]);
                }
                break;
            case 15: //  DESACTIVAR

                if (co.params[1].startsWith("MONI")) {
                    configuracion.desactivarComprobacionMonitores();
                    System.out.println("Comprobación de monitores DESACTIVADA");
                }
                break;
            case 23: // ACTIVAR

                if (co.params[1].startsWith("MONI")) {
                    configuracion.activarComprobacionMonitores();
                    System.out.println("Comprobación de monitores ACTIVADA");
                }
                break;
            case 16:    //  ESTADO

                mostrarEstado();
                break;
            case 17:    // IMPRIMIR

                if (co.params[1].startsWith("LIST")) {
                    imprimirListado();
                }
                break;
            case 18:       // ESTADO COLA

                gestorColas.informarEstadoCola();
                break;
            case 19:    // PING

                ping(co.params[1]);
                break;
            case 20:    // RUN SCRIPT EN UN OPERADOR

                if (co.params.length < 3 || co.params[1].equals("")) {
                    System.err.println("Faltan parámetros");
                    return true;
                }
                gestorColas.operadorRun(co.params);
                break;
            case 21:   // RUN SCRIPT EN TODOS LOS OPERADORES

                if (co.params.length < 2 || co.params[1].equals("")) {
                    System.err.println("Faltan parámetros");
                    return true;
                }
                co.params[0] = null; // marcamos con null el primer parametro para que se sepa que son TODOS
                if (co.params[1].startsWith("REIN")) {
                    gestorColas.operadores.reiniciar();
                } else {
                    gestorColas.operadorRun(co.params);
                }
                break;
            case 22:  // HUECOS
                if (co.params[1].startsWith("GEST")) {
                    gestorColas.gestores.listarHuecos();
                }
                break;
            // case 23: ver mas arriba (ACTIVAR)
            case 24:       // DEPURACION
                configurarDepuracion(co.params[1]);
                break;
            case 25:       // HORA
                gestorColas.gestores.pedirHoraGestores();
                break;
            default:
                System.out.println("ERROR. COMANDO NO IMPLEMENTADO");
        }
        return true;
    }

    void imprimirListado() {
        ImpresionListadoCita implis = new ImpresionListadoCita();
        implis.imprimir();
    }

    void ping(String param) {
        if (param.equals("NO")) {
            if (pinger != null) {
                pinger.parar();
                pinger = null;
            }
        } else {
            if (pinger == null) {
                pinger = new Pinger();
                generaLogPing();
            }
            gestorColas.ping(pinger, param);
        }
    }

    public void pingCliente(servidor.clientes.Cliente cli) {
        if (pinger == null) {
            pinger = new Pinger();
            generaLogPing();
        }
        pinger.nuevoDestino(cli);
        pinger.comenzar(180);
    }

    void generaLogPing() {
        java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("ddMMyyyy");
        String cadenaFecha = sdf.format(new Date());
        String nombre = "logPing_" + cadenaFecha + ".log";
        File logping = new File(nombre);
        if (!logping.exists()) {
            logMensajesSalientes = new LogGenerico(nombre, "Ping a clientes");
        }
    }

    public void test(String[] params) {
        listaHoy.crearTareaCierreYa();
    }

    void arrancarServidorHttp() {
        consola.desactivar();
        servidorHttp = new servidor.http.ServidorHttp();
        servidorHttp.start();
        consola.activar();
        configuracion.usuariosAutorizados.add("ateneo:oenetA");
        configuracion.usuariosAutorizados.add("ateneo:niveluno");
    }

    void mostrarEstado() {
        DecimalFormat dcf = new DecimalFormat("###,###,###");
        String[] datos = gestorColas.obtenerEstado();
        long memTotal = Runtime.getRuntime().totalMemory();
        long memOcupada = memTotal - Runtime.getRuntime().freeMemory();
        System.out.println("\n" + consola.getTitle() + "\n"
                + "corriendo en " + System.getProperty("java.vm.name") + " " + System.getProperty("java.version") + "\n"
                + "   memoria total:   " + dcf.format(memTotal / 1024) + " K\n"
                + "   memoria ocupada: " + dcf.format(memOcupada / 1024) + " K\n"
                + "ESTADO DEL SERVIDOR:\n"
                + "Modo:               " + datos[0] + "\n"
                + "Comprob. monitores: " + datos[1] + "\n"
                + "Recepcionista:      " + datos[2] + "\n"
                + "Presentes:          " + datos[3] + "\n"
                + "Operadores:         " + datos[4] + "\n"
                + "TURNO:              " + datos[5] + "\n"
                + "Prior. cita previa: " + datos[6] + "\n"
                + "Gestión huecos:     " + datos[7] + "\n"
                + "Base de datos en:   " + datos[8]);
        if (datos[9].equals("RECUP SI")) {
            System.out.println("* ACTIVADO MODO RECUPERACION SQLSERVER * \n");
        }
    }

    void configurarDepuracion(String modo) {
        switch (modo) {
            case "SI":
                logMensajes.abrir();
                guardarMensajes = true;
                break;
            case "NO":
                logMensajes.cerrar();
                guardarMensajes = false;
                break;
        }
        System.out.println("DEPURACION: ");
        System.out.println(" Guardar mensajes: " + (guardarMensajes ? "SI" : "NO"));
    }

    void mostrarAyuda() {
        System.out.println("Comandos implementados:\n"
                + "LISTAR\n"
                + "    listar clientes conectados\n"
                + "LISTAR ADMINISTRADORES\n"
                + "LISTAR GESTORES\n"
                + "LISTAR OPERADORES\n"
                + "LISTAR MONITORES\n"
                + "    listar solo los especificados\n"
                + "TURNO M ó TURNO T\n"
                + "    forzar cambio de turno a MAÑANA o TARDE.\n"
                + "RELEER\n"
                + "    recargar a memoria todas las tablas\n"
                + "RESET CONTADORES\n"
                + "    poner a CERO numeradores de tiques\n"
                + "CARGAR MESAS\n"
                + "    recargar tabla de PUESTOS con asignación de capacidades a mesas\n"
                + "MATAR TODOS ó NUM_MESA\n"
                + "    desconecta todos los operadoes o la mesa indicada\n"
                + "DESACTIVAR MONITORES\n"
                + "    desactivar comprobación de monitores\n"
                + "IMPRIMIR LISTADO\n"
                + "    imprimir lista de cita previa en su estado actual\n"
                + "ESTADO ó VERSION\n"
                + "    mostrar la versión del programa\n"
                + "    y el estado actual del servicio\n"
                + "AYUDA ó HELP ó ?\n"
                + "    mostrar esta ayuda\n"
                + "SALIR ó QUIT ó EXIT\n"
                + "    cerrar el programa\n"
                + "\nTodos los comandos pueden abreviarse a las 4 primeras letras\n");

    }

    static String pideVariableEntorno(String varName) {
        try {
            return System.getenv(varName);
        } catch (Exception exc) {
            return "";
        }
    }

    public static void main(String[] args) {
        // Punto principal de entrada
        Configuracion.comprobarDEBUG();
        ServidorMain sm = new ServidorMain();
        sm.args = new Parametros(args);
//        if (!sm.args.contiene("ejecutarSinDescargar")) {
//            sm.actualizar();
//        }
//        if (!sm.configuracion.modoTest) {
//            ActualizadorATENEO.envia_datos_servidor(sm.configuracion.codigoCentro);
//        }
        sm.iniciar();
    }

}
