/* 
* 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.datos;

import gestor.utiles.*;
import java.io.*;
import java.sql.Timestamp;
import java.util.*;
import gestor.utiles.Fecha;

public class TablaCandidatos {

    public static final int ORDEN_NIF = 0;
    public static final int ORDEN_NOMBRE = 1;
    public static final int ORDEN_HORACITA = 2;
    public static final int ORDEN_HORACALCULADA = 3;
    public static final int ORDEN_TICKET = 4;
    public static final int ORDEN_VINCULADA = 5;
    protected ArrayList<RegistroCandidatos> datosFiltrados;
    protected ArrayList<RegistroCandidatos> datosTotal;
    protected HashMap<Integer, RegistroCandidatos> indice;
    protected int orden = ORDEN_HORACITA;
    private static TablaCandidatos yo = null;
    public boolean cargada = false;

    public TablaCandidatos() {
        datosFiltrados = new ArrayList<>();
        datosTotal = new ArrayList<>();
        indice = new HashMap<>();
    }

    public static TablaCandidatos getTablaCandidatos() {
        if (yo == null) {
            yo = new TablaCandidatos();
        }
        return yo;
    }

    public void vaciar() {
        datosFiltrados.clear();
        datosTotal.clear();
        indice.clear();
    }

    @SuppressWarnings("unchecked")
    public TablaCandidatos clonar(boolean filtrado) {
        TablaCandidatos clon = new TablaCandidatos();
        if (filtrado) {
            clon.datosFiltrados = (ArrayList<RegistroCandidatos>) datosFiltrados.clone();
        } else {
            clon.datosFiltrados = (ArrayList<RegistroCandidatos>) datosTotal.clone();
        }
        return clon;
    }

    public void filtrarTabla() {
        datosFiltrados.clear();
        for (RegistroCandidatos rc : datosTotal) {
            if (filtrarRegistro(rc)) {
                datosFiltrados.add(rc);
            }
        }
    }

    public void cambiaTurno() {
        filtrarTabla();
    }

   // ******************************************
    // En este método se filtran los registro que aparecerán
    // en el grid de Candidatos. Actualmente: Turno, CitaPrevia y Terminados
    public boolean filtrarRegistro(RegistroCandidatos rc) {
        if (Global.main.filtrarTerminados && (rc.estado.equals("S") || rc.estado.equals("F"))) {
            return false;
        }
        if (Global.main.vistaCitaPrevia) {
            if (!rc.esCitaPrevia()) {
                return false;
            }
        }
        String turno = Global.main.getTurnoVisible();
        boolean enTurno = turno.equals(" ") || rc.turno.equals(turno);
        if (!enTurno) {
            return false;
        }
        if (Global.main.vistaRenta) {
            if (!rc.esRenta()) {
                return false;
            }
        }
        return true;
    }
   //*********************************************

    public RegistroCandidatos eliminar(int n) {
        RegistroCandidatos r = datosFiltrados.remove(n);
        return r;
    }

    public void setNumElementos(int numero) {
        datosTotal.ensureCapacity(numero);
        datosFiltrados.ensureCapacity(numero);
    }

    public int recordsCount() {
        return datosFiltrados.size();
    }

    public void ordena(Comparator<RegistroCandidatos> comparador) {
        Collections.sort(datosFiltrados, comparador);
    }

    public RegistroCandidatos nuevoRegistro(String reg) {
        try {
            RegistroCandidatos r = new RegistroCandidatos(this);
            r.leerRegistroCompleto(reg);

            if (indice.containsKey(r.id)) {
                r = indice.get(r.id);
                r.leerRegistroCompleto(reg);
            } else {
                datosTotal.add(r);
                indice.put(r.id, r);
            }
            boolean pasaFiltro = filtrarRegistro(r);
            if (pasaFiltro) {
                sustituirEnFiltrados(r);
            } else {
                eliminarDeFiltrados(r);
            }
            return r;
        } catch (DatosException exc) {
            exc.printStackTrace();
            return null;
        }
    }

    public void modificaRegistro(String reg) {
        try {
            RegistroCandidatos r = new RegistroCandidatos(this);
            r.leerRegistroCompleto(reg);
            if (indice.containsKey(r.id)) {
                r = indice.get(r.id);
                r.leerRegistroCompleto(reg);
            } else {
                throw new DatosException("HemosRecibidoUnRegistroQueNoExiste!!!");
            }
            boolean pasaFiltro = filtrarRegistro(r);
            if (pasaFiltro) {
                sustituirEnFiltrados(r);
            } else {
                eliminarDeFiltrados(r);
            }
        } catch (DatosException exc) {
            //TODO tratar esta excepcion, quizas devolver codigo de error al servidor?

        }
    }

    public void copiaRegistro(RegistroCandidatos nr) {
        datosFiltrados.add(nr);
    }

    public RegistroCandidatos getRegistroNum(int n) {
        if (n < 0 || n >= datosFiltrados.size()) {
            return null;
        }
        return datosFiltrados.get(n);
    }

   //<editor-fold desc="Busquedas">
    public RegistroCandidatos buscarPorId(int id) {
        for (RegistroCandidatos rb : datosFiltrados) {
            if (rb.id == id) {
                return rb;
            }
        }
        return null;
    }

    public int buscarPorIdEnTotal(int id) {
        for (int i = 0; i < datosTotal.size(); i++) {
            RegistroCandidatos rb = datosTotal.get(i);
            if (rb.id == id) {
                return i;
            }
        }
        return -1;
    }

    public boolean eliminarDeFiltrados(RegistroCandidatos r) {
        for (int i = 0; i < datosFiltrados.size(); i++) {
            if (datosFiltrados.get(i).id == r.id) {
                datosFiltrados.remove(i);
                return true;
            }
        }
        return false;
    }

    public void sustituirEnFiltrados(RegistroCandidatos r) {
        int n = datosFiltrados.size();
        for (int i = 0; i < n; i++) {
            if (datosFiltrados.get(i).id == r.id) {
                datosFiltrados.set(i, r);
                return;
            }
        }
        datosFiltrados.add(r);
    }

    public RegistroCandidatos buscarPorNif(String nif) {
        for (RegistroCandidatos rb : datosFiltrados) {
            if (rb.nif.startsWith(nif)) {
                return rb;
            }
        }
        return null;
    }

    public RegistroCandidatos buscarPorNifPresente(String nif) {
        int n = datosFiltrados.size();
        for (int i = 0; i < n; i++) {
            RegistroCandidatos rb = datosFiltrados.get(i);
            if (rb.nif.equals(nif) && rb.estado.equals("P")) {
                return rb;
            }
        }
        return null;
    }

    public RegistroCandidatos buscarPorNifyCola(String nif, String cola) {
        for (RegistroCandidatos rb : datosTotal) {
            if (rb.nif.equals(nif) && rb.cola.equals(cola) && (rb.estadoVacio() || rb.estado.equals("D"))) {
                return rb;
            }
        }
        return null;
    }

    public String buscarNombrePorNif(String nif) {
        int n = datosFiltrados.size();
        for (int i = 0; i < n; i++) {
            RegistroCandidatos rb = datosFiltrados.get(i);
            if (rb.nif.equals(nif)) {
                return rb.nombre;
            }
        }
        return "";
    }

    public int buscarHora(Timestamp h) {
        int n = datosFiltrados.size();
        for (int i = 0; i < n; i++) {
            RegistroCandidatos r = datosFiltrados.get(i);
            if (r.horaCita.compareTo(h) > 0) {
                return i;
            }
        }
        return -1;
    }

   //</editor-fold>
    public void cargaEstimacion(String msj) {
        String[] dat = Global.split(msj, '|');
        try {
            RegistroCandidatos r = indice.get(Integer.valueOf(dat[0]));
            if (r != null) {
                r.horaEstimada = Global.nzt(dat[1]);
            }
        } catch (NumberFormatException exc) {
            // No hacer nada aqui...
        }
    }

    public void igualarMesaYCola(RegistroCandidatos reg) {
        if (reg.citaMultiple > 1) {
            int n = datosFiltrados.size();
            for (int i = 0; i < n; i++) {
                RegistroCandidatos r = datosFiltrados.get(i);
                if (r.citaVinculada.equals(reg.citaVinculada) && r.citaMultiple > 1) {
                    r.cola = reg.cola;
                    r.operador = reg.operador;
                }
            }
        }
    }

    public void exportarNotificacionesAExcel(String path) {
        try {
            PrintStream salida = new PrintStream(new FileOutputStream(path, false));
            salida.println("NIF\tNombre\tNotificaciones");
            for (RegistroCandidatos reg : datosFiltrados) {
                String noti = reg.indicadorNotificaciones();
                if (noti != null && !noti.equals("-")) {
                    StringBuilder sb = new StringBuilder(reg.nif);
                    sb.append('\t').append(reg.nombre);
//               sb.append('\t').append(reg.nifConyuge);
//               sb.append('\t').append(reg.apeConyuge);
                    sb.append('\t').append(reg.indicadorNotificaciones());
                    salida.println(sb.toString());
                }
            }
            salida.close();
        } catch (IOException exc) {
        }
    }

    //<editor-fold desc="Vinculados ">
    public void cambiaEstadoVinculados(String codigoCita, String nuevoEstado, Timestamp horaPresente, Timestamp horaCalculada) {
        for (RegistroCandidatos r : datosFiltrados) {
            if (r.citaVinculada.equals(codigoCita) && !r.estado.equals("P") && r.citaMultiple > 1) {
                r.cambiaEstado(nuevoEstado, horaPresente, horaCalculada);
            }
        }
    }

    public int contarVinculados(String codigoCita) {
        int result = 0;
        for (RegistroCandidatos r : datosFiltrados) {
            if (r.citaVinculada.equals(codigoCita) && r.citaMultiple > 1) {
                result++;
            }
        }
        return result;
    }

    public int nifDistintos() {
        HashSet<String> norepes = new HashSet<>();
        for (RegistroCandidatos r : datosFiltrados) {
            if (!norepes.contains(r.nif)) {
                norepes.add(r.nif);
            }
        }
        return norepes.size();
    }

    public String getListaVinculados(String codigoCita, TablaCandidatos copia) {
        String cad = "";
        for (RegistroCandidatos r : datosFiltrados) {
            if (r.citaVinculada.equals(codigoCita) && r.citaMultiple > 1) {
                cad += r.nif + "  " + r.nombre + "\n";
                if (copia != null) {
                    copia.copiaRegistro(r);
                }
            }
        }
        if (copia != null) {
            copia.ordena(copia.obtenerComparador(TablaCandidatos.ORDEN_HORACITA, true));
        }
        return cad;
    }

    public void quitarEstadoVinculados(String codigoCita) {
        for (RegistroCandidatos r : datosFiltrados) {
            if (r.citaVinculada.equals(codigoCita)) {
                r.citaMultiple = 1;
                r.citaVinculada = "     ";
                Global.main.comunicaCambioEstado(r);
            }
        }
    }

    public void igualarHoraCalculada(java.sql.Timestamp horaCalculada) {
        for (RegistroCandidatos reg : datosFiltrados) {
            reg.horaCalculada = horaCalculada;
        }
    }

    public RegistroCandidatos primeroEnHora() {
        try {
            long ahoraMismo = System.currentTimeMillis();
            for (RegistroCandidatos reg : datosFiltrados) {
                int r = Global.compruebaHoraCalculada(ahoraMismo, reg.horaCita.getTime());
                if (r < 3) {
                    reg.horaCalculada = Global.calcularHora(r, reg.horaCita, ahoraMismo);
                    return reg;
                }
            }
        } catch (Exception exc) {
        }
        return null;
    }

   //</editor-fold>
    //<editor-fold desc="Comparadores">
    public Comparator<RegistroCandidatos> obtenerComparador(int orden, boolean asc) {
        Comparator<RegistroCandidatos> comparador = null;
        switch (orden) {
            case TablaCandidatos.ORDEN_NOMBRE:
                comparador = new ComparadorNombre(asc);
                break;
            case TablaCandidatos.ORDEN_NIF:
                comparador = new ComparadorNif(asc);
                break;
            case TablaCandidatos.ORDEN_VINCULADA:
                comparador = new ComparadorVinculada(asc);
                break;
            case TablaCandidatos.ORDEN_TICKET:
                comparador = new ComparadorTicket(asc);
                break;
            default:
                comparador = new ComparadorHoraCita(asc);
                break;
        }
        return comparador;
    }

    public class ComparadorNif implements Comparator<RegistroCandidatos> {

        boolean asc;

        public ComparadorNif(boolean asc) {
            this.asc = asc;
        }

        @Override
        public int compare(RegistroCandidatos r1, RegistroCandidatos r2) {
            if (asc) {
                return r1.nif.compareTo(r2.nif);
            } else {
                return r2.nif.compareTo(r1.nif);
            }
        }
    }

    public class ComparadorNombre implements Comparator<RegistroCandidatos> {

        boolean asc;

        public ComparadorNombre(boolean asc) {
            this.asc = asc;
        }

        @Override
        public int compare(RegistroCandidatos r1, RegistroCandidatos r2) {
            if (asc) {
                return r1.nombre.compareTo(r2.nombre);
            } else {
                return r2.nombre.compareTo(r1.nombre);
            }
        }
    }

    public class ComparadorVinculada implements Comparator<RegistroCandidatos> {

        boolean asc;

        public ComparadorVinculada(boolean asc) {
            this.asc = asc;
        }

        @Override
        public int compare(RegistroCandidatos r1, RegistroCandidatos r2) {
            if (asc) {
                return r1.citaVinculada.compareTo(r2.citaVinculada);
            } else {
                return r2.citaVinculada.compareTo(r1.citaVinculada);
            }
        }
    }

    public class ComparadorTicket implements Comparator<RegistroCandidatos> {

        boolean asc;

        public ComparadorTicket(boolean asc) {
            this.asc = asc;
        }

        @Override
        public int compare(RegistroCandidatos r1, RegistroCandidatos r2) {
            if (asc) {
                return r1.numeroTicket.compareTo(r2.numeroTicket);
            } else {
                return r2.numeroTicket.compareTo(r1.numeroTicket);
            }
        }
    }

    public class ComparadorHoraCita implements Comparator<RegistroCandidatos> {

        boolean asc;

        public ComparadorHoraCita(boolean asc) {
            this.asc = asc;
        }

        @Override
        public int compare(RegistroCandidatos r1, RegistroCandidatos r2) {
            java.sql.Timestamp t1 = Fecha.horaNula;
            java.sql.Timestamp t2 = Fecha.horaNula;
            if (asc) {
                t1 = r1.horaCita;
                t2 = r2.horaCita;
            } else {
                t1 = r2.horaCita;
                t2 = r1.horaCita;
            }
            if (t1 == null) {
                t1 = Fecha.horaNula;
            }
            if (t2 == null) {
                t2 = Fecha.horaNula;
            }
            int v = t1.compareTo(t2);
            if (v == 0) {
                t1 = r1.horaPresente;
                t2 = r2.horaPresente;
                if (t1 == null) {
                    t1 = Fecha.horaNula;
                }
                if (t2 == null) {
                    t2 = Fecha.horaNula;
                }
                return t1.compareTo(t2);
            }
            return v;
        }
    }

   //</editor-fold>
}
