/* 
* 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 cargador.*;
import gestor.datos.*;
import java.awt.print.PrinterJob;
import java.util.*;
import java.util.logging.*;
import javax.print.*;
import javax.swing.*;
import gestor.utiles.*;
import java.awt.*;
import java.io.File;

public final class Main extends javax.swing.JFrame implements cargador.ILanzable {

    //<editor-fold desc=" 1.Variables ">
    public String numeroGestor;
    int numeroMesas = 0;
    public String turno;
    public String turnoVisible;
    public boolean vistaCitaPrevia = false;
    public boolean vistaRenta = false;
    public boolean filtrarTerminados = false;
    public boolean mostrarPuestosConfigurados = false;
    public Comunicaciones comunicaciones;
    String numRegCandidatos = "xx";
    TablaCandidatos candidatos;
    TablaHuecos huecos;
    TablaColas colas;
    LinkedList<String> mensajesPendientes = new LinkedList<>();
    public Configuracion conf;
    Parametros args;
    ImpresorTicket impresorTicket;
    public boolean gestionHuecos = false;
    public static Logger log;
    LogGenerico logImpresora = null;
    LogGenerico logFracasoHueco = null;
    public LectorSmartCard lectorSC = null;
    boolean sinDnie = false;
    int registrosLeidos;
    int registrosEsperados;
    

    //</editor-fold>
    public Main() {
        conf = Configuracion.instanciaUnica();
        if (!conf.cargar()) {
            System.exit(-1);
        }
        Global.main = this;
        // cambiar color de los ToolTips
        javax.swing.UIManager.put("ToolTip.background", java.awt.Color.yellow);
        preparaLogging();
        initComponents();
        cargarLogo();
    }

    void cargarLogo() {
        File logo = new File("imagenes/SplashAteneo.jpg");
        ImageIcon icono;
        if(logo.exists()) {
            icono = new javax.swing.ImageIcon(logo.getAbsolutePath());            
        } else {
            icono = new javax.swing.ImageIcon(getClass().getResource("/recursos/Splash_renta.jpg"));
        }
        jLabel1.setSize(icono.getIconWidth(), icono.getIconHeight());
        this.setSize(icono.getIconWidth(), icono.getIconHeight());
        jLabel1.setIcon(icono);
        this.repaint();
    }
    
    public void registrarVentanaEnLectorSC(ISmartCardAvisable ventana) {
        if (lectorSC != null) {
            lectorSC.registrarVentanaAvisable(ventana);
        }
    }

    void preparaLogging() {
        try {
            log = Logger.getLogger("Logger");
            Handler fh = new FileHandler("Gestor.log");
            fh.setFormatter(new SimpleFormatter());
            log.addHandler(fh);
            log.setLevel(Level.FINEST);
        } catch (Exception exc) {
            MsgBox("No se ha podido iniciar el proceso de LOG");
            System.exit(-1);
        }
        // borrar logs de tickets de mas de diez dias
        Global.borrarLogsAntiguos("logs", "logImpresora", 10);

    }

    void comprobarArgumentos() {
        if (args.contieneNoNulo("ip")) {
            String ip = args.valor("ip");
            if (ip.length() >= 8) {
                conf.ipServidor = ip;
                conf.gestorPrincipal = false;
            }
        }
        if (args.contiene("noDnie")) {
            sinDnie = true;
        }
    }

    void inicia() {
        colas = TablaColas.getTablaColas();
        preparaComunicaciones();
        preparaDatos();

        this.setVisible(false);
    }

    public void preparaImpresora() {
        String nombre = conf.impresora.trim().toLowerCase();
        if (!nombre.equals("")) {
            PrintService[] pservices = PrintServiceLookup.lookupPrintServices(null, null);
            boolean encontrado = false;
            for (PrintService pservice : pservices) {
                if (pservice.getName().toLowerCase().equals(nombre)) {
                    encontrado = true;
                    break;
                }
            }
            if (!encontrado) {
                nombre = "";
            }
        }
        while (nombre.equals("")) {
            try {
                PrinterJob pj = PrinterJob.getPrinterJob();
                pj.printDialog();
                nombre = pj.getPrintService().getName();
                conf.impresora = nombre;
                pj.cancel();
                conf.guardar();
            } catch (Exception exc) {
            }
        }
        impresorTicket = new ImpresorTicket(conf.impresora);
        impresorTicket.setNombrePlataforma(conf.centro);
        if (conf.codigosCorteTicket != null) {
            impresorTicket.setImprimirCorte(true);
        }
    }

    public String pedirUsuario() {
        String codigo = javax.swing.JOptionPane.showInputDialog(this, "Introduzca identificador de Red o NIF", System.getProperty("user.name"));
        if (codigo == null || codigo.trim().length() == 0) {
            return null;
        }
        if (codigo.length() >= 14) {
            codigo = codigo.substring(0, 13);
        }
        return codigo.trim() + "*";
    }

    void preparaComunicaciones() {
        comunicaciones = new Comunicaciones();
        String txt = "";
        if (!comunicaciones.abrir()) {
            if (conf.usandoUDP) {
                txt = "No se localiza el servidor ATENEO denominado " + conf.nombreServidor;
            } else {
                txt = "No se puede conectar con el servidor en " + conf.ipServidor + ":" + conf.puertoIpServidor;
                if (!conf.ipServidor.equals(conf.ipServidorSec)) {
                    txt += "\nni el de respaldo en " + conf.ipServidorSec + ":" + conf.puertoIpServidorSec;
                }
            }
            MsgBox(txt);
            cerrarAplicacion();
        }
        String codigoGestor = pedirUsuario();
        if (codigoGestor == null) {
            System.exit(0);
        }
        conf.codigoGestor = codigoGestor;
        comunicaciones.enviar(Comunicaciones.CONEXION, conf.codigoGestor, "0");
    }

    public void enviarHora() {
        try {
            Date hora = new Date();
            comunicaciones.enviar(Comunicaciones.ENVIO_HORA, hora.toString(), conf.codigoGestor);
        } catch (Exception exc) {}
    }

    public void conexionAceptada(Mensaje msj) {
        try {
            numeroGestor = msj.param(0);
            numeroMesas = msj.intParam(1);
            conf.margenRetraso = msj.intParam(2) * 60000;
            conf.margenPenalizacion = msj.intParam(3) * 60000;
            turno = msj.param(4);
            gestionHuecos = msj.boolParam(5);

            try {
                String horaActual = msj.param(6);
                String co = "cmd /C time " + horaActual;
                Runtime.getRuntime().exec(co);
            } catch (Exception exc) {
            }
            try {
                String fechaActual = msj.param(7);
                String co = "cmd /C date " + fechaActual;
                Runtime.getRuntime().exec(co);
            } catch (Exception exc) {
            }
            if (msj.contiene("mostrarpuestos")) {
                mostrarPuestosConfigurados = msj.boolValor("mostrarpuestos");
                if (mostrarPuestosConfigurados) {
                    numeroMesas = 0;
                }
            } else if (numeroMesas == 0) {
                mostrarPuestosConfigurados = true;
            }
            try {
                if (msj.param(8).equalsIgnoreCase("0")) {
                    conf.permitirNoIden = false;
                }
            } catch (Exception exc) {
            }
            turnoVisible = turno;

            arrancaVentanaPrincipal();
        } catch (NumberFormatException exc) {
            log.log(Level.SEVERE, "Error en los parametros del mensaje CONEXION ACEPTADA: {0}", msj);
        } catch (Exception exc) {
            log.log(Level.SEVERE, "Error al arrancar la ventana principal: {0}", exc.getMessage());
        }
    }

    void preparaDatos() {
        candidatos = TablaCandidatos.getTablaCandidatos();
        huecos = TablaHuecos.getTablaHuecos();
    }
    
    public void iniciaCargaCandidatos(String msj) {
        try {
            int numregistros = Integer.parseInt(msj);
            Global.principal.quitarOrdenGrid();
            candidatos.vaciar();
            candidatos.setNumElementos(numregistros);
            registrosLeidos = 0;
            registrosEsperados = numregistros;
            if (registrosEsperados == 0) {
                ajustesFinRegistrosCandidatos();
            }
        } catch (Exception exc) {
            exc.printStackTrace();
        }
    }

    public void nuevoRegistroCandidatos(String reg) {
        registrosLeidos++;
        candidatos.nuevoRegistro(reg);
        if (registrosLeidos >= registrosEsperados) {
            ajustesFinRegistrosCandidatos();
        }
    }

    void ajustesFinRegistrosCandidatos() {
        TablaPresentes.getTablaPresentes().recargarTabla(candidatos);
        candidatos.cargada = true;
        if (Global.principal != null) {
            if (Global.principal.solicitadaAperturaRelacion) {
                Global.principal.abrirVentanaCandidatos();
            }
            Global.principal.refrescarDatos(false);
        }
    }

    public void nuevoRegistroHuecos(String reg) {
        if (!reg.equals("FIN_REGISTROS")) {
            if (huecos.cargada) {
                huecos.vaciar();
            }
            huecos.nuevoRegistro(reg);
        } else {
            huecos.finCarga();
        }
    }

    public void nuevoCandidato(String reg) {
        String[] partes = reg.split("\\|", 2);
        RegistroCandidatos r = candidatos.nuevoRegistro(partes[1]);
        if (r == null) {
            Global.principal.msgBox("Error al recibir mensaje con tique: \n" + reg);
            return;
        }
        if (partes[0].equals(numeroGestor)) {
            imprimirTicket(r);
        }
        Global.principal.refrescarDatos(true);
    }

    public void huecoOcupado(String mensaje) {
        String[] params = Global.split(mensaje, '|');
        java.sql.Timestamp horaCita = java.sql.Timestamp.valueOf(params[0]);
        String cola = params[1];
        // Vamos a grabar los fracasos en la asignacion de huecos para depurar...
        if (logFracasoHueco == null) {
            logFracasoHueco = new LogGenerico("HuecosCancelados.log", "Huecos cancelados");
        }
        logFracasoHueco.escribir(Fecha.formatoHoraHMS(new Date()) + " -> " + Fecha.formatoHoraHM(horaCita) + " " + cola);
        // Eliminamos los huecos para que no se repita el intento...
        // pero hay un error, pues esos huecos no deberían existir ya.
        TablaHuecos.getTablaHuecos().eliminarTodos(cola, horaCita);
        MsgBox("La hora solicitada se ha ocupado. Solicite otra");
    }

    public void nuevoCandidatoNoPresente(String reg) {
        String[] cs = Global.split(reg, '|');
        int id = Integer.parseInt(cs[0]);
        String turnoReg = cs[9];
        if (!turnoReg.equals(turno)) {
            Global.principal.msgBox("Se reservó un hueco para un turno distinto del actual. \nNO SE EMITIRÁ TIQUE");
            return;
        }
        RegistroCandidatos r = candidatos.buscarPorId(id);
        if (r == null) {
            return;
        }
        if (JOptionPane.showConfirmDialog(this,
                "¿ Quiere marcar la nueva cita como PRESENTE y emitir el tique ?", "EMISIÓN DE TIQUE",
                JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) != JOptionPane.YES_OPTION) {
            return;
        }
        r.cambiaEstado("P", Fecha.ahora(), r.horaCita);
    }

    public void incorporarHuecos(String msj) {
        String[] cs = Global.split(msj, '|');
        huecos.incorporarCitas(cs[0], cs[1], cs[2]);
    }

    public void iniciarEnvioDeColas() {
        colas.marcarTodosNoActualizados();
    }

    public void nuevoRegistroColas(String sreg) {
        try {
            if (!sreg.equals("FIN_REGISTROS")) {
                RegistroCola reg = colas.nuevoRegistro(sreg);
                if (Global.principal != null && reg != null) {
                    Global.principal.cambiarEstadoCola(reg.cola, reg.cerrada, reg.colaEspecial);
                }
            } else {
                colas.borrarNoActualizados();
                if (Global.principal != null) {
                    Global.principal.eliminaFormNuevoCandidato();
                }
                comunicaciones.enviar(Comunicaciones.ENVIAR_TABLA_CANDIDATOS, "xx");
                colas.estaCompleta();
                if (Global.principal != null && Global.principal.solicitadaAperturaNuevo) {
                    Global.principal.abreFormNuevoCandidato(null);
                }
            }
        } catch (Exception exc) {
            log.warning(exc.getMessage());
        }
    }

    public void cambiarEstadoCola(String mensaje) {
        String[] params = Global.split(mensaje, '|');
        if (params.length < 3) {
            return;
        }
        RegistroCola rc = colas.buscar(params[0]);
        if (rc != null) {
            rc.cerrada = params[1].equals("si");
            if (Global.principal != null) {
                Global.principal.cambiarEstadoCola(params[0], rc.cerrada, rc.colaEspecial);
            }
        }
    }

    public void cargaEstimacionCandidatos(String msj) {
        String[] regs = Global.split(msj, '·');
        for (String reg : regs) {
            candidatos.cargaEstimacion(reg);
        }
        Global.principal.refrescarDatos(false);
    }

    public void cambiaEstadoCandidato(String msj) {
        candidatos.modificaRegistro(msj);
        Global.principal.refrescarDatos(false);
    }

    public void comunicaCambioEstado(RegistroCandidatos reg) {
        comunicaciones.enviar(Comunicaciones.ENVIO_MODIFICACION_CANDIDATO, numeroGestor, reg.toString());
    }

    public String getTurno() {
        return turno;
    }

    public String getTurnoVisible() {
        return turnoVisible;
    }

    public void cambiarFiltrosCandidatos() {
        setTurnoVisible(Global.principal.formCandidatos.vistaTurnoSeleccionada);
        vistaCitaPrevia = Global.principal.formCandidatos.verCitaPrevia;
        filtrarTerminados = Global.principal.formCandidatos.filtrarTerminados;
        vistaRenta = Global.principal.formCandidatos.verRenta;
        candidatos.filtrarTabla();
        Global.principal.refrescarDatos(false);
    }

    public void setTurnoVisible(String turnoRequerido) {
        if (turnoRequerido.equals("S")) {
            turnoVisible = turno;
        } else {
            turnoVisible = turnoRequerido;
        }
    }

    public void imprimirTicket(RegistroCandidatos reg) {
        RegistroCola rc = colas.buscar(reg.cola);
        if (conf.imprimirTicket) {
            impresorTicket.setHoraCalculada(reg.horaCalculada2);
            impresorTicket.setHoraEmision(reg.horaPresente);
            impresorTicket.setNumeroTicket(reg.numeroTicket);
            impresorTicket.setIdTicket("" + reg.id);
            impresorTicket.setNif(reg.nif);
            if (rc != null) {
                impresorTicket.setNombreCola(rc.descripcion);
                impresorTicket.setTextoTicket(rc.salaEspera);
            } else {
                impresorTicket.setNombreCola("Atención al público");
                impresorTicket.setTextoTicket("");
            }
            impresorTicket.print();
        } else {
            FormTicketVisual ftv = new FormTicketVisual(this, true);
            ftv.setSegundosFuera(10);
            ftv.setTextoEtiqueta(reg.numeroTicket);
            if (rc != null) {
                ftv.setTextoSala(rc.salaEspera);
            }
            ftv.setNif(reg.nif);
            ftv.setVisible(true);
        }
        guardarLogTicket(reg);
    }

    public void guardarLogTicket(RegistroCandidatos r) {
        if (logImpresora == null) {
            java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("ddMMyyyy");
            String cadenaFecha = sdf.format(new Date());
            String nombre = "logImpresora_" + cadenaFecha + ".log";
            File logimpre = new File(nombre);
            if (!logimpre.exists()) {
                logImpresora = new LogGenerico(nombre, "Impresora");
            }
        }
        logImpresora.escribir(r.nif + ";" + r.id + ";" + r.numeroTicket + ";" + r.cola + ";" + Fecha.formatoHoraHMS(new Date()));
    }

    void arrancaVentanaPrincipal() {
        FormPrincipal fp = new FormPrincipal(numeroMesas);
        Global.principal = fp;
        fp.setExtendedState(JFrame.MAXIMIZED_BOTH);
        fp.setVisible(true);
        preparaImpresora();
    }

    public void cerrarAplicacion() {
        try {
            System.exit(0);
        } catch (Exception exc) {
            log.info("Error cerrando la aplicación");
        }
    }

    void MsgBox(String msg) {
        JOptionPane.showMessageDialog(this, msg);
    }

    void comenzarAplicacion() {
        if (!sinDnie) {    // desactivar DNIe pasando 'noDnie' al jecutar
            lectorSC = new LectorSmartCard();
        }
        setLocationRelativeTo(null);
        setVisible(true);
        inicia();
    }

    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jLabel1 = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Gestor ATENEO");
        setUndecorated(true);
        setResizable(false);

        jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        jLabel1.setDoubleBuffered(true);
        jLabel1.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        jLabel1.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        getContentPane().add(jLabel1, java.awt.BorderLayout.CENTER);

        pack();
    }// </editor-fold>//GEN-END:initComponents

    public static void main(final String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                Main sm = new Main();
                sm.args = new Parametros(args);
                if (!sm.args.contiene("ejecutarSinDescargar")) {
                    cargador.Configuracion conf = new cargador.Configuracion();
                    conf.fichero = "Gestor.jar";
                    conf.tipoCliente = "2";
                    if (sm.conf.usandoUDP) {
                        conf.usandoUDP = true;
                        conf.nombreServidor = sm.conf.nombreServidor;
                    } else {
                        conf.ipServidor = sm.conf.ipServidor;
                        conf.ipServidorSec = sm.conf.ipServidorSec;
                    }
                    conf.ipPort = sm.conf.puertoIpServidor;
                    conf.ipPortSec = sm.conf.puertoIpServidorSec;
                    CargadorCliente cargador = new CargadorCliente(conf, sm);
                    cargador.lanzar("");
                } else {
                    sm.comprobarArgumentos();
                    sm.comenzarAplicacion();
                }
            }
        });
    }

    @Override
    public void lanzaCliente() {
        comprobarArgumentos();
        comenzarAplicacion();
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel jLabel1;
    // End of variables declaration//GEN-END:variables
}
