import java.util.ArrayList;
import java.lang.StringBuffer;

public class Horario{

	ArrayList trabajos; // ordenada por hora del inicio real

	int [] horasLibres = new int [168];  //las horas son de 0 a 167
	// -1 indica que la hora está libre,
	// un valor >= 0 indica el número de trabajo
	
	public Horario(){
		trabajos = new ArrayList();
		for(int i=0; i<horasLibres.length; i++){
			horasLibres[i]=-1;
		}
	}


	// Da un nuevo horario que es la copia de otro
	public Horario(Horario orig){
		trabajos = new ArrayList();
		for (int i=0; i<orig.trabajos.size(); i++) {
			trabajos.add( (Trabajo) orig.trabajos.get(i) );
		}
			
		for(int i=0; i<horasLibres.length; i++){
			horasLibres[i]=orig.horasLibres[i];
		}
	}

	public int numTrabajos(){
		return trabajos.size();
	}

	public double[] periodosLibres(){
		/*
		   Devuelve un array con:
		   [0]: número de horas libres en el horario
		   [1]: longitud media de los períodos de horas libres
		*/
		//el número de horas libres en el período actual de horas libres
		int acc=0;
		//el número de períodos de horas libres
		int numPer=0;
		
		//  (para calcular la media):
		// la suma de las longitudes de todos los períodos de horas libres
		int sumLong=0;
		
		//el número de horas libres
		int numHL=0;

		for (int i = 0; i<horasLibres.length; i++){
			if(horasLibres[i]==-1){
				numHL++;
				acc++;
			}
			else if (acc!=0){
				sumLong += acc;
				numPer++;
				acc = 0;
			}
		}
		double[] result = new double[2];
		result [0] = numHL;
		result [1] = (double)sumLong / numPer;
		
		return result;
		
	}
	
	public boolean contiene(Trabajo trabajo){

		for(int i=0; i<horasLibres.length; i++){
			if (trabajo.id == horasLibres[i]) return true;
		}
		return false;
	}
	
	public boolean compruebaLimites(Trabajo trabajo, int desplazamiento){
		// Devuelve falso si el trabajo queda fuera del horario
		if (trabajo.hora + desplazamiento < 1) return false;
		if (trabajo.hora + desplazamiento + trabajo.tamano > 168) return false;
		//167+0 1  168 > 168
		return true;
	}
	
	public boolean compruebaTolerancia(Trabajo trabajo, int desplazamiento){
		//   Comprueba si el desplazamiento está permitido
		// por la tolerancia del trabajo
		
		if (desplazamiento < 0){
			if (  Math.abs( desplazamiento ) > trabajo.izquierda  ) {
				return false;
			}
		}
		else {
			if ( desplazamiento > trabajo.derecha ) {
				return false;
			}
		}
		return true;
	}

	public boolean compruebaHorasLibres(Trabajo trabajo, int desplazamiento){

		// a: hora a la que debe empezar el trabajo que nos han pasado
		// b: hora a la que debe acabar
		int a=trabajo.hora+desplazamiento;
		int b= a + trabajo.tamano;

		a--; b--; //porque empieza en 0
		
		for(int i=a; i<b; i++){
			if(horasLibres[i] != -1) {
				//System.out.println("Hora i="+i+" ocupada. a="+a+" b="+b);
				return false;
			}
		}
		
		return true;
	}
		
		
		
		
	public boolean sePuedePoner(Trabajo trabajo, int desplazamiento){
			

		//comprueba límites
		if (!compruebaLimites(trabajo,desplazamiento))
			return false;

		//comprueba si el desplazamiento está permitido
		if (!compruebaTolerancia(trabajo,desplazamiento))
			return false;
		
		//si el horario está vacío, se puede poner
		if ( trabajos.size() == 0) return true;
		
		//comprueba si el trabajo está puesto
		if (contiene(trabajo))
			return false;
	
		//comprueba si las horas están libres
		if (!compruebaHorasLibres(trabajo,desplazamiento))
			return false;
		
		return true;		
	}		

	public boolean sePuedeQuitar(Trabajo trabajo){
		return contiene(trabajo);
	}
	public boolean sePuedeAjustar(Trabajo trabajo, int desplazamiento){
		if (!contiene(trabajo))
			return false;
		if (!compruebaLimites(trabajo,desplazamiento))
			return false;
		if (!compruebaTolerancia(trabajo, desplazamiento)){
			return false;
		}
		int a = trabajo.hora + desplazamiento;
		int b = a + trabajo.tamano;
		
		a--; b--;  //porque empieza en 0
		
		//   Un trabajo se puede ajustar si la nueva posición está libre
		// u ocupada por el mismo trabajo
		//
		for (int i=a; i<b; i++){
			if (!(horasLibres[i]==-1 || horasLibres[i]==trabajo.id)) return false;
		}
		
		return true;
	}

	public boolean sePuedeIntercambiar(Trabajo viejo, Trabajo nuevo){
		// cambiar viejo (dentro del horario) por nuevo (aún sin poner)
		// 
		if (!contiene(viejo))
			return false;
		if (contiene(nuevo))
			return false;
		Horario h = new Horario(this);
		h.quitar(viejo);
		return h.sePuedePoner(nuevo,0);
	}


	public void poner(Trabajo trabajo, int desplazamiento){
		int inicio = 0;
		int i = 0;
		int total = trabajos.size();
		Trabajo nuevo= new Trabajo (trabajo);
		nuevo.setEmpieza( trabajo.hora + desplazamiento );


		while (i<total){
			inicio = ((Trabajo)(trabajos.get(i))).empieza;
			if (inicio > nuevo.getEmpieza() ) break;
			i++;
		}
		trabajos.add(i,nuevo);
		// -1 porque trabajo.hora empieza en 1 y no en 0
		for(	i = nuevo.getEmpieza()-1;
			i<nuevo.getEmpieza()+nuevo.getTamano()-1;
			i++
			){
			horasLibres[i]=nuevo.getId();
		}
		//System.out.println(nuevo);
		//System.out.println(horasLibresToString());
	}

	public void quitar (Trabajo trabajo){
		int inicio = 0;
		int i = 0;
		int total = trabajos.size();

		while (i<total){
			if (((Trabajo)(trabajos.get(i))).esIgual(trabajo)) break;
			i++;
		}
 
		trabajos.remove(i);
		// -1 porque trabajo.hora empieza en 1 y no en 0
		for(i = trabajo.empieza-1; i<trabajo.empieza+trabajo.tamano-1; i++){
			horasLibres[i]=-1;
		}
	}

	public void ajustar (Trabajo trabajo, int desplazamiento) {
		quitar(trabajo);
		poner(trabajo, desplazamiento);
	}
		
	public void intercambiar (Trabajo viejo, Trabajo nuevo) {
		quitar(viejo);
		poner(nuevo,0);
	}
	
		
	public String toString(){
		StringBuffer buf=new StringBuffer();
		buf.append( "Horario de " + trabajos.size() + " trabajos:\n");
		int i=0;
		while ( i<trabajos.size() ) {
			buf.append( ((Trabajo)trabajos.get(i)).toString() + "\n");
			i++;
		}
		buf.append(horasLibresToString()+"\n");
		
		return buf.toString();
	}

	public String horasLibresToString(){
		StringBuffer buf = new StringBuffer();	

		buf.append("Horas ocupadas: \n");
		int j = 0;
		int id = -1;
		
		//-1 porque en la última hora no puede empezar un trabajo nuevo
		int n = horasLibres.length-1;

		for(int i=0; i<n; i++) {
			
			if(i%10==0) buf.append(" ");
			if (i%40==0) buf.append("\n");
			if (horasLibres[i] !=-1){
				if(id != horasLibres[i]){
					buf.append("X");
				}
				else{
					buf.append("x");
				}
				id = horasLibres[i];
				j++;
			}
			else{
				buf.append("_");
			}
		}
		
		buf.append("\n En el horario hay " + j + " horas ocupadas.\n"+
			" En el horario hay " + (n-j) + "  horas libres.");
		return buf.toString();
	}

}	


