package es.ejie.frmk.infraestructura.utilidades.concurrencia;

import es.ejie.frmk.Q70Factoria;
import es.ejie.frmk.control.excepciones.Q70FrameworkException;
import es.ejie.frmk.control.excepciones.Q70GestorDeExcepcionesServidor;
import es.ejie.frmk.infraestructura.logs.base.Q70LogInterno;
import es.ejie.frmk.infraestructura.traza.Q70TraceLevel;
import es.ejie.frmk.infraestructura.utilidades.constantes.Q70UtilidadesConstantes;
import es.ejie.frmk.infraestructura.utilidades.excepciones.Q70UtilidadesExcepcion;

/**
 * Clase que actúa como candado hasta que todos los threads hayan salido de la
 * zona crítica.
 * @version 2.0 Fecha: 23-mar-2006
 */
public class Q70LockReconfigureThread {
	
	// Referencia a la clase que contiene las variables que condicionan el bloqueo/desbloqueo.
	private Q70Lock lock = null;
	
	/**
	 * Constructor privado para que se use el otro constructor obligatoriamente.
	 */
	private Q70LockReconfigureThread(){
	}
	
	public Q70LockReconfigureThread(Q70Lock lock) {
		this.lock = lock;
	}
	
	/**
	 * Método que activa el bloqueo de threads en la entrada de la zona
	 * crítica y bloquea la ejecución hasta que todos los threads hayan salido
	 * de la zona crítica.
	 */
	synchronized protected void suspender() throws Q70FrameworkException{
		// Activa el bloqueo
		lock.setBloqueo(true);
		// En caso de que haya algún thread en la zona crítica...
		if (lock.getContador()>0) {			
			try {
				// suspendo la ejecución.
				wait();
			} catch (InterruptedException e) {
				// Si el componente a reconfigurar es LOGS o TRAZAS, utilizamos Q70LogInterno.
				if (lock.isComponenteLogsTraza()) {
					Q70LogInterno.log("\nERROR!!! Se ha intentado suspender un thread controlador ya suspendido.\n");
					throw new Q70FrameworkException(Q70UtilidadesConstantes.UTILIDADES_LOCK,this.getClass().toString(),"suspender","Se ha producido un error en el método suspender.",e);										
				} else {
					Q70Factoria.getTraza().trace(Q70UtilidadesConstantes.UTILIDADES_LOCK, Q70TraceLevel.FATAL, "\nERROR!!! Se ha intentado suspender un thread controlador ya suspendido.\n");
					Q70GestorDeExcepcionesServidor.getSingleton().recogerThrowable(new Q70UtilidadesExcepcion(Q70UtilidadesConstantes.UTILIDADES_LOCK, this.getClass().getName(),"suspender","ERROR!!! Se ha intentado suspender un thread controlador ya suspendido.", e));					
				}
			}			
		}
	}
	
	/**
	 * Método que resta uno al contador de threads en la zona crítica y en caso
	 * de que no haya ningún thread en la zona crítica, desbloquea la ejecución.
	 */
	synchronized protected void salidaZonaCritica(){
		// Resto uno al contador de threads en la zona crítica.
		lock.menos();
		// Cuando no haya ningún thread en la zona crítica...
		if (lock.getContador()==0) {
			// y esté activado el bloqueo...
			if (lock.isBloqueo()) {
				// activo la ejecución.
				notify();
			}
		}
	}
}