/**
 * ---------------------------------------------------------------------
 * $Id: Simulador.java,v 1.0 2013/08/23 
 * Universidad Francisco de Paula Santander 
 * Programa Ingenieria de Sistemas
 *
 * Proyecto: SEED_UFPS
 * ----------------------------------------------------------------------
 */

package simsecuencia;

import Mundo_Secuencia.SimuladorSecuencia;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.image.ImageView;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.util.Duration;

/**
 * Clase controlador del Vista.FXML donde se crean y manipulan los componente javafx de la Aplicacion.
 * @author Uriel Garcia - Yulieth Pabon
 * @version 1.0
 */

public class Simulador implements Initializable {
    
    @FXML   private     Rectangle   pos, pos1, pos2, pos3, pos4, pos5, pos6, pos7, pos8, pos9, pos10, 
                                    pos11, pos12, pos13, pos14, pos15, pos16, pos17, pos18, pos19, pos20,
                                    pos21, pos22, pos23, pos24, piv;    
    @FXML   private     Label       p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, 
                                    p11, p12, p13, p14, p15, p16, p17, p18, p19,
                                    p20, p21, p22, p23, p24;  
    @FXML   private     TextField   txtCap, txtIns, txtEli, txtGet, txtEdit1, txtEdit2;    
    @FXML   private     Label       label, label1, label2, label3, label4, label5, label6, label7, label8, label9, label10,
                                    label11, label12, label13, label14, label15, label16, label17, label18, label19, 
                                    label20, label21, label22, label23, label24, nota, msg, labelPiv;    
    @FXML   private     ImageView   borde2, borde3, borde;
    @FXML   private     Rectangle[] objs;    
    @FXML   private     Label[]     labels, posic;    
    @FXML   private     Timeline    lineaTiempo;
    @FXML   private     SimuladorSecuencia simulador;

    
    
    @FXML
    private void btCrear(ActionEvent event) {
        try{
            //Validacion de la entrada
            String val = txtCap.getText(); 
            txtCap.setText("");
            if(val.isEmpty()){
                impNota("Debe ingresar un tamaño para la Secuencia!",1);
                return;
            }       
            if(!esNumero(val)){
                impNota("Debe ingresar un valor numerico!",1);
                return;
            }             
            int cap = Integer.parseInt(val);
            if(cap<1 || cap>25){
                impNota("Cantidad de posiciones incorrecta. Rango permitido: 1 a 25!",1);
                return;
            }
            if(objs==null || labels==null || posic==null || this.simulador==null){
                impNota("No se puede crear la Secuencia!",1);
                return;
            }        
            
            //crear la Secuencia
            this.simulador.crearSecuencia(cap);
            this.pintarTDA();           
            impNota("Se ha creado una Secuencia con "+cap+" posiciones!",0);  
            
        }catch(Exception e){
            impNota("No se puede crear la Secuencia!",1);
        }        
    }
    
    @FXML
    private void btIns(ActionEvent event){        
        try{   
            //Realizacion de la validacion
            String val = txtIns.getText();        
            txtIns.setText("");
            if(val.isEmpty()){
                impNota("Debe ingresar el dato a Insertar en la Secuencia!",1);
                return;
            }        
            if(!esNumero(val)){
                impNota("Debe ingresar un valor numerico!",1);
                return;
            } 
            if(objs==null || this.labels==null || posic==null || this.simulador==null || this.simulador.getMiSecuencia()==null){
                impNota("No se puede insertar el Elemento!",1);
                return;
            }
            if(!simulador.puedeInsertar()){
                impNota("La Secuencia se encuentra llena!",1);
                return;
            }
            int dato = Integer.parseInt(val);
            if(dato>=1000 || dato<=-100){
                impNota("El valor ingresado supera el rango permitido: -99 a 999!",1);
                return;
            }            
            
            //Realizacion de la Insercion
            boolean rta = this.simulador.insertar(dato);
            this.pintarTDA();
            if(!rta)
                impNota("El elemento ya se encuentra insertado en la Secuencia",1);  
            else{
                impNota("El Elemento ha sido insertado en la Secuencia.",0); 
                int ind = this.simulador.obtenerIndice(dato);
                this.animacion(0, ind,dato); 
           }
        }catch(Exception e){
            impNota("No se puede insertar el Elemento!",1);
        }
    }    
    
    @FXML
    private void btEli(ActionEvent event){        
        try{
            //Realizaciond de la validacion
            String val = txtEli.getText();  
            txtEli.setText("");
            if(val.isEmpty()){
                impNota("Debe ingresar el dato a Eliminar en la Secuencia!",1);
                return;
            }        
            if(!esNumero(val)){
                impNota("Debe ingresar un valor numerico!",1);
                return;
            } 
            if(objs==null || labels==null || posic==null || simulador==null || this.simulador.getMiSecuencia()==null){
                impNota("No se puede eliminar el Elemento!",1);
                return;
            }
            if(this.simulador.esVacia()){
                impNota("La Secuencia aun no posee Elementos!",1);
                return;
            }        
            
            //Eliminar el dato
            int dato = Integer.parseInt(val); 
            int posi = this.simulador.obtenerIndice(dato);
            boolean rta = simulador.eliminar(dato); 
            this.pintarTDA();
            if(!rta)
                impNota("El Elemento a eliminar no existe!",1); 
            else{
                impNota("El elemento '"+dato+"' ha sido eliminado de la Secuencia!",0); 
                this.animacion(1, posi, dato);
            }
            
        }catch(Exception e){
            impNota("No se puede eliminar el Elemento!",1);
        }        
    }
    
    @FXML
    private void btGet(ActionEvent event){
        try{      
            //Realizacion de las validaciones
            String val = txtGet.getText();        
            txtGet.setText("");
            if(val.isEmpty()){
                impNota("Debe ingresar la posicion del Elemento!",1);
                return;
            }        
            if(!esNumero(val)){
                impNota("Debe ingresar un valor numerico!",1);
                return;
            } 
            if(objs==null || labels==null || posic==null || simulador==null || this.simulador.getMiSecuencia()==null){
                impNota("No se puede obtener el Elemento!",1);
                return;
            }
            if(this.simulador.esVacia()){
                impNota("La Secuencia aun no posee Elementos!",1);
                txtGet.setText("");
                return;
            }        
            int posi = Integer.parseInt(val);      
            
            //Ubicar el elemento            
            int dato = this.simulador.obtenerElemento(posi);
            if(dato==(-100)){
                impNota("No se ha encontrado un elemento en esta posicion!",1);
            }
            else{
                this.animacion(2, posi, dato);
                impNota("El elemento ha sido encontrado: '"+dato+"'!",0);
            }             
        }catch(Exception e){
            impNota("No se puede obtener el Elemento!",1);
        }
        
    }
    
    @FXML
    private void btTam(ActionEvent event){
        try{ 
            if(objs==null || labels==null || posic==null || simulador==null || this.simulador.getMiSecuencia()==null){
                impNota("No se puede determinar el tamaño!",1);
                return;
            }
            msg.setVisible(true);            
            msg.setText("Tamaño de la Secuencia: "+this.simulador.conocerTamanio()+" Elementos!");
            impNota("Tamaño de la Secuencia calculado!",0);
        }catch(Exception e){
            impNota("No se puede determinar el Tamaño!",1);
            msg.setVisible(false);
        }
    }
    
    @FXML
    private void btCap(ActionEvent event){
        try{
            if(objs==null || labels==null || posic==null || simulador==null || this.simulador.getMiSecuencia()==null){
                impNota("No se puede determinar la capacidad!",1);
                return;
            }
            msg.setVisible(true);
            msg.setText("Capacidad de la Secuencia: "+this.simulador.conocerCapacidad()+" posiciones!");
            impNota("Capacidad de la Secuencia calculada!",0);
        }catch(Exception e){
            impNota("No se puede determinar la Capacidad!",1);
            msg.setVisible(false);
        }        
    }
    
    @FXML
    private void btEdit(ActionEvent event){        
        try{
            //Realizacion de las validaciones
            String cad1 = txtEdit1.getText();
            String cad2 = txtEdit2.getText();
            txtEdit1.setText("");
            txtEdit2.setText("");
            if(cad1.isEmpty() || cad2.isEmpty()){
                impNota("Debe ingresar la posicion a reemplazar y el nuevo Elemento!",1);
                return;
            }        
            if(!esNumero(cad1) || !esNumero(cad2)){
                impNota("Debe ingresar valores numericos!",1);
                return;
            }
            if(objs==null || labels==null || posic==null || simulador==null || this.simulador.getMiSecuencia()==null){
                impNota("No se puede editar el elemento!",1);
                return;
            }
            if(this.simulador.esVacia()){
                impNota("La Secuencia aun no posee Elementos!",1);
                return;
            }
            int posi = Integer.parseInt(cad1); 
            int dato = Integer.parseInt(cad2);
            if(dato>=1000 || dato<=-100){
                impNota("El valor ingresado supera el rango permitido: -99 a 999!",1);
                return;
            } 
            
            //Editar el dato             
            int rta = this.simulador.editar(posi,dato);
            this.pintarTDA();
            if(rta==0){
                impNota("El elemento en la posicion '"+posi+"' ha sido reemplazado por el Elemento '"+dato+"'",0 );
                this.animacion(3, posi, dato);
            }
            if(rta==-1)
                impNota("El elemento con el que desea reemplazar ya existe en la Secuencia!",1 );
            if(rta==-2)
                impNota("La posicion ingresada para la edicion es Incorrecta!",1 );
            
        }catch(Exception e){
            impNota("No se puede editar el Elemento!",1);            
        }        
    }    
    
    
    @FXML
    private void salir(ActionEvent event){
        System.exit(0);
    }    

    @FXML
    private void inicializar(){ 
        objs[0]=pos;objs[1]=pos1;objs[2]=pos2;objs[3]=pos3;objs[4]=pos4;
        objs[5]=pos5;objs[6]=pos6;objs[7]=pos7;objs[8]=pos8;objs[9]=pos9;
        objs[10]=pos10;objs[11]=pos11;objs[12]=pos12;objs[13]=pos13;objs[14]=pos14;
        objs[15]=pos15;objs[16]=pos16;objs[17]=pos17;objs[18]=pos18;objs[19]=pos19;
        objs[20]=pos20;objs[21]=pos21;objs[22]=pos22;objs[23]=pos23;objs[24]=pos24;
        for(int i=0; i<objs.length; i++){
            objs[i].setVisible(false);
        } 
        labels[0]=label;labels[1]=label1;labels[2]=label2;labels[3]=label3;labels[4]=label4;
        labels[5]=label5;labels[6]=label6;labels[7]=label7;labels[8]=label8;labels[9]=label9;
        labels[10]=label10;labels[11]=label11;labels[12]=label12;labels[13]=label13;labels[14]=label14;
        labels[15]=label15;labels[16]=label16;labels[17]=label17;labels[18]=label18;labels[19]=label19;
        labels[20]=label20;labels[21]=label21;labels[22]=label22;labels[23]=label23;labels[24]=label24;
        for(int i=0; i<labels.length; i++){
            labels[i].setVisible(false);
        } 
        posic[0]=p0;posic[1]=p1;posic[2]=p2;posic[3]=p3;posic[4]=p4;
        posic[5]=p5;posic[6]=p6;posic[7]=p7;posic[8]=p8;posic[9]=p9;
        posic[10]=p10;posic[11]=p11;posic[12]=p12;posic[13]=p13;posic[14]=p14;
        posic[15]=p15;posic[16]=p16;posic[17]=p17;posic[18]=p18;posic[19]=p19;
        posic[20]=p20;posic[21]=p21;posic[22]=p22;posic[23]=p23;posic[24]=p24;
        for(int i=0; i<posic.length; i++){
            posic[i].setVisible(false);
        }
        //Objetos que muestran mensaje en consola
        msg.setVisible(false);
        this.piv.setVisible(false);
        this.labelPiv.setVisible(false);
    }
   
        
    @FXML
    private void impNota(String nota, int tipo){
        String cab = "";
        if(tipo==0){
            cab="Exito, ";
            this.nota.setTextFill(Color.BLACK);
            this.borde.setImage(borde2.getImage());
        }            
        if(tipo==1){
            cab="Error, ";
            this.nota.setTextFill(Color.BLACK);
            this.borde.setImage(borde3.getImage());
        }
        this.nota.setVisible(true);
        this.nota.setText(cab+nota);
    }
    
    @FXML
    private boolean esNumero(String val){
    try{
        Integer.parseInt(val);
        }catch(Exception e){
            return (false);
        }
        return (true);
    }

    @FXML
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        //Inicializar los diferentes tipos de datos utilizados.
        this.objs = new Rectangle[25];
        this.labels = new Label[25];
        this.posic = new Label[25];
        this.simulador = new SimuladorSecuencia();
        this.lineaTiempo = new Timeline();
        //Inicializar los objetos graficos
        this.inicializar();
        this.impNota("El Simulador para Secuencia<T> ha iniciado!",0);
    }
    
    @FXML
    private void pintarTDA() {
        this.inicializar();
        double lx = 185.0;
        String datos[] = this.simulador.impSecuencia().split("_");
        for(int i=0; i<this.simulador.conocerCapacidad(); i++){
            this.objs[i].setLayoutX(lx);
            this.objs[i].setVisible(true);
            this.posic[i].setLayoutX(lx);
            this.posic[i].setVisible(true);
            this.labels[i].setLayoutX(lx);
            String val = "";
            if(i<datos.length)
                val = datos[i];
            this.labels[i].setText(val);
            this.labels[i].setVisible(true);
            lx = lx + 25.0;            
        }
    }
    
    @FXML
    private void animacion(int tipo, int posi, int val){
        this.ocultaAnim();
        msg.setVisible(false);
        lineaTiempo = new Timeline();
        lineaTiempo.setCycleCount(1); 
        KeyFrame f1=null,f11=null,f2=null,f22=null,f3=null,f33=null,f4=null,f44=null,
                f5=null,f55=null,f6=null,f66=null;
        double durac = 2000;
        switch(tipo){
            //Añadir al inicio
            case 0 :
                piv.setLayoutX(185.0);
                piv.setLayoutY(220.0);
                labelPiv.setLayoutX(185.0);
                labelPiv.setLayoutY(220.0);
                piv.setFill(Color.GREEN);
                piv.setStroke(Color.BLACK);
                labelPiv.setText(val+"");                
                double lx = (posi*(25.0));
                //Mover en X
                f1 = new KeyFrame(Duration.ZERO, new KeyValue(piv.translateXProperty(),0));
                f11 = new KeyFrame(Duration.ZERO, new KeyValue(labelPiv.translateXProperty(),0));
                f2 = new KeyFrame(new Duration(durac), new KeyValue(piv.translateXProperty(),lx));
                f22 = new KeyFrame(new Duration(durac), new KeyValue(labelPiv.translateXProperty(),lx));
                //Mover en Y
                f3 = new KeyFrame(Duration.ZERO, new KeyValue(piv.translateYProperty(),0));
                f33 = new KeyFrame(new Duration(durac), new KeyValue(piv.translateYProperty(),50));
                f4 = new KeyFrame(Duration.ZERO, new KeyValue(labelPiv.translateYProperty(),0));
                f44 = new KeyFrame(new Duration(durac), new KeyValue(labelPiv.translateYProperty(),50));
                //Mover COlor
                f5 = new KeyFrame(new Duration(durac), new KeyValue(piv.fillProperty(),Color.GREEN));
                f55 = new KeyFrame(new Duration(durac+1000), new KeyValue(piv.fillProperty(),Color.web("#33e7ff")));
                f6 = new KeyFrame(new Duration(durac), new KeyValue(piv.strokeProperty(),Color.BLACK));
                f66 = new KeyFrame(new Duration(durac+1000), new KeyValue(piv.strokeProperty(),Color.web("#1400ff")));                
                break;
                
                //Eliminar
            case 1 :
                labelPiv.setText(val+"");                  
                double x = objs[posi].getLayoutX();
                double y = objs[posi].getLayoutY();
                piv.setLayoutX(x);
                piv.setLayoutY(y);
                piv.setFill(Color.web("#33e7ff"));
                piv.setStroke(Color.web("#1400ff"));
                labelPiv.setLayoutX(x);
                labelPiv.setLayoutY(y);
                //Agregar los fotogramas. Empieza en cero y se traslada hasta la distancia.
                //Mover en X
                f1 = new KeyFrame(Duration.ZERO, new KeyValue(piv.translateXProperty(),0));
                f11 = new KeyFrame(Duration.ZERO, new KeyValue(labelPiv.translateXProperty(),0));
                f2 = new KeyFrame(new Duration(durac), new KeyValue(piv.translateXProperty(),(-piv.getLayoutX()+185)));
                f22 = new KeyFrame(new Duration(durac), new KeyValue(labelPiv.translateXProperty(),(-labelPiv.getLayoutX()+185)));
                //Mover en Y
                f3 = new KeyFrame(Duration.ZERO, new KeyValue(piv.translateYProperty(),0));
                f33 = new KeyFrame(new Duration(durac), new KeyValue(piv.translateYProperty(),-50.0));
                f4 = new KeyFrame(Duration.ZERO, new KeyValue(labelPiv.translateYProperty(),0));
                f44 = new KeyFrame(new Duration(durac), new KeyValue(labelPiv.translateYProperty(),-50.0));
                //Mover el COlor
                f5 = new KeyFrame(new Duration(durac), new KeyValue(piv.fillProperty(),Color.web("#33e7ff")));
                f55 = new KeyFrame(new Duration(durac+1000), new KeyValue(piv.fillProperty(),Color.RED));
                f6 = new KeyFrame(new Duration(durac), new KeyValue(piv.strokeProperty(),Color.web("#1400ff")));
                f66 = new KeyFrame(new Duration(durac+1000), new KeyValue(piv.strokeProperty(),Color.BLACK));                
                break;
                //GEt
            case 2 :
                labelPiv.setText(val+"");                  
                piv.setLayoutX(185);
                piv.setLayoutY(270);
                piv.setFill(Color.ORANGE);
                piv.setStroke(Color.BLACK);
                labelPiv.setLayoutX(185);
                labelPiv.setLayoutY(270);
                //Mover en X
                f1 = new KeyFrame(Duration.ZERO, new KeyValue(piv.translateXProperty(),0));
                f11 = new KeyFrame(Duration.ZERO, new KeyValue(labelPiv.translateXProperty(),0));
                f2 = new KeyFrame(new Duration(durac), new KeyValue(piv.translateXProperty(),(objs[posi].getLayoutX()-185)));
                f22 = new KeyFrame(new Duration(durac), new KeyValue(labelPiv.translateXProperty(),(labels[posi].getLayoutX()-185)));        
                //Mover en Y
                f3 = new KeyFrame(Duration.ZERO, new KeyValue(piv.translateYProperty(),0));
                f33 = new KeyFrame(new Duration(durac), new KeyValue(piv.translateYProperty(),0));
                f4 = new KeyFrame(Duration.ZERO, new KeyValue(labelPiv.translateYProperty(),0));
                f44 = new KeyFrame(new Duration(durac), new KeyValue(labelPiv.translateYProperty(),0));
                //Cambiar color
                f5 = new KeyFrame(new Duration(durac), new KeyValue(piv.fillProperty(),Color.ORANGE));
                f55 = new KeyFrame(new Duration(durac+1000), new KeyValue(piv.fillProperty(),Color.web("#33e7ff")));
                f6 = new KeyFrame(new Duration(durac), new KeyValue(piv.strokeProperty(),Color.BLACK));
                f66 = new KeyFrame(new Duration(durac+1000), new KeyValue(piv.strokeProperty(),Color.web("#1400ff")));  
                break;
                
                //SEt
            case 3: 
                labelPiv.setText(val+"");                
                piv.setLayoutX(185);
                piv.setLayoutY(270);
                piv.setFill(Color.ORANGE);
                piv.setStroke(Color.BLACK);
                labelPiv.setLayoutX(185);
                labelPiv.setLayoutY(270);
                //Mover en X
                f1 = new KeyFrame(Duration.ZERO, new KeyValue(piv.translateXProperty(),0));
                f11 = new KeyFrame(Duration.ZERO, new KeyValue(labelPiv.translateXProperty(),0));
                f2 = new KeyFrame(new Duration(durac), new KeyValue(piv.translateXProperty(),(objs[posi].getLayoutX()-185)));
                f22 = new KeyFrame(new Duration(durac), new KeyValue(labelPiv.translateXProperty(),(labels[posi].getLayoutX()-185)));        
                //Mover en Y
                f3 = new KeyFrame(Duration.ZERO, new KeyValue(piv.translateYProperty(),0));
                f33 = new KeyFrame(new Duration(durac), new KeyValue(piv.translateYProperty(),0));
                f4 = new KeyFrame(Duration.ZERO, new KeyValue(labelPiv.translateYProperty(),0));
                f44 = new KeyFrame(new Duration(durac), new KeyValue(labelPiv.translateYProperty(),0));    
                //Cambiar Color
                f5 = new KeyFrame(new Duration(durac), new KeyValue(piv.fillProperty(),Color.ORANGE));
                f55 = new KeyFrame(new Duration(durac+1000), new KeyValue(piv.fillProperty(),Color.web("#33e7ff")));
                f6 = new KeyFrame(new Duration(durac), new KeyValue(piv.strokeProperty(),Color.BLACK));
                f66 = new KeyFrame(new Duration(durac+1000), new KeyValue(piv.strokeProperty(),Color.web("#1400ff")));  
                break;
        }
        piv.setVisible(true);
        labelPiv.setVisible(true);
        lineaTiempo.getKeyFrames().addAll(f1,f11,f2,f22,f3,f33,f4,f44,f5,f55,f6,f66);
        lineaTiempo.play();
    }

    private void ocultaAnim() {
        this.lineaTiempo = new Timeline();
        this.lineaTiempo.stop();
        this.piv.setVisible(false);
        this.labelPiv.setVisible(false);
    }


    
    
}
