package algoritmo;

import ambienteGrafico.componentes.Canvas;
import auxiliar.Arquivo;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Observable;
import java.util.Timer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;


public class EspacoDeBusca extends Observable{

    /**
     * @param 
     */
    private ConjuntoDeAgentes agentes = null;
    private ConjuntoDeAlvos alvos = null;
    private ConjuntoDeObstaculos obstaculos = null;
    private int limiteMaxCoordX;//limite inferior sempre = 0
    private int limiteMaxCoordY;//limite inferior sempre = 0
    //private int indexUltimoAlvo;
    //private int indexUltimoObstaculo;
    private int cicloAtual;
    private int cicloGatilho; //intervalo de verificacao pra ver se alcançou o objetivo
    private int intervaloGatilho;
    private int numMaxCiclos;
    private int porcentagemMinimaCompleta;

    private boolean execucaoFinalizada;
    private double[] veloCorrentezaPolar;
    private double[] veloCorrentezaCartesiana;
    private Solucao melhorSolucaoPossivel = new Solucao(0);

    ///Objetivos de execução
    public static final int ESTABILIZAR_SWARM = 0;
	public static final int ALCANACAR_ALVO = 1;
    public static final int EXPLORAR_AMBIENTE = 2;
    public static final int EXECUTAR_PSO = 3;
    private boolean estabilizarSwarm = true;
    private boolean alcancarAlvo = false;
    private boolean explorarAmbiente = false;
    private boolean alcancarObjetivoUsandoPSO = false;
    private boolean alcancarObjetivoUsandoMI = false; //MP significa mapeamento inteligente
    //Representacao Grafica do Ambiente
    private Canvas canvas;

    //simulaçõesTCC
    private StringBuffer stringResultados = new StringBuffer();
    private int simulacao = 1;
    private int numRepeticao = 1;

    private EspacoDeBusca() {
        inicializarEspacoDeBusca();
    }

    public static EspacoDeBusca getInstance() {
        return EspacoDeBuscaHolder.instancia;
    }

    private static class EspacoDeBuscaHolder {

        private static EspacoDeBusca instancia = new EspacoDeBusca();
    }

    public void inicializarEspacoDeBusca() {
        agentes = new ConjuntoDeAgentes();//ConjuntoDeAgentes.getInstance();
        alvos = ConjuntoDeAlvos.getInstance();
        obstaculos = ConjuntoDeObstaculos.getInstance();

        cicloAtual = 0;
        cicloGatilho = 5;
        intervaloGatilho = 5;
        numMaxCiclos = 2000;
        porcentagemMinimaCompleta = 90;
        execucaoFinalizada = false;
        veloCorrentezaPolar = new double[2];
        veloCorrentezaPolar[0] = 1;
        veloCorrentezaPolar[1] = 90;
        veloCorrentezaCartesiana = new double[2];
        limiteMaxCoordX = 1420; //(1027m)
        limiteMaxCoordY = 800; //(655m)

        //adicionarObstaculosPadroes();
        adicionarAlvosPadroes();
        //adicionarAgentesAleatoriamente(3);
    }

    public void estabelecerMelhorSolucaoPossivel(){

       SensorFotografico sensor = new SensorFotografico(null, 0, null);
       melhorSolucaoPossivel = sensor.estabelecerMelhorSolucaoPossivel();
        
    }

    public void estabelecerObjetivoDaExecucao(int objetivoDaExecucao){

        //tira todos os agentes do estado inativo ---
        for (int k = 0; k < agentes.getNumAgentes(); k++) {
            agentes.get(k).setEstadoDePausa(false);
            agentes.get(k).setAlvoEncontrado(false);
        }

        //Muda o objetivo
        if (objetivoDaExecucao == EspacoDeBusca.ESTABILIZAR_SWARM) {
            estabilizarSwarm = true;
            alcancarAlvo = false;
            explorarAmbiente = false;
            alcancarObjetivoUsandoPSO = false;
        }
        else if(objetivoDaExecucao == EspacoDeBusca.ALCANACAR_ALVO){
            estabilizarSwarm = false;
            alcancarAlvo = true;
            explorarAmbiente = false;
            alcancarObjetivoUsandoPSO = false;
        }
        else if(objetivoDaExecucao == EspacoDeBusca.EXPLORAR_AMBIENTE){
            estabilizarSwarm = false;
            alcancarAlvo = false;
            explorarAmbiente = true;
            alcancarObjetivoUsandoPSO = false;
        }
        else if(objetivoDaExecucao == EspacoDeBusca.EXECUTAR_PSO){
            estabilizarSwarm = false;
            alcancarAlvo = false;
            explorarAmbiente = false;
            alcancarObjetivoUsandoPSO = true;
        }
    }

    public void executar() {
        if (estabilizarSwarm) {
            estabilizarSwarm();
        }
        else if(alcancarAlvo){
           alcancarAlvo();
        }
        else if(explorarAmbiente){
           explorarAmbiente();
        }
        else if(alcancarObjetivoUsandoMI){
           executarMapeamentoInteligente();
        }
        else if(alcancarObjetivoUsandoPSO){
           executarPSO();
        }
    }

    public void estabilizarSwarm() {
        Agente agente;
        double[] posicao;
        double[] posicaoAnterior;
        for (int k = 0; k < agentes.getNumAgentes(); k++) {
            agente = agentes.get(k);
            posicao = agente.getPosicao();
            posicaoAnterior = posicao.clone();

            agente.estabilizarPosicao(veloCorrentezaPolar, limiteMaxCoordX, limiteMaxCoordY);

            //Verifica se encontra-se dentro do espaço de busca
            if (posicao[0] >= 0 && posicao[0] <= limiteMaxCoordX &&
                    posicao[1] >= 0 && posicao[1] <= limiteMaxCoordY) {
                ;
            } else {
                agentes.get(k).setPosicao(posicaoAnterior);
                System.out.println("Fora do limite do espaco de busca!  MaxX: " + limiteMaxCoordX + " MaxY: " + limiteMaxCoordY);
            }
        }
    }

    public void alcancarAlvo() {
        Agente agente;
        double[] posicaoAtual;
        double[] posicaoAnterior;
        double[] velocidadePAnterior;
        double[] alvoCoordCarteziana = new double[2];

        //Define o alvo
        //Essa é a rotina que deve ser mudada caso tenhamos mais de um alvo na lista
        //REVER - ESCOLHER COR OU POSICAO !!!!!!!!!!!!!!!!!!!!!
        for (int k = 0; k < alvos.getNumAlvos(); k++) {
            if (alvos.get(k).isAtivo()) {
                alvoCoordCarteziana = alvos.get(k).getPosicao();
                break;
            }
        }
        //Rotina onde os agentes buscam o alvo
        for (int k = 0; k < agentes.getNumAgentes(); k++) {
            agente = agentes.get(k);

            posicaoAnterior = agente.getPosicao().clone();
            velocidadePAnterior = agente.getVelocidadePolar().clone();

            agente.setPosicaoDestino(alvoCoordCarteziana);
            agente.alcancarDestino(veloCorrentezaPolar, limiteMaxCoordX, limiteMaxCoordY);

            posicaoAtual = agente.getPosicao();
            //Verifica se encontra-se dentro do espaço de busca
            if (posicaoAtual[0] >= 0 && posicaoAtual[0] <= limiteMaxCoordX &&
                   posicaoAtual[1] >= 0 && posicaoAtual[1] <= limiteMaxCoordY) {
                ;
            }
            else {
                agentes.get(k).setPosicao(posicaoAnterior);
                System.out.println("Fora do limite do espaco de busca!  MaxX: " + limiteMaxCoordX + " MaxY: " + limiteMaxCoordY);
            }

            //Rotina de collision avoidance; verifica se vai bater em alguma coisa
            Agente vizinho;
            for (int i = 0; i < agentes.getNumAgentes(); i++) {
                //Testa se há choque com outro agente
                 if(k!=i){
                     vizinho = agentes.get(i);
                     if( (Math.abs(vizinho.getPosicao()[0] - posicaoAtual[0]) < 18)///////tamanho da figura
                        && (Math.abs(vizinho.getPosicao()[1] - posicaoAtual[1]) < 18)) {
                         agente.setPosicao(posicaoAnterior);//pausa por um ciclo
                         //agente.setVelocidadePolar(velocidadePAnterior);//pausa por um ciclo
                         //agente.setEstadoDePausa(true);
                         //vizinho.setEstadoDePausa(true);
                         System.out.println("Dois agentes não ocupam o mesmo lugar no espaço!");
                     }
                 }
                 //outros testes...
            }//Fim da rotina de collision avoidance
            
        }//Fim da rotina onde os agentes buscam o alvo
    }

    public void explorarAmbiente() {
        notifyObservers(3);
        setChanged();
        Agente agente;//todos os agentes já devem conhecer os seus alvos nesse instante
        boolean destinoAlcancado;
         boolean condicaoParadaAlcançada = false;

        System.out.println("INICIO execucao EXPLORAÇÃO");
        condicaoParadaAlcançada = verificarCondicaoParada2(); //verificarCondicaoParada1();
        if(!condicaoParadaAlcançada) {
            //Rotina onde os agentes exploram o ambiente
            for (int k = 0; k < agentes.getNumAgentes(); k++) {
                agente = agentes.get(k);
                //Na primeira chamada ao método explorarAmbiente,
                //posicaoDestino = posicaoAtual, portanto o agente permanece parado
                //agente.alcancarDestino retorna TRUE
                destinoAlcancado = agente.alcancarDestino(veloCorrentezaPolar, limiteMaxCoordX, limiteMaxCoordY);

                if(destinoAlcancado ){
                    Solucao solucao = null;
                    if(!agente.isEstadoDePausa()){// se não estiver parado num local por conta de uma má escolha de destino
                        solucao = agente.getSensorFitness().sensorResponse(agente.getPosicao()); //Analisa o fitness
                        solucao.calculaFitness();
                    }
                    if(agente.getSensorFitness().isObjetivoEncontrado()){
                        //muda estratégia --- comunicação (cada agente pode ter um alvo diferente...?)
                        System.out.println("Agente: "+agente.getIdAgente()+" -> Muda Estratégia de Execução");
                        estabilizarSwarm = false;
                        alcancarAlvo = false;
                        explorarAmbiente = false;
                        alcancarObjetivoUsandoMI = true;
                        //agente.comunicaSolucao(solucao);

                        //Deixa gBest e Lbest preparados para inicialização do PSO
                        agente.getMemoriaDeSolucoes().setSolucaoPbest(solucao);
                        agente.getMemoriaDeSolucoes().setSolucaoLbest(solucao);
                        agente.setEstadoPSO(true);
                        agente.getMemoriaDeSolucoes().removerTodos();
                        agente.getMemoriaDeSolucoesRecebidas().removerTodos();
                    }//
                    else{
                        agente.explorarAmbiente(veloCorrentezaPolar, limiteMaxCoordX, limiteMaxCoordY);
                    }
                }
             }//Fim da rotina onde os agentes buscam o alvo
        }
    }

    public void executarMapeamentoInteligente(){ // TODO
        
        
        boolean condicaoParadaAlcançada = false;
        int fatorInercia = 1;
        Agente agente;//todos os agentes já devem conhecer os seus alvos nesse instante
        boolean destinoAlcancado;

        System.out.println("INICIO execucao MI");
        condicaoParadaAlcançada = verificarCondicaoParada2(); //verificarCondicaoParada1();

        if(!condicaoParadaAlcançada) {
            for (int j = 0; j < agentes.getNumAgentes(); j++) {
               agente = agentes.get(j);
               
               destinoAlcancado = agente.alcancarDestino(veloCorrentezaPolar, limiteMaxCoordX, limiteMaxCoordY);
              
               
               if( !destinoAlcancado && agente.sePosicaoDestinoJaFoiAvaliadaPorVizinho() && agente.isEstadoPSO()){
                   if(!agente.isEscolheuPosicaoAleatoria()){
                       //System.out.println("MUDAR DESTINO - "+agente.showPosicao()+" | "+ agente.showPosicaoDestino());
                       agente.exploracaoInteligente(limiteMaxCoordX, limiteMaxCoordY, fatorInercia);
                       //System.out.println("NOVO DESTINO - "+agente.showPosicaoDestino());
                   }
                   else{
                        ;//System.out.println("NÃO PODE MUDAR POIS A POSIÇÃO FOI ESCOLHIDA ALEATORIAMENTE - CASO EXTREMO");
                   }
               }

               agente.comunicacao2();
               if(destinoAlcancado ){
                    
                   Solucao solucao = null;
                   ConjuntoDeSolucoes memoriaDeSolucoes = agente.getMemoriaDeSolucoes();;
                   if(!agente.isEstadoDePausa()){// se não estiver parado num local por conta de uma má escolha de destino

                        solucao = agente.getSensorFitness().sensorResponse(agente.getPosicao()); //Analisa o fitness
                        solucao.calculaFitness();
                        System.out.println("Agente: "+agente.getIdAgente()+" ->Mostra Fitness: "+solucao.getFitness()+ " Mostra Fitness Lbest: "+memoriaDeSolucoes.getSolucaoLbest().getFitness());
                       //Atualiza Pbest
                       if(solucao.getFitness() >= memoriaDeSolucoes.getSolucaoPbest().getFitness()){
                           memoriaDeSolucoes.setSolucaoPbest(solucao);
                           System.out.println("Agente: "+agente.getIdAgente()+" ->Atualizou pBesdt");
                           if(memoriaDeSolucoes.getSolucaoPbest().getFitness() >= memoriaDeSolucoes.getSolucaoLbest().getFitness()){
                               memoriaDeSolucoes.setSolucaoLbest(memoriaDeSolucoes.getSolucaoPbest());
                               System.out.println("Agente: "+agente.getIdAgente()+" ->Atualizou lBesdt");
                            }
                           else{
                               System.out.println("Agente: "+agente.getIdAgente()+" ->NÂO Atualizou lBesdt");
                           }
                       }
                       else{
                           System.out.println("Agente: "+agente.getIdAgente()+" ->NÂO Atualizou pBesdt nem lbest");
                       }
                   }
                   //agente.comunicacao();//recebe os lbest dos vizinhos e atualiza o lbest

                   if(agente.isEstadoPSO()){//se está no estado PSO
                        System.out.println("Agente: "+agente.getIdAgente()+" -> PSO -> Definir Destino");
                        agente.exploracaoInteligente(limiteMaxCoordX, limiteMaxCoordY, fatorInercia);//escolhe posicao destino
                   }else{
                       if(agente.getSensorFitness().isObjetivoEncontrado()){//se entrou no estado PSO
                            agente.setEstadoPSO(true);
                            agente.getMemoriaDeSolucoes().removerTodos();
                            agente.getMemoriaDeSolucoesRecebidas().removerTodos();
                            System.out.println("Agente: "+agente.getIdAgente()+" -> [Estrou no estado]PSO -> Definir Destino");
                            agente.exploracaoInteligente(limiteMaxCoordX, limiteMaxCoordY, fatorInercia);//escolhe posicao destino
                       }else{//se não entrou no estado PSO
                            System.out.println("Agente: "+agente.getIdAgente()+" -> Explora -> Definir Destino");
                            agente.explorarAmbiente(veloCorrentezaPolar,limiteMaxCoordX, limiteMaxCoordY);//escolhe posicao destino
                       }
                   }
               }

               System.out.println("Agente["+j+"]= velocidade: "+agente.getVelocidadePolar()[0]+" | angulo: "+agente.getVelocidadePolar()[1]
                                                +" | posicao: "+ Math.round(agente.getPosicao()[0])+","+ Math.round(agente.getPosicao()[1])
                                                +" | posicaoDestino: "+ Math.round(agente.getPosicaoDestino()[0])+","+ Math.round(agente.getPosicaoDestino()[1])
                                                +" | modo: PSO-"+ agente.isEstadoPSO());

            }
        }
        
       
        //System.out.println("FIM execucao PSO");
    }

    public void executarPSO() {

        boolean condicaoParadaAlcançada = false;
        int fatorInercia = 1;
        Agente agente;//todos os agentes já devem conhecer os seus alvos nesse instante
        boolean destinoAlcancado;

        //System.out.println("INICIO execucao PSO");

        if(!condicaoParadaAlcançada) {
            for (int j = 0; j < agentes.getNumAgentes(); j++) {
               agente = agentes.get(j);

               destinoAlcancado = agente.alcancarDestino(veloCorrentezaPolar, limiteMaxCoordX, limiteMaxCoordY);
               if(destinoAlcancado ){
                   Solucao solucao = null;
                   ConjuntoDeSolucoes memoriaDeSolucoes = agente.getMemoriaDeSolucoes();;
                   if(!agente.isEstadoDePausa()){// se não estiver parado num local por conta de uma má escolha de destino

                        solucao = agente.getSensorFitness().sensorResponse(agente.getPosicao()); //Analisa o fitness
                        solucao.calculaFitness();
                        
                        //if(memoriaDeSolucoes.getSolucaoPbest()==null){
                                //Deixa gBest e Lbest preparados para inicialização do PSO
                                //Atualiza Pbest e Lbest
                                //agente.getMemoriaDeSolucoes().setSolucaoPbest(solucao);
                                //agente.getMemoriaDeSolucoes().setSolucaoLbest(solucao);
                                //System.out.println("Agente: "+agente.getIdAgente()+" -> Deixa gBest e Lbest preparados para inicialização do PSO");
                                
                        //}

                        //Atualiza Pbest
                       if(solucao.getFitness() >= memoriaDeSolucoes.getSolucaoPbest().getFitness()){
                           memoriaDeSolucoes.setSolucaoPbest(solucao);
                           System.out.println("Agente: "+agente.getIdAgente()+" ->Atualiza pBesdt");
                           if(memoriaDeSolucoes.getSolucaoPbest().getFitness() >= memoriaDeSolucoes.getSolucaoLbest().getFitness()){
                               memoriaDeSolucoes.setSolucaoLbest(memoriaDeSolucoes.getSolucaoPbest());
                               System.out.println("Agente: "+agente.getIdAgente()+" ->Atualiza lBesdt");
                            }
                       }
                   }
                   agente.comunicacao();//recebe os lbest dos vizinhos e atualiza o lbest
                   
                   if(agente.isEstadoPSO()){//se está no estado PSO
                        System.out.println("Agente: "+agente.getIdAgente()+" -> PSO -> Definir Destino");
                        agente.exploracaoInteligentePSO(limiteMaxCoordX, limiteMaxCoordY, fatorInercia);//escolhe posicao destino
                   }else{
                       if(agente.getSensorFitness().isObjetivoEncontrado()){//se entrou no estado PSO
                            agente.setEstadoPSO(true);
                            agente.getMemoriaDeSolucoes().removerTodos();
                            agente.getMemoriaDeSolucoesRecebidas().removerTodos();
                            System.out.println("Agente: "+agente.getIdAgente()+" -> [Estrou no estado]PSO -> Definir Destino");
                            agente.exploracaoInteligentePSO(limiteMaxCoordX, limiteMaxCoordY, fatorInercia);//escolhe posicao destino
                       }else{//se não entrou no estado PSO
                            System.out.println("Agente: "+agente.getIdAgente()+" -> Explora -> Definir Destino");
                            agente.explorarAmbiente(veloCorrentezaPolar,limiteMaxCoordX, limiteMaxCoordY);//escolhe posicao destino
                       }
                   }
               }

               System.out.println("Agente["+j+"]= velocidade: "+agente.getVelocidadePolar()[0]+" | angulo: "+agente.getVelocidadePolar()[1]
                                                +" | posicao: "+ Math.round(agente.getPosicao()[0])+","+ Math.round(agente.getPosicao()[1])
                                                +" | posicaoDestino: "+ Math.round(agente.getPosicaoDestino()[0])+","+ Math.round(agente.getPosicaoDestino()[1])
                                                +" | modo: PSO-"+ agente.isEstadoPSO());
               
            }
        }
        //System.out.println("FIM execucao PSO");
    }

    public void executarFSS() {

        int maxCiclos = 1000;
        int w = 1;

        System.out.println("INICIO execucao FSS");
        for (int i = 0; i < maxCiclos; i++) {
            for (int j = 0; j < agentes.getNumAgentes(); i++) {
                /**TODO***/
            }
        }
        System.out.println("FIM execucao FSS");
    }

    public void adicionarObstaculosPadroes(){

        //Base
        //double[] posicaoDaBase = {903,630};
        double[] posicaoDaBase = {1000,430};
        double raioAreaRepulsaoDaBase = 150;//105;
        double[] tamanhoDaBase = {100,150};
        Obstaculo obstaculo1 = new Obstaculo(obstaculos.getNumObstaculos());
        obstaculo1.setPosicao(posicaoDaBase);
        obstaculo1.setRaioAreaRepulsao(raioAreaRepulsaoDaBase);
        obstaculo1.setTamanho(tamanhoDaBase);
        obstaculo1.setAtivo(true);
        obstaculo1.setCaminhoImagem("/imagens/ItensAmbiente/Plataforma.png");
		obstaculos.inserirObstaculo(obstaculo1);

        //Navio1
        double[] posicaoNavio1 = {493,690};
        double raioAreaRepulsaoNavio1 = 80;//45
        double[] tamanhoNavio1 = {15,30};
        Obstaculo obstaculo2 = new Obstaculo(obstaculos.getNumObstaculos());
        obstaculo2.setPosicao(posicaoNavio1);
        obstaculo2.setRaioAreaRepulsao(raioAreaRepulsaoNavio1);
        obstaculo2.setTamanho(tamanhoNavio1);
        obstaculo2.setAtivo(true);
        obstaculo2.setCaminhoImagem("/imagens/ItensAmbiente/Barco1.png");
        obstaculos.inserirObstaculo(obstaculo2);

        //Navio2
        double[] posicaoNavio2 = {253,315};
        double raioAreaRepulsaoNavio2 = 80;//45
        double[] tamanhoNavio2 = {15,30};
        Obstaculo obstaculo3 = new Obstaculo(obstaculos.getNumObstaculos());
        obstaculo3.setPosicao(posicaoNavio2);
        obstaculo3.setRaioAreaRepulsao(raioAreaRepulsaoNavio2);
        obstaculo3.setTamanho(tamanhoNavio2);
        obstaculo3.setAtivo(true);
        obstaculo3.setCaminhoImagem("/imagens/ItensAmbiente/Barco2.png");
        obstaculos.inserirObstaculo(obstaculo3);
			//System.out.println("Novo "+obstaculos.toString());
	}

    public void adicionarAlvosPadroes(){
        //Duto
        Alvo alvo1 = new Alvo(alvos.getNumAlvos());
        alvo1.setCorTextura(new java.awt.Color(255, 50, 50, 150));
        alvo1.setAtivo(false);
		alvos.inserirAlvo(alvo1);
    }

    public void adicionarAgentesAleatoriamente(int numAgentes){
        double[] posicao = new double[2];
        double[] tamanhoPadraoAgente = {16, 16};////////////////////////////////////
        double[] velocidadePolarPadraoAgente = new double[2];// 5m/s e 0º
        velocidadePolarPadraoAgente[0] = 5;
        
        for(int i=0; i<numAgentes;i++){
            Agente agente = new Agente(i);

            boolean agenteCriado =  false;
            while(!agenteCriado){

                posicao[0] = Math.round(Math.random() * limiteMaxCoordX);
                posicao[1] = Math.round(Math.random() * limiteMaxCoordY);
                velocidadePolarPadraoAgente[1] = (int) Math.round(Math.random() * 360);

                if (!agentes.existeAgente(posicao) && !obstaculos.existeAreaDeRepulsao(posicao)) {//já está testando o volume do agente tb
                    
                    agente.setPosicao(posicao.clone());
                    agente.setPosicaoDestino(posicao.clone());

                    agente.setComprimentoHorizontal(tamanhoPadraoAgente[0]);
                    agente.setComprimentoVertical(tamanhoPadraoAgente[1]);
                    agente.setVelocidadePolar(velocidadePolarPadraoAgente.clone());

                    agentes.inserirAgente(agente);
                    agenteCriado = true;

                } else {
                    agenteCriado = false;
                }
           }
        }
    }

    private boolean verificarCondicaoParada1(){
        if(cicloAtual==cicloGatilho){
            cicloGatilho += intervaloGatilho;
            BufferedImage mapaFinal =  criarMapaFinal();
            BufferedImage mapaOtimo =  melhorSolucaoPossivel.getFotoRegiao();
            
            double porcentagemDePixelsIguais =compararImagens(mapaFinal, mapaOtimo);
             System.out.println("Porcentagem Pixels Iguais: "+ porcentagemDePixelsIguais);
             
            if(porcentagemDePixelsIguais >= porcentagemMinimaCompleta){
                
                execucaoFinalizada = true;
                //canvas.mostrarResultadoFinal(mapaFinal);
                System.out.println("FIM da execução");
                notifyObservers("simulacaoFinalizada");
                return true;
            }else{
                 return false;
            }
        }else{
            return false;
        }
    }

    private boolean verificarCondicaoParada2(){
        if(cicloAtual >= numMaxCiclos){
            execucaoFinalizada = true;
            BufferedImage mapaFinal =  criarMapaFinal();
            BufferedImage mapaOtimo =  melhorSolucaoPossivel.getFotoRegiao();

            double porcentagemDePixelsIguais =compararImagens(mapaFinal, mapaOtimo);
            System.out.println("Porcentagem Pixels Iguais: "+ porcentagemDePixelsIguais);

            notifyObservers("simulacaoFinalizada");
            System.out.println("Enviou Notificação");

            System.out.println("FIM da execução");
            return true;
        }
        else
            return false;

    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
    }

    public void clear() {
        agentes.removerTodos();
        alvos.removerTodos();
        obstaculos.removerTodos();
        //melhorSolucaoPossivel.clear();

    }



    public BufferedImage criarMapaFinal(){

        int heightMapaFinal = canvas.getImagemAmbiente().getHeight();
        int widthMapaFinal = canvas.getImagemAmbiente().getWidth();

        BufferedImage mapaFinal = new BufferedImage(widthMapaFinal, heightMapaFinal, BufferedImage.TYPE_INT_RGB);

        int indice;

        Agente agente;
        BufferedImage fotoDoAgente;

        int[] pontos_mapaFinal = new int[widthMapaFinal * heightMapaFinal];
        mapaFinal.getRGB(0, 0, widthMapaFinal, heightMapaFinal, pontos_mapaFinal, 0, widthMapaFinal);
        int[] pontos_mapaAgente = new int[widthMapaFinal * heightMapaFinal];

        System.out.println("Construção de mapa de todos os agentes...");
        for(int i = 0;i<agentes.getNumAgentes();i++){
            agente = agentes.get(i);
            fotoDoAgente = ((SensorFotografico)agente.getSensorFitness()).construirMapa();
            fotoDoAgente.getRGB(0, 0, widthMapaFinal, heightMapaFinal, pontos_mapaAgente, 0, widthMapaFinal);
            for (int linha = 0; linha < heightMapaFinal; linha++) {
                for (int coluna = 0; coluna < widthMapaFinal; coluna++) {
                   indice = linha * widthMapaFinal + coluna;
                   pontos_mapaFinal[indice] = pontos_mapaFinal[indice] | pontos_mapaAgente[indice];
                }
            }

        }
        mapaFinal.setRGB(0, 0, widthMapaFinal, heightMapaFinal, pontos_mapaFinal, 0, widthMapaFinal);
        System.out.println("Fim da construção de mapa de todos os agentes...");

       
        

        return mapaFinal;
    }

    public double compararImagens(BufferedImage mapaFinal, BufferedImage mapaOtimo){
        int height = mapaFinal.getHeight();
        int width = mapaFinal.getWidth();

        int pontos_mapaFinal[] = new int[width * height];
        mapaFinal.getRGB(0, 0, width, height, pontos_mapaFinal, 0, width);

        int pontos_mapaOtimo[] = new int[width * height];
        mapaOtimo.getRGB(0, 0, width, height, pontos_mapaOtimo, 0, width);

        int totalPixels = width * height;
        int totalPixelsIguais=0;
        int totalPixelBrancosNaImagemOtima=0;
        java.awt.Color cor;
        java.awt.Color cor2;
        for (int i = 0; i < pontos_mapaFinal.length; i++) {
            cor = new java.awt.Color(pontos_mapaOtimo[i]);
            cor2 = new java.awt.Color(pontos_mapaFinal[i]);
            if(cor.getRed()!= 0 && cor.getGreen()!= 0 && cor.getBlue()!= 0){
                totalPixelBrancosNaImagemOtima++;

                if(cor2.getRed()!= 0 && cor2.getGreen()!= 0 && cor2.getBlue()!= 0){
                    totalPixelsIguais++;
                }
                //if(pontos_mapaFinal[i] == pontos_mapaOtimo[i]){
                    //totalPixelsIguais++;
               // }
            }
            
        }
         
        double porcentagemDePixelsIguais = (double) (totalPixelsIguais*100)/totalPixelBrancosNaImagemOtima;
        /*//regra de tres mafiosa (85% = 100%)
        double proporcao =  (double) 100/85;
        double porcentagemDePixelsIguais2 = proporcao * porcentagemDePixelsIguais;
        */

        /*
        stringResultados.append(numRepeticao);
        stringResultados.append("\n");
        stringResultados.append("TotalPixelBrancosNaImagemOtima: ");
        stringResultados.append(totalPixelBrancosNaImagemOtima);
        stringResultados.append("\n");
        stringResultados.append("TotalPixelsIguais: ");
        stringResultados.append(totalPixelsIguais);
        stringResultados.append("\n");
        stringResultados.append("Porcentagem: ");
        stringResultados.append(porcentagemDePixelsIguais);
        stringResultados.append("\n");
        stringResultados.append("\n");
        */

        System.out.println(stringResultados);
        //System.out.println("Porcentagem2: "+ porcentagemDePixelsIguais2);
        return porcentagemDePixelsIguais;
    }
    
   
    //----------------Getters & Setters-------------------//
    public ConjuntoDeAgentes getAgentes() {
        return agentes;
    }

    public void setAgentes(ConjuntoDeAgentes agentes) {
        this.agentes = agentes;
    }

    public ConjuntoDeAlvos getAlvos() {
        return alvos;
    }

    public void setAlvos(ConjuntoDeAlvos alvos) {
        this.alvos = alvos;
    }

    public ConjuntoDeObstaculos getObstaculos() {
        return obstaculos;
    }

    public void setObstaculos(ConjuntoDeObstaculos obstaculos) {
        this.obstaculos = obstaculos;
    }

    public Solucao getMelhorSolucaoPossivel() {
        return melhorSolucaoPossivel;
    }

    public void setMelhorSolucaoPossivel(Solucao best) {
        melhorSolucaoPossivel = best;
    }



    public int getLimiteMaxCoordX() {
        return limiteMaxCoordX;
    }

    public void setLimiteMaxCoordX(int limiteMaxCoordX) {
        this.limiteMaxCoordX = limiteMaxCoordX;
    }

    public int getLimiteMaxCoordY() {
        return limiteMaxCoordY;
    }

    public void setLimiteMaxCoordY(int limiteMaxCoordY) {
        this.limiteMaxCoordY = limiteMaxCoordY;
    }

    public int getCicloAtual() {
        return cicloAtual;
    }

    public void setCicloAtual(int cicloAtual) {
        this.cicloAtual = cicloAtual;
    }

    public double[] getVeloCorrentezaPolar() {
        return veloCorrentezaPolar;
    }

    public void setVeloCorrentezaCartesiana(double[] veloCorrentezaCartesiana) {
        this.veloCorrentezaCartesiana = veloCorrentezaCartesiana;
    }

    public void setVeloCorrentezaPolar(double[] veloCorrentezaPolar) {
        this.veloCorrentezaPolar = veloCorrentezaPolar;
    }

    public Canvas getCanvas() {
        return canvas;
    }

    public void setCanvas(Canvas canvas) {
        this.canvas = canvas;
    }

    public boolean isExecucaoFinalizada() {
        return execucaoFinalizada;
    }

    public void setExecucaoFinalizada(boolean execucaoFinalizada) {
        this.execucaoFinalizada = execucaoFinalizada;
    }

    public int getNumMaxCiclos() {
        return numMaxCiclos;
    }

    public void setNumMaxCiclos(int numMaxCiclos) {
        this.numMaxCiclos = numMaxCiclos;
    }

    public int getPorcentagemMinimaCompleta() {
        return porcentagemMinimaCompleta;
    }

    public void setPorcentagemMinimaCompleta(int porcentagemMinimaCompleta) {
        this.porcentagemMinimaCompleta = porcentagemMinimaCompleta;
    }

    public int getCicloGatilho() {
        return cicloGatilho;
    }

    public void setCicloGatilho(int cicloGatilho) {
        this.cicloGatilho = cicloGatilho;
    }

    public int getIntervaloGatilho() {
        return intervaloGatilho;
    }

    public void setIntervaloGatilho(int intervaloGatilho) {
        this.intervaloGatilho = intervaloGatilho;
    }

}
