package com.fp.common.thread;

import java.util.ArrayList;
import java.util.List;

import com.fp.common.logger.APPLogger;

/**
 * Clase orquestadora de la ejecucion de hilos, controla el numero de operaciones que se ejecutan en paralelo.
 * @author Jorge Vaca
 * @version 2.1
 */
/**
 * @author Jorge Vaca
 * @version 2.1
 */
/**
 * @author Jorge Vaca
 * @version 2.1
 */
public class Monitor {

	/** Indica que para el proceso en ejecucion. */
	private boolean stop = false;
	
	/** Contador de hilos activos. Cada hilo procesa una cuenta en el fin de dia.*/
	private Long count = Long.valueOf(0);

	/** Monitos de hilo. */
	private boolean available = true;

	/** Monitor de finaliación de ejecución de hilos. */
	private boolean end = true;
	/** Maximo numero de hilos a levantar en la ejecución de un batch. */
	protected Integer maxthreads = 0;

	/** Lista que almacena el numero del hilo a procesar. */
	private List<Integer> lmaxthreads; 
	
	
	/**
	 * Crea una instancia de Monitor.
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public Monitor(Integer pMaxthreads) throws Exception{
		maxthreads = pMaxthreads;
		lmaxthreads = new ArrayList();
		for (int i = 1; i <= maxthreads; i++) {
			lmaxthreads.add(i);
		}
	}

	
	/**
	 * Metodo que permite controlar la finalizacion de ejecucion de un hilo, resta el contador en 1 para permitir que 
	 * la aplicacion levante la ejecucion de un hilo adicional. 
	 * @param pThreadNumber	Numero de hilo en ejecucion, se utiliza en el numero de mensaje con el cual se ejecuta el fin de dia. 
	 * @throws Exception
	 */
	public synchronized void removeCounter(Integer pThreadNumber) throws Exception {
		if (!available) {
			wait();
		}
		try{
			available = false;
			count--;
			lmaxthreads.add(pThreadNumber);
		}finally{
			available = true;
			if (count <= 0) {
				end = true;
			}
			this.notify();
		}
	}


	/**
	 * Metodo que controla el inicio de ejecucion de un hilo. Suma 1 al contador de hilos en ejecucion.
	 * @return	Integer	Numero de hilo en ejecuvion. 
	 * @throws Exception
	 */
	public synchronized Integer addCounter() throws Exception {
		if (!available || count >= this.maxthreads) {
			wait();
		}
        Integer numthread =0;
        try{
			available = false;
			int icount = this.count.intValue();
			icount++;
			this.count = Long.valueOf(icount);
			if(!lmaxthreads.isEmpty()){
				numthread = lmaxthreads.get(0);
				lmaxthreads.remove(0);			
			}		
        }finally{
           available = true;
		   end = false;
		   this.notify();
        }
		return numthread;
	}


	/**
	 * Metodo que controla la finalizacion de ejecucion de todos los hilos que se levantaron en la ejecucion del batch. 
	 * @throws Exception
	 */
	public synchronized void finish() throws Exception {
		while (!end) {
			wait();
		}
		try {
			// this.setStatusProcessed();
			// TODO Change status to executed
			APPLogger.getLogger().info("Fin Prceso de Batch ");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Metodo que entrega el numero de hilos en ejecucion. 
	 * @return	Long
	 */
	public Long getCount() {
		return count;
	}


	/**
	 * Entrega el valor de: stop
	 * @return boolean
	 */
	public boolean isStop() {
		return stop;
	}


	/**
	 * Fija el valor de: stop
	 * @param stop valor a almacenar en el objeto.
	 */
	public void setStop(boolean stop) {
		this.stop = stop;
	}



	
	
}