package core;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList;
import java.util.ResourceBundle;

import javax.swing.JPanel;

import org.apache.log4j.Logger;

import utils.Constantes;
import utils.Utilidades;
import actions.ContextualAction;
import business.Arista;
import business.Grafo;
import business.Resultados;
import business.Vertice;


public class PanelEdicion extends JPanel {

	private static Logger logger = Logger.getLogger(PanelEdicion.class);
	private static final long serialVersionUID = 0xf32e7b508421ea44L;
	private ResourceBundle mensajes;
	private Grafo grafo;
	private PanelInfo panelInfo;
	private MenuContextual menuContextual;
	private boolean arrastra;
	private Point puntoPulsado;
	private Vertice verticePulsado;
	private Vertice verticeSoltado;
	private Arista aristaPulsada;
	private ArrayList<Vertice> verticesInvertidosYa;
	private double zoom;

	public PanelEdicion(PanelInfo pInfo, MenuContextual mC) {

		grafo = new Grafo();
		zoom = 1.0;
		arrastra = false;
		panelInfo = pInfo;
		menuContextual = mC;
		verticesInvertidosYa = new ArrayList<Vertice>();
		setPreferredSize(new Dimension(Constantes.PANEL_ANCHO, Constantes.PANEL_ALTO));
		setBackground(Color.WHITE);
		ContextualAction contextual = new ContextualAction(this, panelInfo);
		menuContextual.getBotonBorrar().addActionListener(contextual);
		menuContextual.getBotonMover().addActionListener(contextual);
		add(menuContextual);

		addMouseMotionListener(new MouseMotionAdapter() {

			public void mouseMoved(MouseEvent e) {
				panelInfo.setPoint(new Point((int)Math.round(e.getPoint().getX() / zoom) ,(int)Math.round(e.getPoint().getY() / zoom)));
				panelInfo.repaint();
			}

			public void mouseDragged(MouseEvent e) {
				if(panelInfo.getModoEscritura().isEnabled()) {
					Point punto = e.getPoint();
					if(!Utilidades.esVaciaONula(getGrafo().getVerticesSeleccionados()) && arrastra) {
						logger.info("Moviendo vértices");
						Point puntoPulsado = verticePulsado.getPunto();
						Point p;
						ArrayList<Vertice> verticesSeleccionados = grafo.getVerticesSeleccionados();
						boolean excedePanel = false;
						for(Vertice v : verticesSeleccionados) {
							p = v.getPunto();
							if(v == verticePulsado) {
								if(punto.getX() / zoom < 0 || punto.getY() / zoom < 0 || punto.getX() / zoom > Constantes.PANEL_ANCHO || punto.getY() / zoom > Constantes.PANEL_ALTO) {
									excedePanel = true;
									break;
								}
							} else {
								if((punto.getX() / zoom) + p.x - puntoPulsado.getX() < 0 || (punto.getY() / zoom) + p.y - puntoPulsado.getY() < 0 || (punto.getX() / zoom) + p.x - puntoPulsado.getX() > Constantes.PANEL_ANCHO || (punto.getY() / zoom) + p.y - puntoPulsado.getY() > Constantes.PANEL_ALTO) {
									excedePanel = true;
									break;
								}
							}
						}
						if(!excedePanel) {
							for(Vertice v : verticesSeleccionados) {
								p = v.getPunto();
								if(v == verticePulsado) {
									v.setPunto(new Point((int)Math.round(punto.getX() / zoom) ,(int)Math.round(punto.getY() / zoom)));
								} else {
									v.setPunto(new Point((int)Math.round((punto.getX() / zoom) + p.x - puntoPulsado.getX()) ,(int)Math.round((punto.getY() / zoom) + p.y - puntoPulsado.getY())));
								}
							}
						}
						repaint();
					} else if(verticePulsado == null && !arrastra) {
						logger.info("Seleccionando vértices arrastrando");
						Graphics graphics = getGraphics();
						graphics.drawLine(puntoPulsado.x, puntoPulsado.y, punto.x, puntoPulsado.y);
						graphics.drawLine(puntoPulsado.x, puntoPulsado.y, puntoPulsado.x, punto.y);
						graphics.drawLine(puntoPulsado.x, punto.y, punto.x, punto.y);
						graphics.drawLine(punto.x, puntoPulsado.y, punto.x, punto.y);
						ArrayList<Vertice> vertices = grafo.getVertices();
						for(Vertice v : vertices) {
							if(!verticesInvertidosYa.contains(v) && Utilidades.estaDentroRegion(v.getPunto(), puntoPulsado, e.getPoint(), zoom)) {
								grafo.invertirSeleccionVertice(v);
								verticesInvertidosYa.add(v);
							} else if (verticesInvertidosYa.contains(v) && !Utilidades.estaDentroRegion(v.getPunto(), puntoPulsado, e.getPoint(), zoom)) {
								grafo.invertirSeleccionVertice(v);
								verticesInvertidosYa.remove(v);
							}
							panelInfo.mostrarNumeroVerticesSeleccionados(grafo.getVerticesSeleccionados().size());
						}
						repaint();
					}
				}
			}
		});

		addMouseListener(new MouseAdapter() {

			public void mousePressed(MouseEvent e) {
				if(panelInfo.getModoEscritura().isEnabled()) {
					puntoPulsado = new Point((int)Math.round(e.getPoint().getX()) ,(int)Math.round(e.getPoint().getY()));
					Point puntoPulsadoZoom = new Point((int)Math.round(e.getPoint().getX() / zoom) ,(int)Math.round(e.getPoint().getY() / zoom));
					verticePulsado = grafo.obtenerVerticeEnPunto(puntoPulsadoZoom);
					aristaPulsada = grafo.obtenerAristaEnPunto(puntoPulsadoZoom);
					if(e.getButton() == 1 && grafo.getVerticesSeleccionados().contains(verticePulsado))
						arrastra = true;
				}
			}

			public void mouseReleased(MouseEvent e) {
				if(panelInfo.getModoEscritura().isEnabled()) {
					arrastra = false;
					verticesInvertidosYa = new ArrayList<Vertice>();
					verticeSoltado = grafo.obtenerVerticeEnPunto(new Point((int)Math.round(e.getPoint().getX() / zoom) ,(int)Math.round(e.getPoint().getY() / zoom)));
					if(verticePulsado != null && verticeSoltado != null && verticePulsado != verticeSoltado) {
						logger.info("Nueva arista añadida");
						Arista a = new Arista(verticePulsado, verticeSoltado, grafo.getAristaId(), false);
						grafo.anadirArista(a);
						panelInfo.mostrarNumeroAristas(grafo.getAristas().size());
						Resultados.setMatriz((int[][])null);
						repaint();
					}
				}
			}

			public void mouseClicked(MouseEvent e) {
				if(panelInfo.getModoEscritura().isEnabled()) {
					if(verticePulsado == null && aristaPulsada == null) {
						logger.info("Nuevo vértice añadido");
						grafo.anadirVertice(new Vertice(new Point((int)Math.round(e.getPoint().getX() / zoom) ,(int)Math.round(e.getPoint().getY() / zoom)), grafo.getVerticeId(), false));
						panelInfo.mostrarNumeroVertices(grafo.getVertices().size());
						Resultados.setMatriz((int[][])null);
					} else if(verticePulsado != null) {
						if(!Utilidades.esVaciaONula(getGrafo().getVerticesSeleccionados()) && !e.isControlDown()) {
							logger.info("Todos los elementos han sido deseleccionados");
							grafo.deseleccionarTodosVertices();
							grafo.deseleccionarTodasAristas();
							panelInfo.mostrarNumeroVerticesSeleccionados(0);
							panelInfo.mostrarNumeroAristasSeleccionadas(0);
						}
						if(!(!Utilidades.esVaciaONula(getGrafo().getVerticesSeleccionados()) && grafo.getVerticesSeleccionados().contains(verticePulsado) && e.isControlDown())) {
							logger.info("Vértice añadido a seleccionados");
							grafo.seleccionarVertice(verticePulsado);
							panelInfo.mostrarNumeroVerticesSeleccionados(grafo.getVerticesSeleccionados().size());
						} else if(e.getButton() != 3){
							logger.info("El vértice ha sido deseleccionado");
							grafo.deseleccionarVertice(verticePulsado);
							panelInfo.mostrarNumeroVerticesSeleccionados(grafo.getVerticesSeleccionados().size());
						}
						if(e.getButton() == 3) {
							logger.info("Menú contextual mostrado");
							menuContextual.getBotonMover().setVisible(true);
							ContextualAction.setVerticePulsado(verticePulsado);
							add(menuContextual);
							menuContextual.show(menuContextual.getParent(), e.getX(), e.getY());
						}
					} else if(aristaPulsada != null) {
						if(!Utilidades.esVaciaONula(getGrafo().getAristasSeleccionadas()) && !e.isControlDown()) {
							logger.info("Todos los elementos han sido deseleccionados");
							grafo.deseleccionarTodasAristas();
							grafo.deseleccionarTodosVertices();
							panelInfo.mostrarNumeroAristasSeleccionadas(0);
							panelInfo.mostrarNumeroVerticesSeleccionados(0);
						}
						if(!(!Utilidades.esVaciaONula(getGrafo().getAristasSeleccionadas()) && grafo.getAristasSeleccionadas().contains(aristaPulsada) && e.isControlDown())) {
							logger.info("Arista añadida a seleccionadas");
							grafo.seleccionarArista(aristaPulsada);
							panelInfo.mostrarNumeroAristasSeleccionadas(grafo.getAristasSeleccionadas().size());
						} else if(e.getButton() != 3){
							logger.info("La arista ha sido deseleccionada");
							grafo.deseleccionarArista(aristaPulsada);
							panelInfo.mostrarNumeroAristasSeleccionadas(grafo.getAristasSeleccionadas().size());
						}
						if(e.getButton() == 3) {
							logger.info("Menú contextual mostrado");
							menuContextual.getBotonMover().setVisible(false);
							add(menuContextual);
							menuContextual.show(menuContextual.getParent(), e.getX(), e.getY());
						}
					}
					repaint();
				}
			}
		});
	}

	public void paintComponent(Graphics g) {
		Graphics2D g2D = (Graphics2D)g;
		g2D.scale(zoom, zoom);
		super.paintComponent(g2D);
		if(grafo.getVertices().size() > 0)
			grafo.dibujarGrafo(g2D);
	}

	public Grafo getGrafo() {
		return grafo;
	}

	public void setGrafo(Grafo g) {
		grafo = g;
	}

	public ResourceBundle getMensajes() {
		return mensajes;
	}

	public void setMensajes(ResourceBundle m) {
		mensajes = m;
		grafo.setMensajes(mensajes);
	}
	
	public double getZoom() {
		return zoom;
	}

	public void setZoom(double zoom) {
		this.zoom = zoom;
	}
}