package business;

import java.awt.Graphics;
import java.awt.Point;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.ResourceBundle;

import utils.Constantes;
import utils.Utilidades;
import core.ModalAceptar;

public class Grafo {

	protected ArrayList<Vertice> vertices;
	protected ArrayList<Arista> aristas;
	private ArrayList<Vertice> verticesSeleccionados;
	private HashSet<Arista> aristasSeleccionadas;
	private int verticeId;
	private int aristaId;
	protected ResourceBundle mensajes;

	public Grafo() {
		vertices = new ArrayList<Vertice>();
		aristas = new ArrayList<Arista>();
		verticesSeleccionados = new ArrayList<Vertice>();
		aristasSeleccionadas = new HashSet<Arista>();
		verticeId = 1;
		aristaId = 1;
	}

	public void dibujarGrafo(Graphics g) {
		for(Arista a : aristas) {
			a.dibujarArista(g);
		}
		for(Vertice v: vertices) {
			v.dibujarVertice(g);
		}
	}

	public void anadirVertice(Vertice v) {
		vertices.add(v);
	}

	public void anadirArista(Arista a) {
		if(obtenerAristaPorVertices(a.getVerticeOrigen().getId(), a.getVerticeDestino().getId()) == null) {
			aristas.add(a);
			a.getVerticeOrigen().getAdyacentes().add(a.getVerticeDestino());
			a.getVerticeDestino().getAdyacentes().add(a.getVerticeOrigen());
			if(Configuracion.isModoArbol()) {
				int matrizDistancias[][];
				if(Resultados.getMatriz() == null) {
					int numeroVertices = vertices.size();
					matrizDistancias = new int[numeroVertices][numeroVertices];
					Utilidades.CalcularMatriz(matrizDistancias, this);
					Resultados.setMatriz(matrizDistancias);
				} else {
					matrizDistancias = Resultados.getMatriz();
				}
				try {
					for(int f = 0; f < matrizDistancias.length; f++) {
						for(int c = 0; c < matrizDistancias.length; c++)
							if((matrizDistancias[f][c] == 0 || matrizDistancias[f][c] == -1) && f != c)
								throw new Exception();
					}
				} catch(Exception exc) {
					Resultados.setMatriz((int[][])null);
					borrarArista(a);
					ModalAceptar modal = new ModalAceptar(mensajes, Constantes.ERROR, "NoConexoNoArbol");
					modal.setVisible(true);
				}
				try {
					if(Utilidades.existeCiclo(this))
						throw new Exception();
				} catch(Exception exc2) {
					borrarArista(a);
					ModalAceptar modal = new ModalAceptar(mensajes, Constantes.ERROR, "CiclosNoArbol");
					modal.setVisible(true);
				}
			}
		} else {
			ModalAceptar modal = new ModalAceptar(mensajes, Constantes.INFORMACION, "YaExisteAris");
			modal.setVisible(true);
		}
	}

	public int obtenerIndiceVerticePorId(int id) {
		int indice = 0;
		for(Vertice v : vertices) {
			if(v.getId().equals(id)) {
				return indice;
			}
			indice++;
		}
		return -1;
	}

	public Vertice obtenerVerticePorId(int id) {
		for(Vertice v : vertices) {
			if(v.getId().equals(id))
				return v;
		}
		return null;
	}

	public Vertice obtenerVerticeEnPunto(Point p) {
		for(Vertice v : vertices) {
			if(p.x <= v.getPunto().x + Constantes.PIXELES_VERTICES/2 && p.x >= v.getPunto().x - Constantes.PIXELES_VERTICES/2 && p.y <= v.getPunto().y + Constantes.PIXELES_VERTICES/2 && p.y >= v.getPunto().y - Constantes.PIXELES_VERTICES/2) {
				return v;
			}
		}
		return null;
	}

	public Arista obtenerAristaEnPunto(Point p) {
		for(Arista a : aristas) {
			if(a.obtenerDistanciaAPunto(p).compareTo(new BigDecimal(2)) <= 0) {
				return a;
			}
		}
		return null;
	}

	public Arista obtenerAristaPorVertices(int v1, int v2) {
		for(Arista a : aristas) {
			if(a.getVerticeOrigen().getId() == v1 && a.getVerticeDestino().getId() == v2 || a.getVerticeOrigen().getId() == v2 && a.getVerticeDestino().getId() == v1)
				return a;
		}
		return null;
	}

	public void borrarVertice(Vertice n) {
		ArrayList<Arista> paraBorrar = new ArrayList<Arista>();
		for(Arista a : aristas) {
			if(a.getVerticeOrigen() == n || a.getVerticeDestino() == n)
				paraBorrar.add(a);
		}
		for(Arista a : paraBorrar)
			borrarArista(a);

		vertices.remove(n);
	}

	public void borrarVertices(ArrayList<Vertice> vertices) {
		for(Vertice v : vertices) {
			borrarVertice(v);
		}
	}

	public void borrarArista(Arista a) {
		a.getVerticeOrigen().getAdyacentes().remove(a.getVerticeDestino());
		a.getVerticeDestino().getAdyacentes().remove(a.getVerticeOrigen());
		aristas.remove(a);
	}

	public void borrarAristas(HashSet<Arista> aristas) {
		for(Arista a : aristas) {
			borrarArista(a);
		}
	}

	public void seleccionarVertice(Vertice v) {
		v.setSeleccionado(true);
		verticesSeleccionados.add(v);
	}

	public void deseleccionarVertice(Vertice v) {
		v.setSeleccionado(false);
		verticesSeleccionados.remove(v);
	}

	public void deseleccionarTodosVertices() {
		for(Vertice v : verticesSeleccionados) {
			v.setSeleccionado(false);
		}
		verticesSeleccionados = new ArrayList<Vertice>();
	}

	public void seleccionarArista(Arista a) {
		a.setSeleccionada(true);
		aristasSeleccionadas.add(a);
	}

	public void deseleccionarArista(Arista a) {
		a.setSeleccionada(false);
		aristasSeleccionadas.remove(a);
	}

	public void deseleccionarTodasAristas() {
		for(Arista a : aristasSeleccionadas) {
			a.setSeleccionada(false);
		}
		aristasSeleccionadas = new HashSet<Arista>();
	}

	public void invertirSeleccionVertice(Vertice v) {
		if(v.isSeleccionado()) {
			v.setSeleccionado(false);
			verticesSeleccionados.remove(v);
		} else {
			v.setSeleccionado(true);
			verticesSeleccionados.add(v);
		}
	}

	public ArrayList<Vertice> getVertices() {
		return vertices;
	}

	public ArrayList<Arista> getAristas() {
		return aristas;
	}

	public int getVerticeId() {
		return verticeId++;
	}

	public void setVerticeId(int verticeId) {
		this.verticeId = verticeId;
	}

	public int getAristaId() {
		return aristaId++;
	}

	public void setAristaId(int aristaId) {
		this.aristaId = aristaId;
	}

	public ArrayList<Vertice> getVerticesSeleccionados() {
		return verticesSeleccionados;
	}

	public void setVerticesSeleccionados(ArrayList<Vertice> verticesSeleccionados) {
		this.verticesSeleccionados = verticesSeleccionados;
	}

	public HashSet<Arista> getAristasSeleccionadas() {
		return aristasSeleccionadas;
	}

	public void setAristasSeleccionadas(HashSet<Arista> aristasSeleccionadas) {
		this.aristasSeleccionadas = aristasSeleccionadas;
	}

	public ResourceBundle getMensajes() {
		return mensajes;
	}

	public void setMensajes(ResourceBundle mensajes) {
		this.mensajes = mensajes;
	}
}