package pckPlano;

/** Ultima atualizacao : 17-05-2001 
 * Autores : Claudio Copello - 980860
 *           Joao Porto - 981389
 *           Joao Guilherme - 981374
 *           Joyce Ynoue - 981414
 *           Eduardo Lins - 952302
 *           Fernando Viegas - 900508
 */

import pckDemanda.Encomenda;
import pckMapa.Trecho;
import pckMapa.Mapa;

public class ValidadorImpl extends Validador {

    
    public ValidadorImpl(){
	/** Construtor da classe
	 */
	mensagemErro = "";
    }

    public boolean pA( Plano planoAtendimento, Encomenda[] encomendas, Veiculo[] veiculos, Mapa mapa ){
	boolean v1 = rotas( planoAtendimento.rotas(), mapa );
	boolean v2 = encomendas( planoAtendimento, encomendas );
	boolean v3 = capacidade( planoAtendimento );

	return ( v1 && v2 && v3 );

    }    

    public boolean rotas( Rota[] planoRotas, Mapa mapa ){
	/** Validacao das rotas do Plano de Atendimento 
	 * Entrada: Plano de Atendimento, Encomendas e Veiculos
	 * Saida: Verdadeiro se o Plano de Rotas e valido. Falso, caso contrario
	 */


	boolean v1 = conectTrecho(planoRotas, mapa);
	boolean v2 = conectHorario (planoRotas);
	boolean v3 = tempoPercTrechos(planoRotas);

	return ( v1 && v2 && v3 );

    }

    public boolean encomendas( Plano planoAtendimento, Encomenda[] encomendas ){
	/** Validacao das encomendas do plano de atendimento 
	 * Entrada: Plano de Atendimento, Encomendas e Veiculos
	 * Saida: Verdadeiro se o Plano de Atendimento satisfaz as encomendas. Falso, caso contrario
	 */

	boolean v1 = trechoCargaDescargaEncomenda(planoAtendimento, encomendas);
	boolean v2 = horarioCargaDescargaEncomenda(planoAtendimento, encomendas);
	return ( v1 && v2 );

    }


    public boolean capacidade( Plano planoAtendimento ){
	/** Validacao da capacidade do veiculo
	 * Entrada: Plano de Atendimento
	 * Saida: Verdadeiro se a capacidade e sempre valida. Falso, caso contrario
	 */
	    
	Rota[] rotas;
	Passo[] passos;
	Encomenda[] encomendas;
	float capv, carga;

	rotas = planoAtendimento.rotas();

	// Loop para percorrer todas as rotas do Plano
	for( int r=0; r < rotas.length; r++ ){

	    // Obtem a capacidade do veiculo designado para esta rota
	    capv = rotas[r].veiculo().getCapacidade();
	    // Zera a carga inicial
	    carga = 0;

	    passos = rotas[r].passos(); 
	    // Percorre todos os passos da rota verificando a capacidade do veiculo
	    for( int p=0; p < passos.length; p++ ){

		// Acumula todas as encomendas carregadas ate o passo p que
		// nao foram descarregadas ainda

		// Adiciona 'a carga as encomendas carregadas neste passo
		encomendas = passos[p].carrega(); 
		for( int e=0; e < encomendas.length; e++) {
		    carga += encomendas[e].getVolume();
		}

		// Subtrai da carga as encomendas descarregadas neste passo
		encomendas = passos[p].descarrega(); 
		for( int e=0; e < encomendas.length; e++) {
		    carga -= encomendas[e].getVolume();
		}

		// Verifica se a carga ao final do passo excede a capacidade do veiculo
		if (carga > capv){
		    mensagemErro = mensagemErro + "\n Capacidade Maxima do Veiculo excedida";
		    return false;
		}
	    }
	}
	return true;
    }
    

    public boolean conectTrecho( Rota[] planoRotas, Mapa mapa ){
	/** Validacao da conectividade dos trechos
	 *  dst(trecho(Pi))=org(trecho(pi+1)) 
	 * Entrada: Plano de Rotas
	 * Saida: Verdadeiro se os trechos sao conexos. Falso, caso contrario
	 */
	int i,j;
	Passo[] p;
	for (i=0; i<planoRotas.length; i++){
	    p = planoRotas[i].passos();
	    for (j=0; j<p.length-1; j++)
		if(!mapa.pode(p[i].trecho(),p[i+1].trecho()))
		    return false;
	} 
	return true;
    }


    public boolean tempoPercTrechos( Rota[] planoRotas){
	/** Validacao do tempo de permanencia em um trecho
	 * Entrada: Plano de Atendimento, Encomendas e Veiculos
	 * Saida: Verdadeiro se o tempo de permanencia eh valido. Falso, caso contrario
	 */
	Passo[] passos;
	Encomenda[] carregadas, descarregadas;
	double tempoTotalCarga, tempoTotalDescarga;

	/* para cada rota do plano de rotas */
	for (int r=0; r<planoRotas.length; r++){

	    /* para cada passo desta rota */
	    passos = planoRotas[r].passos();
	    for (int p=0; p<passos.length; p++){

		/* calculando o tempo total de cargas neste passo */
		tempoTotalCarga = 0;
		carregadas = passos[p].carrega();
		for (int e=0; e<carregadas.length; e++){
		    tempoTotalCarga = tempoTotalCarga + carregadas[e].getTempoCarga();
		}

		/* calculando o tempo total de descargas neste passo */
		tempoTotalDescarga = 0;
		descarregadas = passos[p].descarrega();
		for (int e=0; e<descarregadas.length; e++){
		    tempoTotalDescarga = tempoTotalDescarga + descarregadas[e].getTempoDescarga();
		}

		/**********************************
		 *ALTERAR:
		 *passos[p].trecho.tempoPercurso para o nome correto que tiver sido definido
		 *conversao de tempoTotalCarga e tempoTotalDescarga para a unidade apropriada
		 **********************************/
		
		if ( passos[p].intervalo().getInicio() +
		     tempoTotalCarga +
		     tempoTotalDescarga +
		     passos[p].trecho().tempoPercurso() >
		     passos[p].intervalo().getFim() ){
		    mensagemErro = mensagemErro + "\nTempo de permanencia em um trecho excedido.";
		    return false;
		}

	    }

	    return true;

	}
    }


    public boolean conectHorario( Rota[] planoRotas ) {
	/** Validacao da conectividade dos horaris 
	 * Entrada: Plano de Rotas
	 * Saida: Verdadeiro se os horarios sao conexos . Falso, caso contrario
	 */
    
	boolean valido = false;
	Passo[] passos = null;

    // Percorre todo o array de Rota[] setando o array passos 
	for ( int iLoop = 0; iLoop < planoRotas.length; iLoop++) {
	    passos = planoRotas[iLoop].passos();

	    for ( int i = 0; i < passos.length-1; i++ ) {
		Passo passoAtual = passos[i];
		Passo passoProximo = passos[i+1];
		IntervaloData intervaloAtual = passoAtual.intervalo();
		IntervaloData intervaloProximo = passoProximo.intervalo();
		double horaFim = intervaloAtual.getFim();
		double horaInicio = intervaloProximo.getInicio();
	    
		// Verifica se o instante final de um passo eh o instante inicial do passo seguinte.
		if ( horaFim == horaInicio ) {
		    valido = true;
		} else {
		    mensagemErro = mensagemErro + "\n Conectividade de horario falhou no passo " + i + " da Rota " + iLoop;
		} 
	    }
	}
	return valido;
    }



    public boolean horarioCargaDescargaEncomenda( Plano planoAtendimento, Encomenda[] encomendas ){
	/** Validacao se todas as encomendas foram carregadas/descarregadas no horario
	 * Entrada: Plano de Atendimento, Encomendas e Veiculos
	 * Saida: Verdadeiro se todas as encomendas foram carregadas/descarregadas no horario. Falso, caso contrario
	 */

	Passo passo;
	Encomenda encomenda;

     /* para cada encomenda da lista de encomendas */
	for (int e=0; e<encomendas.length; e++){
	    
	    encomenda = encomendas[e];
	    
	    /* validando se contempla a carga da encomenda */
	    passo = planoAtendimento.trechoCarga(encomenda);
	    if (passo == null){
		mensagemErro = mensagemErro + "\nCarga da encomenda " + encomenda.getEncomendaID() + " nao contemplada.";
		return false;
	    }

	    /* validando horario de carga da encomenda */
	    if ( ( encomenda.getHoraOrigem() < passo.intervalo().getInicio() ) ||
		( encomenda.getHoraOrigem() > passo.intervalo().getFim()) ){
		mensagemErro = mensagemErro + "\nHorario de carga da encomenda " + encomenda.getEncomendaID() + " nao contemplado.";
		return false;
	    }

	    /* validando se contempla a descarga da encomenda */
	    passo = planoAtendimento.trechoDescarga(encomenda);
	    if (passo == null){
		mensagemErro = mensagemErro + "\nDescarga da encomenda " + encomenda.getEncomendaID() + " nao contemplada.";
		return false;
	    }

	    /* validando horario de descarga da encomenda */
	    if (( encomenda.getHoraDestino() < passo.intervalo().getInicio() ) ||
		( encomenda.getHoraDestino() > passo.intervalo().getFim())){
		mensagemErro = mensagemErro + "\nHorario de descarga da encomenda " + encomenda.getEncomendaID() + " nao contemplado.";
		return false;
	    }

	}
	
	return true;
    }


    public boolean trechoCargaDescargaEncomenda( Plano planoAtendimento, Encomenda[] encomendas ) {
	/** Validacao se todas as encomendas foram carregadas/descarregadas naquele trecho
	 * Entrada: Plano de Atendimento,  encomendas,  veiculos
	 * Saida: Verdadeiro se todas as encomendas foram contempladas. Falso, caso contrario
	 */

	Rota[] rotas;
	boolean valido = false;
   
	rotas = planoAtendimento.rotas();

    // Loop para percorrer todas as Encomendas
	for( int r=0; r < encomendas.length ; r++ ){

	    Encomenda encomenda = encomendas[r];

	    Passo passo =  planoAtendimento.trechoCarga(encomenda);

	    if (passo != null ) {
		if ( (encomenda.getOrigem().id() != passo.trecho().id()) &&
		     (encomenda.getDestino().id() != passo.trecho().id()) ) {
		    mensagemErro = mensagemErro + "\n A encomenda nao sera carregada ou descarregada nesse trecho";
		} else {
		    valido = true;
		}
	    } else {
		mensagemErro = mensagemErro + "\n A encomenda nao sera carregada ou descarregada nesse trecho";
	    }
	}
	return valido;
    }

    

    public String getMensagemErro(){
    /** Obtem a mensagem de erro gerada pelos metodos anteriores 
     * Entrada: nenhuma
     * Saida: Mensagem de erro gerada pelos outros metodos da classe
     */
	return mensagemErro;
    }


}











