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

import java.sql.*;
import java.text.DecimalFormat;
import java.util.*;
import java.util.logging.Level;
import servidor.datos.base.*;
import servidor.utiles.*;

public class TablaHuecos extends MemTablaHuecos {

    DecimalFormat df1 = new DecimalFormat("0000");
    DecimalFormat df2 = new DecimalFormat("00");
    HashMap<String, String> rangos;
    String cadenaRangosHuecos = "";

    public TablaHuecos() {

    }

    public String buscarRangoHuecos(String cola) {
        try {
            if (rangos.containsKey(cola)) {
                return rangos.get(cola);
            }
            return cola;
        } catch (Exception exc) {
            return cola;

        }
    }

    public String buscarRangoHuecosPorCola(String cola) {
        try {
            if (rangos.containsKey(cola)) {
                return rangos.get(cola);
            }
        } catch (Exception exc) {
            return cola;
        }
        return cola;
    }

    public void modificarRangoHuecos(String[] lineas) {
        Connection conexion = BaseDatos.bd().conexion;
        borrarRango();
        for (String linea : lineas) {
            String[] campos = Global.split(linea, '=');
            if (campos.length == 2) {
                modificarRangoenBD(conexion, campos[0], campos[1]);
            }
        }
        cargarTablaRangoHuecos();
    }

    public void borrarRango() {
        try {
            Connection conexion = BaseDatos.bd().conexion;
            Statement stmt = conexion.createStatement();
            stmt.execute("DELETE FROM RangoHuecos ");
            cadenaRangosHuecos = "";
            rangos.clear();
        } catch (Exception exc) {
            servidor.ServidorMain.log.log(Level.WARNING, "TablaHuecos.borrarRango:{0}", exc.getMessage());
        }
    }

    void modificarRangoenBD(Connection conexion, String origen, String destino) {

        try {
            Statement stmt = conexion.createStatement();
            ResultSet rs = stmt.executeQuery("SELECT Count(*) as Total FROM RangoHuecos WHERE Origen = '" + origen + "' ");
            rs.next();
            int p = rs.getInt("Total");
            rs.close();
            if (p == 0) {
                stmt.execute("INSERT INTO RangoHuecos (Origen, Destino) VALUES ('" + origen + "','" + destino + "')");
            } else {
                stmt.execute("UPDATE RangoHuecos SET Destino = '" + destino + "' WHERE Origen = '" + origen + "' ");
            }
            stmt.close();
        } catch (Exception exc) {
            servidor.ServidorMain.log.log(Level.WARNING, "TablaHuecos.modificarRang:{0}", exc.getMessage());
        }

    }

    public void cargarTablaRangoHuecos() {
        try {
            if (rangos == null) {
                rangos = new HashMap<>();
            }
            rangos.clear();
            cadenaRangosHuecos = "";
            StringBuilder sb = new StringBuilder("");
            Connection conexion = BaseDatos.bd().conexion;
            ResultSet rs;
            Statement stmt = conexion.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
            rs = stmt.executeQuery("SELECT Origen, Destino FROM RangoHuecos");
            while (rs.next()) {
                String colaD = rs.getString(2);
                String colaO = rs.getString(1);
                rangos.put(colaO, colaD);
                sb.append(colaO).append('=').append(colaD).append('|');
            }
            if (sb.length() > 0) {
                sb.setLength(sb.length() - 1);
            }

            rs.close();
            cadenaRangosHuecos = sb.toString();
            stmt.close();
        } catch (Exception exc) {
            servidor.ServidorMain.log.log(Level.WARNING, "TablaHuecos.CargarRango:{0}", exc.getMessage());
        }
    }

    public boolean rangosTieneContenido() {
        return cadenaRangosHuecos.length() > 2;
    }

    public String getcadenaRangos() {
        return cadenaRangosHuecos;
    }

    public String buscarRegistroPorId(int id) {
        return buscarId(id).registro();
    }

    public RegistroHuecos horaCitaDisponible(Timestamp horaDeseada, String cola) {
        RegistroHuecos encontrado = null;
        String colaR = buscarRangoHuecos(cola);
        for (MemRegistro fila : filas) {
            RegistroHuecos reg = (RegistroHuecos) fila;
            if (reg.getCola().equals(colaR) && reg.getHoraCita().equals(horaDeseada)) {
                encontrado = reg;
                break;
            }
        }
        if (encontrado != null) {
            delete(encontrado);
        }
        return encontrado;
    }

    public ArrayList<RegistroHuecos> generarUnHueco(String cola, String turno, Timestamp hInicio) {
        ArrayList<RegistroHuecos> generados = new ArrayList<>();
        String colaR = buscarRangoHuecosPorCola(cola);
        RegistroHuecos reg = new RegistroHuecos();
        reg.setCola(colaR);
        reg.setTurno(turno);
        reg.setHoraCita(hInicio);
        generados.add(reg);
        return generados;
    }

    public ArrayList<RegistroHuecos> generarHuecos(String cola, String turno, Timestamp hInicio, Timestamp hFin, int duracion, int puestos) {
        long inicio = hInicio.getTime();
        long delta = duracion * 60000L;
        Timestamp t1 = hInicio;
        Timestamp t2 = new Timestamp(inicio + delta);
        GregorianCalendar gc = new GregorianCalendar();
        gc.setTime(t1);
        String colaR = buscarRangoHuecosPorCola(cola);
        ArrayList<RegistroHuecos> generados = new ArrayList<>();
        while (t2.equals(hFin) || t2.before(hFin)) {
            for (int i = 0; i < puestos; i++) {
                RegistroHuecos reg = new RegistroHuecos();
                reg.setCola(colaR);
                reg.setTurno(turno);
                reg.setHoraCita(t1);
                generados.add(reg);
            }
            inicio += delta;
            t1 = new Timestamp(inicio);
            t2 = new Timestamp(inicio + delta);
        }
        return generados;
    }

    public ArrayList<String[]> generarAntiHuecos(String cola, String turno, Timestamp hInicio, Timestamp hFin, int duracion, int puestos) {
        long inicio = hInicio.getTime();
        long delta = duracion * 60000L;
        String colaR = buscarRangoHuecosPorCola(cola);
        Timestamp t1 = hInicio;
        Timestamp t2 = new Timestamp(inicio + delta);
        ArrayList<String[]> generados = new ArrayList<>();
        while (t2.equals(hFin) || t2.before(hFin)) {
            String[] params = new String[3];
            params[0] = colaR;
            params[1] = t1.toString();
            params[2] = String.valueOf(-puestos);
            generados.add(params);
            inicio += delta;
            t1 = new Timestamp(inicio);
            t2 = new Timestamp(inicio + delta);
        }
        return generados;
    }

    public void incorporarHuecos(ArrayList<RegistroHuecos> al) {
        for (RegistroHuecos reg : al) {
            try {
                insert(reg);
            } catch (Exception exc) {
                servidor.ServidorMain.log.log(Level.WARNING, "Error al incorporar huecos: {0}", reg.toString());
            }
        }
    }

    public String ocuparHuecos(String cola, String sHora, String sCuantos) {
        java.sql.Timestamp hora = java.sql.Timestamp.valueOf(sHora);
        int cuantos = Integer.parseInt(sCuantos);
        for (int i = 0; i < cuantos; i++) {
            if (horaCitaDisponible(hora, cola) == null) {
                return "no hay huecos " + cola + " " + sHora + " " + sCuantos + " filas size " + filas.size();
            }
        }
        return "OK";
    }

    public String mapaHuecos(String cola, String turno) {
        Timestamp ahora = Fecha.ahora();
        String colaR = buscarRangoHuecos(cola);
        ArrayList<RegistroHuecos> al = new ArrayList<>();
        for (MemRegistro fila : filas) {
            RegistroHuecos reg = (RegistroHuecos) fila;
            if (reg.getCola().equals(colaR) && reg.getTurno().equals(turno) && reg.getHoraCita().after(ahora)) {
                al.add(reg);
            }
        }
        if (al.size() > 0) {
            return mapaHuecos(al);
        }
        return null;
    }

    public String mapaHuecos(ArrayList<RegistroHuecos> regs) {
        Calendar cal = new GregorianCalendar();
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        long lasSeis = cal.getTimeInMillis() / 60000L;

        TreeMap<Timestamp, Integer> citas = new TreeMap<>();
        for (RegistroHuecos reg : regs) {
            Timestamp horaCita = reg.getHoraCita();
            int n = 1;
            if (citas.containsKey(horaCita)) {
                n = citas.get(horaCita) + 1;
            }
            citas.put(horaCita, n);
        }
        if (citas.size() > 0) {
            StringBuilder sb = new StringBuilder(250);
            for (Map.Entry<Timestamp, Integer> par : citas.entrySet()) {
                long minutos = par.getKey().getTime() / 60000L;
                int n = par.getValue();
                sb.append(df1.format(minutos - lasSeis)).append(df2.format(n));
            }
            return sb.toString();
        }
        return null;
    }

    public RegistroHuecos dameCitaDisponible(String cola, String turno) {
        RegistroHuecos encontrado = null;
        String colaR = buscarRangoHuecos(cola);
        Timestamp ahora = Fecha.ahoraRestada(60000 * 4);
        for (MemRegistro fila : filas) {
            RegistroHuecos reg = (RegistroHuecos) fila;
            if (reg.getCola().equals(colaR) && reg.getHoraCita().after(ahora)) {
                encontrado = reg;
                break;
            }
        }
        if (encontrado != null) {
            delete(encontrado);
        }
        return encontrado;
    }

    public void borarCaducados() {
        try {
            Timestamp ahora = Fecha.ahoraRestada(60000 * 7);
            int p = filas.size();
            for (int i = 0; i < filas.size(); i++) {
                RegistroHuecos reg = (RegistroHuecos) filas.get(i);
                if (reg.getHoraCita().before(ahora)) {
                    delete(reg);
                    i--;
                }
            }

        } catch (Exception exc) {
            servidor.ServidorMain.log.warning("Error al Eliminar huecos Caducados ");
        }
    }
}
