/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Graficos;

import Colecciones_SEED.ListaCD;
import Colecciones_SEED.Pila;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.scene.control.Label;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.util.Duration;


/*
 * Clase que representa el grafo gráfico
 */
public class GrafoG {

    private ListaCD<VerticeG> misVerticesG;
    private ListaCD<AristaG> misAristasG;
    private Pila<Circle> pila;
    private Pila<Label> lab;
    private Pila<Line> lin;
    private Pila<Character> val;
    private Pila<Label> pesos;
    

    public GrafoG() {
        this.misVerticesG = new ListaCD<VerticeG>();
        this.misAristasG = new ListaCD<AristaG>();
        pila = new Pila();
        lab = new Pila();
        lin = new Pila();
        val = new Pila();
        pesos = new Pila();
    }
    
    /**
     *
     * @param nodos
     */
    public void cargarNodos(Circle[] nodos) {
        for(int i=0; i<nodos.length; i++)
            this.pila.apilar(nodos[i]);
    }

    /**
     *
     * @param labels
     */
    public void cargarLabels(Label[] labels) {
        for(int i=0; i<labels.length; i++)
            this.lab.apilar(labels[i]);
    }

    /**
     *
     * @param lineas
     */
    public void cargarLineas(Line[] lineas) {
        for(int i=0; i<lineas.length; i++)
            this.lin.apilar(lineas[i]);
    }
    
    public void cargarPesos(Label[] p) {
        for(int i=0; i<p.length; i++)
            this.pesos.apilar(p[i]);
    }
    
    
    public void cargarVals(){
       this.val.apilar('Z');
       this.val.apilar('Y');this.val.apilar('X');this.val.apilar('W');this.val.apilar('V');this.val.apilar('U');
       this.val.apilar('T');this.val.apilar('S');this.val.apilar('R');this.val.apilar('Q');this.val.apilar('P');
       this.val.apilar('O');this.val.apilar('N');this.val.apilar('M');this.val.apilar('L');this.val.apilar('K');
       this.val.apilar('J');this.val.apilar('I');this.val.apilar('H');this.val.apilar('G');this.val.apilar('F');
       this.val.apilar('E');this.val.apilar('D');this.val.apilar('C');this.val.apilar('B');this.val.apilar('A');
        
        
    }

    public void pintarGrafo() {
        for(int i=0; i<this.misVerticesG.getTamanio(); i++){
            VerticeG v = this.misVerticesG.get(i);
            Circle c = v.getC();
            Label l = v.getL();
            c.setVisible(true);
            l.setText(v.getInfo()+"");
            l.setVisible(true);
        }
        for(int i=0; i<this.misAristasG.getTamanio(); i++){
            this.misAristasG.get(i).getArco().setVisible(true);
            this.misAristasG.get(i).getP().setTextFill(Color.BLUE);
            this.misAristasG.get(i).getP().setVisible(true);
        }
            
    }

    public char insertarVertice(double lx, double ly) {
        Circle c = this.pila.desapilar();
        Label l = this.lab.desapilar();
        c.setLayoutX(lx);
        c.setLayoutY(ly);
        l.setLayoutX(lx+(-12.0));
        l.setLayoutY(ly+(-6.0));
        VerticeG v = new VerticeG((char)(this.val.desapilar()),c,l);
        this.misVerticesG.insertarAlFinal(v);
        return (v.getInfo());
    }
    
    public char eliminarVertice(double lx, double ly) {
        VerticeG v = this.verticePorCoordenada(lx, ly);
        if(v==null)
            return ('1');
        this.misVerticesG.eliminar(this.misVerticesG.getIndice(v));
        v.getC().setVisible(false);
        v.getL().setVisible(false);
        
        //Eliminar las Aristas Relacionadas
        ListaCD<AristaG> aaux = new ListaCD<AristaG>();  
        
        //Eliminar todos los vertices
        for(AristaG a: this.misAristasG){
            if(!a.getVertA().equals(v) && !a.getVertB().equals(v))
                aaux.insertarAlFinal(a);
        }
      this.misAristasG = aaux;    
      this.val.apilar(v.getInfo());
      return (v.getInfo());
    }
    

    public int impTamanio() {
        return (this.misVerticesG.getTamanio());
    }

    public boolean pintarVertice(double lx, double ly) {
        
        VerticeG v = this.verticePorCoordenada(lx, ly);
        if(v==null)
            return (false);
        
        Circle c = v.getC();
        c.setFill(Color.BEIGE);
        c.setStroke(Color.RED);
        c.setVisible(true);
        
        return (true);
        
    }
    
    public VerticeG verticePorCoordenada(double lx, double ly){
        for(int i=0; i<this.misVerticesG.getTamanio();i++){
             Circle c = this.misVerticesG.get(i).getC();
            double cx = c.getLayoutX();
            double cy = c.getLayoutY();
            if(lx>=(cx-12)&&lx<=(cx+12) && ly>=(cy-12)&&ly<=(cy+12)){
                return (this.misVerticesG.get(i));
            }
        }
        return (null);
    }

    public boolean insertarArista(double lx1, double ly1, double lx2, double ly2, int peso) {
        
        VerticeG v1 = this.verticePorCoordenada(lx1, ly1);
        VerticeG v2 = this.verticePorCoordenada(lx2, ly2);        
        if(v1==null || v2==null || v1.getInfo()==v2.getInfo()){
            return (false);
        }
        
        if(this.getAristaPorVertices(v1, v2)!=null)
            return (false);        
        Circle c1 = v1.getC();
        Circle c2 = v2.getC();
        
        //arco de la arista
        Line l = this.lin.desapilar();
        l.setLayoutX(c1.getLayoutX());
        l.setLayoutY(c1.getLayoutY());
        l.setStartX(0.0);
        l.setEndX((c2.getLayoutX())-(c1.getLayoutX()));
        l.setStartY(0.0);
        l.setEndY((c2.getLayoutY())-(c1.getLayoutY()));
        l.setVisible(true);
        
        //peso de la arista
        Label p = this.pesos.desapilar();
        p.setLayoutX(((c2.getLayoutX()+c1.getLayoutX())/2));
        p.setLayoutY(((c2.getLayoutY()+c1.getLayoutY())/2));
        p.setText(peso+"");
        this.misAristasG.insertarAlFinal(new AristaG(v1,v2,l,peso,p));        
        this.reajustarColores();        
        
        v1.insertarVecino(v2);
        if(v1.getInfo()!=v2.getInfo())
            v2.insertarVecino(v1);
        return (true);        
    }

    public void reajustarColores() {        
        for(int i=0; i<this.misVerticesG.getTamanio();i++){
            Circle c = this.misVerticesG.get(i).getC();
            c.setFill(Color.GREENYELLOW);
            c.setStroke(Color.GREEN);
        }  
        for(int i=0; i<this.misAristasG.getTamanio(); i++){
            Line l = this.misAristasG.get(i).getArco();
            l.setStroke(Color.BLACK);
            this.misAristasG.get(i).getP().setTextFill(Color.BLUE);
        }
    }

    public String getDatosArista(double lx1, double ly1, double lx2, double ly2) {
        String v1 = String.valueOf(this.verticePorCoordenada(lx1, ly1).getInfo());
        String v2 = String.valueOf(this.verticePorCoordenada(lx2, ly2).getInfo());
        return (v1+v2+"");
    }

    public String eliminarArista(double lx1, double ly1, double lx2, double ly2) {
        
        VerticeG v1 = this.verticePorCoordenada(lx1, ly1);
        VerticeG v2 = this.verticePorCoordenada(lx2, ly2);        
        if(v1==null || v2==null){
            return ("");
        }                
        AristaG a = this.getAristaPorVertices(v1, v2);
        if(a==null)
            return "";
        String va = String.valueOf(a.getVertA().getInfo());
        String vb = String.valueOf(a.getVertB().getInfo());        
        int indice = this.misAristasG.getIndice(a);
        if(indice== (-1))
            return "";
        AristaG rta = this.misAristasG.eliminar(indice);
        if(rta==null)
            return "";
        this.lin.apilar(rta.getArco());
        v1.eliminarVecino(v2);
        v2.eliminarVecino(v1);
        this.reajustarColores();        
        
        //Eliminar Aristas
        return (va+vb);
    }
    
    public AristaG getAristaPorVertices(VerticeG v1, VerticeG v2){
        
        for(int i=0; i<this.misAristasG.getTamanio(); i++){
            AristaG a = this.misAristasG.get(i);
            VerticeG aux1 = a.getVertA();
            VerticeG aux2 = a.getVertB();
            
            if( (aux1.getInfo()==v1.getInfo() && aux2.getInfo()==v2.getInfo()) ||
                    (aux1.getInfo()==v2.getInfo() && aux2.getInfo()==v1.getInfo()) )
                return (a);
        }
        
        return (null);
    }

    public boolean puedeInsertar() {
        return (!this.val.esVacia());
    }
    
    public boolean puedeInsertarA() {
        return (!this.lin.esVacia());
    }

    public void animacion(int i, String val, Timeline tl) {
        this.reajustarColores();
        tl = new Timeline();
        tl.setCycleCount(1);
        tl.getKeyFrames().removeAll();
        switch(i){
            //La ruta entre 2 Nodos!
            case 0:
                this.rutaEntreNodos(val,tl);
                break;
            case 1:
                this.rutaBusqueda(val, tl);
                break;              
        }
    }

    private void rutaEntreNodos(String val, Timeline tl) {
        int durac = 0;
        String v[] = val.split("-");
        for(int i=0; i<v.length; i++){
            String ant = "a";
            if(i>0)
                ant = v[i-1];
            String sig = v[i];
            //Pintar el Vertice
            VerticeG v1 = this.verticePorInfo(ant.charAt(0));
            VerticeG v2 =this.verticePorInfo(sig.charAt(0));
            
                    
            tl.getKeyFrames().addAll(new KeyFrame(new Duration(durac), new KeyValue(v2.getC().strokeProperty(),Color.GREEN)),
            new KeyFrame(new Duration((durac+1000)), new KeyValue(v2.getC().strokeProperty(),Color.RED)));
            tl.getKeyFrames().addAll(new KeyFrame(new Duration(durac), new KeyValue(v2.getC().fillProperty(),Color.GREENYELLOW)),
            new KeyFrame(new Duration((durac+1000)), new KeyValue(v2.getC().fillProperty(),Color.BEIGE)));
            durac+=1000;
            
            if(v1!=null){
                AristaG ari = this.getAristaPorVertices(v1, v2);
                if(ari!=null){
                    tl.getKeyFrames().addAll(new KeyFrame(new Duration(durac), new KeyValue(ari.getArco().strokeProperty(),Color.BLACK)),
                    new KeyFrame(new Duration((durac+1000)), new KeyValue(ari.getArco().strokeProperty(),Color.ORANGERED)));
                    tl.getKeyFrames().addAll(new KeyFrame(new Duration(durac), new KeyValue(ari.getP().textFillProperty(),Color.BLUE)),
                    new KeyFrame(new Duration((durac+1000)), new KeyValue(ari.getP().textFillProperty(),Color.ORANGERED)));
                    durac+=1000;
                }
            }            
        }
        tl.play();
    }
    
     private void rutaBusqueda(String val, Timeline tl) {
        int durac = 0;
        String v[] = val.split("-");
        for(int i=0; i<v.length; i++){
            String sig = v[i];
            //Pintar el Vertice
            VerticeG v2 =this.verticePorInfo(sig.charAt(0));            
                    
            tl.getKeyFrames().addAll(new KeyFrame(new Duration(durac), new KeyValue(v2.getC().strokeProperty(),Color.GREEN)),
            new KeyFrame(new Duration((durac+1000)), new KeyValue(v2.getC().strokeProperty(),Color.RED)));
            tl.getKeyFrames().addAll(new KeyFrame(new Duration(durac), new KeyValue(v2.getC().fillProperty(),Color.GREENYELLOW)),
            new KeyFrame(new Duration((durac+1000)), new KeyValue(v2.getC().fillProperty(),Color.BEIGE)));
            durac+=1000;
                      
        }
        tl.play();
    }

    private VerticeG verticePorInfo(char dato) {
        for(VerticeG v: this.misVerticesG){
            if(v.getInfo()==dato)
                return (v);
        }
        return (null);
    }

    public char getPrimerVertice() {
        return (this.misVerticesG.get(0).getInfo());
    }

    

    
 }