package pckPlano;

/** Ultima atualizacao : 08-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.Conexao;

public class ValidadorImpl extends Validador {

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

    public Boolean pA( Plano planoAtendimento, Encomenda[] encomendas, Veiculo[] veiculos ){
	return ( rotas( planoAtendimento.rotas() ) &&
		 encomendas( planoAtendimento, encomendas ) &&
		 capacidade( planoAtendimento ));

    }    

    public Boolean rotas( Rota[] planoRotas ){
	/** 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
	 */

	return ( conectTrecho(planoRotas) && 
		 conectHorario (planoRotas) &&
		 tempoPercTrechos(planoRotas)); 

    }

    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
	 */

	return ( trechoCargaDescagaEncomenda(planoAtendimento, encomendas) &&
		 horarioCargaDescagaEncomenda(planoAtendimento, encomendas));

    }


    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;
	int 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].volume;
		}

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

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

    private Boolean conectTrecho( Rota[] planoRotas ){
	/** 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(!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;
	float 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.inicio +
		     tempoTotalCarga +
		     tempoTotalDescarga +
		     passos[p].trecho.tempoPercurso >
		     passos[p].intervalo.fim ){
		    errorMessage = errorMessage + "\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; i++ ) {
		Passo passoAtual = passos[i];
		Passo passoProximo = passos[i+1];
		IntervaloData intervaloAtual = passoAtual.intervalo();
		IntervaloData intervaloProximo = passoProximo.intervalo();
		Double horaFim = intervaloAtual.fim();
		Double horaInicio = intervaloProximo.inicio();
	    
		// Verifica se o instante final de um passo eh o instante inicial do passo seguinte.
		if ( horaFim == horaInicio ) {
		    valido = true;
		} else {
		    errorMessage = errorMessage + "\n Conectividade de horario falhou no passo " + i + " da Rota " + iLoop;
		} 
	    }
	}
	return valido;
    }



    public Boolean horarioCargaDescargaEncomenda( Plano planoAtendimento, Encomenda[] encomendas, Veiculo[] veiculos ){
	/** 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 (e=0; e<encomendas.length; e++){

	    encomenda = encomendas[e];

	    /* validando se contempla a carga da encomenda */
	    passo = planoAtendimento.trechoCarga(encomenda);
	    if (passo = NULL){
		errorMessage = errorMessage + "\nCarga da encomenda " + encomenda.getEncomendaID + " nao contemplada.";
		return false;
	    }

	    /* validando horario de carga da encomenda */
	    if ( encomenda.getHoraOrigem < passo.intervalo.inicio ) or
									( encomenda.getHoraOrigem > passo.intervalo.fim){
		errorMessage = errorMessage + "\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){
		errorMessage = errorMessage + "\nDescarga da encomenda " + encomenda.getEncomendaID + " nao contemplada.";
		return false;
	    }

	    /* validando horario de descarga da encomenda */
	    if ( encomenda.getHoraDestino < passo.intervalo.inicio ) or
									 ( encomenda.getHoraDestino > passo.intervalo.fim){
		errorMessage = errorMessage + "\nHorario de descarga da encomenda " + encomenda.getEncomendaID + " nao contemplado.";
		return false;
	    }

	}

	return true;
    }

    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;
    }


}











