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

import java.util.*;
import java.util.logging.Level;
import servidor.clientes.*;
import servidor.comunicaciones.*;
import servidor.datos.base.*;

public class EstimadorRetrasos {

    GestorColas gestor;
    ArrayList<OperadorDisp> operadores;
    Date finDelMundo = new Date(Long.MAX_VALUE);
    java.sql.Timestamp finDelMundoTs = new java.sql.Timestamp(Long.MAX_VALUE);
    private final long[] tiemposMedios = new long[255];

    public EstimadorRetrasos(GestorColas elGestor) {
        gestor = elGestor;
        cargarTiempos();
    }

    final void cargarTiempos() {
        int n = gestor.tablaColas.count();
        for (int i = 0; i < n; i++) {
            RegistroColas reg = gestor.tablaColas.registro(i);
            if (reg.getCola().length() == 1) {
                int idx = (int) reg.getCola().charAt(0);
                tiemposMedios[idx] = reg.getTiempoMedio() * 1000;
            }
        }
    }

    long tiempoMedioCola(String cola) {
        return tiemposMedios[(int) cola.charAt(0)];
    }

    public void estimar(CursorPresentes presentes) {
        try {
            cargarOperadores();
            presentes.actualizar(finDelMundoTs, false);
            while (presentes.haySiguiente()) {
                RegistroCandidatos reg = (RegistroCandidatos) presentes.siguiente();
                if (reg.getCola().length() > 1) {
                    continue;
                }
                OperadorDisp op = buscarOperador(reg.getCola());
                if (op != null) {
                    if (op.horaLibre != null) {
                        reg.setHoraEstimada(op.horaLibre);
                        op.horaLibre = horaIncrementada(op.horaLibre, reg.getCola(), reg.getCitaMultiple());
                    }
                } else {
                    reg.setHoraEstimada(null);
                }
            }
        } catch (Exception exc) {
            servidor.ServidorMain.log.log(Level.WARNING, "ERROR en proceso ''estimar''\n{0}", exc.getMessage());
        }
    }

    Date horaIncrementada(Date dHora, String cola, int citas) {
        long hora = dHora.getTime();
        long delta = tiempoMedioCola(cola);
        return new Date(hora + (delta * citas));
    }

    public void cargarOperadores() {
        try {
            operadores = new ArrayList<>(gestor.operadores.size());
            for (Operador opLibre : gestor.operadores.libres) {
                operadores.add(new OperadorDisp(opLibre));
            }
            for (Operador op : gestor.operadores) {
                if (op.getEstado() == 4) {
                    operadores.add(new OperadorDisp(op));
                }
            }
        } catch (Exception exc) {
            System.err.println("ESTIMADOR.Error en cargarOperadores");
            exc.printStackTrace();
        }
    }

    OperadorDisp buscarOperador(String cap) {
        try {
            Date minHora = finDelMundo;
            OperadorDisp elegido = null;
            for (OperadorDisp op : operadores) {
                if (op.caps.contains(cap)) {
                    if (op.horaLibre.before(minHora)) {
                        minHora = op.horaLibre;
                        elegido = op;
                    }
                }
            }
            return elegido;
        } catch (Exception exc) {
            System.err.println("ESTIMADOR. Error en buscarOperador:" + exc.getMessage());
            return null;
        }
    }

    class OperadorDisp {

        public HashSet<String> caps;
        public Date horaLibre;
        public String codigo;

        public OperadorDisp(Operador op) {
            codigo = op.getNombre();
            caps = new HashSet<>();
            for (Iterator it = op.iteradorCapacidades(); it.hasNext();) {
                Operador.DatosCapacidad dc = (Operador.DatosCapacidad) it.next();
                if (dc.Actual) {
                    caps.add(dc.nombre);
                }
            }
            Date ahora = new Date();
            if (op.getEstado() == 2) {
                horaLibre = ahora;
            } else {
                if (op.horaUltimaAsignacion == null || op.colaActual == null) {
                    horaLibre = ahora;
                } else {
                    horaLibre = horaIncrementada(op.horaUltimaAsignacion, op.colaActual, op.citasActuales);
                    if (horaLibre.before(ahora)) {
                        horaLibre = ahora;
                    }
                }
            }
        }
    }
}
