package actions;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.ResourceBundle;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JMenuItem;

import org.apache.log4j.Logger;

import process.CalculoProcess;
import utils.Constantes;
import utils.Utilidades;
import business.Arista;
import business.Configuracion;
import business.Grafo;
import business.Resultados;
import business.Vertice;
import core.BarraHerramientas;
import core.ModalAceptar;
import core.ModalConfirmacion;
import core.PanelEdicion;
import core.PanelInfo;

public class ResultadosAction implements ActionListener {
	
	private static Logger logger = Logger.getLogger(ResultadosAction.class);

	private static PanelEdicion panelEdicion;
	private static PanelInfo panelInfo;
	private static BarraHerramientas barra;
	private ResourceBundle mensajes;

	public ResultadosAction(PanelEdicion pEdicion, PanelInfo pInfo, BarraHerramientas b) {
		panelEdicion = pEdicion;
		panelInfo = pInfo;
		barra = b;
		mensajes = panelEdicion.getMensajes();
	}

	public void actionPerformed(ActionEvent e) {
		JButton b = new JButton();
		JMenuItem m = new JMenuItem();
		if (e.getSource() instanceof JButton) {
			b = (JButton) e.getSource();
			m.setName("");
		} else if (e.getSource() instanceof JMenuItem) {
			b.setName("");
			m = (JMenuItem) e.getSource();
		}
		
		if (b.getName().equals("Dimension") || m.getName().equals("Dimension")) {
			validacionesDimension();
		} else if(m.getName().equals("Dijkstra")) {
			calcularDijkstra();
		} else if(b.getName().equals("Limpiar")) {
			limpiar();
			cambiarAModoEscritura();
		} else if(b.getName().equals("Siguiente")) {
			avanzarResultados();
		} else if(b.getName().equals("Anterior")) {
			retrocederResultados();
		}
	}
	
	public void validacionesDimension() {
		if(panelEdicion.getGrafo().getVertices().size() == 0) {
			ModalAceptar modal = new ModalAceptar(mensajes, Constantes.INFORMACION, "NoExisteGrafo");
			modal.setVisible(true);
		} else {
			if(panelEdicion.getGrafo().getVertices().size() > 14 && Configuracion.isPanelesConfirmacion()) {
				ModalConfirmacion modal = new ModalConfirmacion(mensajes, Constantes.PREGUNTA, "PuedeTardar", getClass().getSimpleName());
				modal.setVisible(true);
			} else if (Utilidades.esVaciaONula(Resultados.getResultados())){
				calcularDimension();
			}
		}
	}
	
	public void calcularDimension() {
		CalculoProcess calculoProcess = new CalculoProcess(panelEdicion,this,barra);
		calculoProcess.start();
		panelEdicion.repaint();
		barra.repaint();
	}
	
	public void calcularDijkstra() {
		Grafo grafo = panelEdicion.getGrafo();
    	if(grafo.getVertices().size() == 0) {
        	ModalAceptar modal = new ModalAceptar(panelEdicion.getMensajes(), Constantes.INFORMACION, "NoExisteGrafo");
        	modal.setVisible(true);
    	} else if(!Utilidades.esVaciaONula(grafo.getVerticesSeleccionados()) && grafo.getVerticesSeleccionados().size() == 2) {
    		ArrayList<Vertice> verticesSeleccionados = grafo.getVerticesSeleccionados();
    		HashMap<Integer,Vertice> camino = new HashMap<Integer,Vertice>();
        	Utilidades.algoritmoDijkstra(verticesSeleccionados.get(0), camino, grafo);
        	if (camino.get(verticesSeleccionados.get(1).getId()) != null) {
        		mostrarResultadosDijkstra(grafo, camino, verticesSeleccionados);
        	} else {
        		ModalAceptar modal = new ModalAceptar(panelEdicion.getMensajes(), Constantes.ERROR, "dosVerticesInconexos");
        		modal.setVisible(true);
        	}
    	} else {
    		ModalAceptar modal = new ModalAceptar(panelEdicion.getMensajes(), Constantes.ADVERTENCIA, "seleccioneDosVertices");
    		modal.setVisible(true);
    	}
	}
	
	public void mostrarResultadosDijkstra(Grafo grafo, HashMap<Integer,Vertice> camino, ArrayList<Vertice> verticesSeleccionados) {
		if(barra.getNumeroSolucion().getText().equals("-")) {
			Integer clave =	verticesSeleccionados.get(1).getId();
			while(camino.containsKey(clave)) {
				grafo.obtenerAristaPorVertices(clave, camino.get(clave).getPadre()).setSolucionadora(true);
				clave = camino.get(clave).getPadre();
			}
			barra.getNumeroSolucion().setText("1");
			cambiarAModoLectura();
			logger.info("Aplicado el algoritmo de Dijkstra");
		}
	}
	
	public void mostrarResultadosDimension(ArrayList<Integer> solucion) {
		if(barra.getNumeroSolucion().getText().equals("-")) {
			for(int i=0; i<solucion.size(); i++) {
				panelEdicion.getGrafo().obtenerVerticePorId(solucion.get(i)).setSolucion(true);
				logger.info("Solución mostrada: " + solucion.get(i));
			}
			barra.getNumeroSolucion().setText("1");
			cambiarAModoLectura();
		}
	}
	
	public void avanzarResultados() {
		Integer numeroActual = Integer.valueOf(barra.getNumeroSolucion().getText());
		Vector<ArrayList<Integer>> resultados = Resultados.getResultados();
		if(numeroActual.compareTo(resultados.size()) < 0) {
			ArrayList<Integer> solucionActual = resultados.get(numeroActual - 1);
			ArrayList<Integer> solucionSiguiente = resultados.get(numeroActual);
	    	for(int i=0; i<solucionActual.size(); i++) {
	    		panelEdicion.getGrafo().obtenerVerticePorId(solucionActual.get(i)).setSolucion(false);
	    	}
	    	for(int i=0; i<solucionSiguiente.size(); i++) {
	    		panelEdicion.getGrafo().obtenerVerticePorId(solucionSiguiente.get(i)).setSolucion(true);
	    		logger.info("Solución mostrada: " + solucionSiguiente.get(i));
	    	}
	    	barra.getNumeroSolucion().setText(new Integer(numeroActual + 1).toString());
	    	panelEdicion.repaint();
		} else {
			ModalAceptar modal = new ModalAceptar(panelEdicion.getMensajes(), Constantes.INFORMACION, "ultimaSolucion");
			modal.setVisible(true);
		}
		
    }
	
	public void retrocederResultados() {
		Integer numeroActual = Integer.valueOf(barra.getNumeroSolucion().getText());
		if(!numeroActual.equals(1)) {
			Vector<ArrayList<Integer>> resultados = Resultados.getResultados();
			ArrayList<Integer> solucionActual = resultados.get(numeroActual - 1);
			ArrayList<Integer> solucionAnterior = resultados.get(numeroActual - 2);
			for(int i=0; i<solucionActual.size(); i++) {
				panelEdicion.getGrafo().obtenerVerticePorId(solucionActual.get(i)).setSolucion(false);
			}
			for(int i=0; i<solucionAnterior.size(); i++) {
				panelEdicion.getGrafo().obtenerVerticePorId(solucionAnterior.get(i)).setSolucion(true);
				logger.info("Solución mostrada: " + solucionAnterior.get(i));
			}
			barra.getNumeroSolucion().setText(new Integer(numeroActual - 1).toString());
			panelEdicion.repaint();
		} else {
			ModalAceptar modal = new ModalAceptar(panelEdicion.getMensajes(), Constantes.INFORMACION, "primeraSolucion");
			modal.setVisible(true);
		}
	}
	
	public static void mostrarResultado(ArrayList<Integer> conjunto) {
		ArrayList<Integer> solucionSiguiente = conjunto;
		ArrayList<Vertice> vertices = panelEdicion.getGrafo().getVertices();
    	for(int i=0; i<vertices.size(); i++) {
    		vertices.get(i).setSolucion(false);
    	}
    	for(int i=0; i<solucionSiguiente.size(); i++) {
    		panelEdicion.getGrafo().obtenerVerticePorId(solucionSiguiente.get(i)).setSolucion(true);
    		logger.info("Solución mostrada: " + solucionSiguiente.get(i));
    	}
    	barra.getNumeroSolucion().setText(new Integer(Resultados.getResultados().indexOf(conjunto) + 1).toString());
    	panelEdicion.repaint();
	}
	
	public void cambiarAModoEscritura() {
		panelInfo.activarModoLectura(false);
		barra.getNumeroSolucion().setText("-");
		barra.getNumeroSoluciones().setText("(-)");
    	panelEdicion.repaint();
    	logger.info("Panel cambiado a modo escritura");
	}
	
	public void cambiarAModoLectura() {
		panelInfo.activarModoLectura(true);
		Grafo grafo = panelEdicion.getGrafo();
		grafo.deseleccionarTodosVertices();
		grafo.deseleccionarTodasAristas();
		grafo.setVerticesSeleccionados(new ArrayList<Vertice>());
		grafo.setAristasSeleccionadas(new HashSet<Arista>());
		panelInfo.mostrarNumeroVerticesSeleccionados(0);
		panelInfo.mostrarNumeroAristasSeleccionadas(0);
    	panelEdicion.repaint();
    	logger.info("Panel cambiado a modo lectura");
	}
	
	public void limpiar() {
		Grafo grafo = panelEdicion.getGrafo();
		for(Vertice v : grafo.getVertices()) {
			v.setSolucion(false);
			v.setSeleccionado(false);
		}
		for(Arista a : grafo.getAristas()) {
			a.setSolucionadora(false);
			a.setSeleccionada(false);
		}
		grafo.setVerticesSeleccionados(new ArrayList<Vertice>());
		grafo.setAristasSeleccionadas(new HashSet<Arista>());
		panelInfo.mostrarNumeroVerticesSeleccionados(0);
		panelInfo.mostrarNumeroAristasSeleccionadas(0);
		Resultados.setResultados(new Vector<ArrayList<Integer>>());
		Resultados.setMatriz((int[][])null);
		logger.info("Todos los resultados han sido borrados");
	}

	public static PanelEdicion getPanelEdicion() {
		return panelEdicion;
	}

	public static PanelInfo getPanelInfo() {
		return panelInfo;
	}

	public static BarraHerramientas getBarra() {
		return barra;
	}
	
}