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

package sdsimulator.interfaz;
import javax.swing.*;

import java.awt.*;
import myuml.*; //Definición de todos los elementos necesarios para componer un 
// diagrama de secuencia. Forma parte de la aplicación WST. Cambios en este 
//paquete, afectarían a la ejecución del programa.
//import java.lang.Exception;
//import java.lang.*;
import com.borland.jbcl.layout.*; //Este paquete deberá estar en el classpath cuando
//ejecutemos el .jar De él se usan las XYConstraints, entre otras.
import java.util.*;

/**
 *
 * @author Miguel Herreros
 */
public class JPanelDiagrama extends JPanel {
    public JPanelDiagrama(Component [] vectorComponentes) throws Exception{
        initComponents();
        cargarVectorComponentes(vectorComponentes);
    }
    
    private void initComponents(){
        //Prepara el panel para mostrar un diagrama.
        setBackground(sdsimulator.Main.FONDO);
        //Dejar la variable de estado a su valor por defecto. De hecho, esta va-
        //riable no se va a usar, porque los mensajes ya están dibujados.
        Shared.state = Shared.state.DEFAULT;
        setLayout(new XYLayout());//Fundamental para colocar los elementos en el diagrama.
    }
    
    //..........................................................................
    /** Añade los componentes contenidos en un vector de componentes al jpanel 
     *  que se mostrará en pantalla.
     *  Ignora la toolbar incluída dentro del panel original, y además, recoloca
     *  todo el diagrama para rellenar el hueco dejado al excluir la toolbar.
     *  genera una excepción si no encuentra lo que se esperaba.
     * @param vectorComponentes
     */
    private void cargarVectorComponentes(Component[] vectorComponentes) throws Exception{
        for (int i=0;i<vectorComponentes.length;i++){
            if (vectorComponentes[i] instanceof MyLifeLine)
               agregarMyLifeLine(vectorComponentes[i]);
            
            else if (vectorComponentes[i] instanceof MyActor)
               agregarMyActor(vectorComponentes[i]);
            
            else if (vectorComponentes[i] instanceof MyMessage)
                agregarMyMessage(vectorComponentes[i]);
            
            else if (vectorComponentes[i] instanceof MyFrame)
                agregarMyFrame(vectorComponentes[i]);
            
            else if (vectorComponentes[i] instanceof JToolBar)
                continue; //Esto existe para poder abrir diagramas viejos, que tenían 
                //la toolbar del integrada en el panel del diagrama.
            else{
                //Hemos encontrado un objeto 'extraño'
                Exception e = new Exception("Unknow component found in diagram");
                throw e;
            }
        }
        
        refrescarReferencias();
    }
              
    private void agregarMyLifeLine(Component componentAntiguo){
        MyLifeLine antiguo = (MyLifeLine) componentAntiguo;
        
        //No hay constructor copia ni sobrecarga de clone en XYConstraints.
        XYConstraints coordenadas = new XYConstraints();
        coordenadas.setX(antiguo.getXY().getX());
        coordenadas.setY(antiguo.getXY().getY());
        coordenadas.setWidth(antiguo.getXY().getWidth());
        coordenadas.setHeight(antiguo.getXY().getHeight());
        
        MyLifeLine nuevo = new MyLifeLine(antiguo.getName(),coordenadas);
        
        //Recuperar el ID.
        nuevo.setID(antiguo.getID());
        
        //Recuperar los mensajes enviados y recibidos. En realidad, estas refe-
        //rencias apuntan a objetos antiguos. Deben ser refrescadas una vez se 
        //hayan añadido todos los componentes del diagrama al JPanel para dibu-
        //jarlos.
        //CUIDADO. EN EL CASO DE QUE SE TRATE DE OBJETOS, ESTÁ COPIÁNDOSE LA 
        //REFERENCIA AL OBJETO EN LA INSTANCIA ORIGINAL. CAMBIARLOS SIGNIFICARÁ 
        //QUE QUEDAN CAMBIADOS EN LA INSTANCIA ORIGINAL. SI DA PROBLEMAS, HABRÁ 
        //QUE MONTAR UN DUPLICADO REAL DE LOS ATRIBUTOS-OBJETO QUE ALTEREMOS.
        nuevo.sendedMsg   = antiguo.sendedMsg;
        nuevo.receivedMsg = antiguo.receivedMsg;

        //Recuperar las variables definidas
        nuevo.setVariables(antiguo.getVariables());
        
        //Esto es cosecha nuestra
        nuevo.setCol(sdsimulator.Main.NUEVO);
        
        add(nuevo,coordenadas,0); //Lo asigna realmente al panel
   }
    
    private void agregarMyActor(Component componentAntiguo){
        MyActor antiguo = (MyActor) componentAntiguo;
        
        //No hay constructor copia ni sobrecarga de clone en XYConstraints.
        XYConstraints coordenadas = new XYConstraints();
        coordenadas.setX(antiguo.getXY().getX());
        coordenadas.setY(antiguo.getXY().getY());
        coordenadas.setWidth(antiguo.getXY().getWidth());
        coordenadas.setHeight(antiguo.getXY().getHeight());
        
        MyActor nuevo = new MyActor(antiguo.getName(),coordenadas);
        
        //Recuperar el ID.
        nuevo.setID(antiguo.getID());

        //Recuperar los mensajes enviados y recibidos. En realidad, estas refe-
        //rencias apuntan a objetos antiguos. Deben ser refrescadas una vez se 
        //hayan añadido todos los componentes del diagrama al JPanel para dibu-
        //jarlos.
        //CUIDADO. EN EL CASO DE QUE SE TRATE DE OBJETOS, ESTÁ COPIÁNDOSE LA 
        //REFERENCIA AL OBJETO EN LA INSTANCIA ORIGINAL. CAMBIARLOS SIGNIFICARÁ 
        //QUE QUEDAN CAMBIADOS EN LA INSTANCIA ORIGINAL. SI DA PROBLEMAS, HABRÁ 
        //QUE MONTAR UN DUPLICADO REAL DE LOS ATRIBUTOS-OBJETO QUE ALTEREMOS.
        nuevo.sendedMsg   = antiguo.sendedMsg;
        nuevo.receivedMsg = antiguo.receivedMsg;

        //Recuperar las variables definidas
        nuevo.setVariables(antiguo.getVariables());
        
        //Esto es cosecha nuestra
        nuevo.setCol(sdsimulator.Main.NUEVO);

        add(nuevo,coordenadas,0); //Lo asigna realmente al panel   
    }
    
    private void agregarMyMessage(Component componentAntiguo){
        MyMessage antiguo = (MyMessage) componentAntiguo;
        
        //No hay constructor copia ni sobrecarga de clone en XYConstraints.
        XYConstraints coordenadas = antiguo.getXY();
        new XYConstraints();
        coordenadas.setX(antiguo.getXY().getX());
        coordenadas.setY(antiguo.getXY().getY());
        coordenadas.setWidth(antiguo.getXY().getWidth());
        coordenadas.setHeight(antiguo.getXY().getHeight());
        

        MyMessage nuevo = new MyMessage(coordenadas, antiguo.getAsin());
        
        //Recuperar todos los atributos del mensage. 
        //source y dest apuntan apuntan a objetos antiguos. Deben ser refresca-
        //das una vez se hayan añadido todos los componentes del diagrama al 
        //JPanel para dibujarlos. 
        //CUIDADO. EN EL CASO DE QUE SE TRATE DE OBJETOS, ESTÁ COPIÁNDOSE LA 
        //REFERENCIA AL OBJETO EN LA INSTANCIA ORIGINAL. CAMBIARLOS SIGNIFICARÁ 
        //QUE QUEDAN CAMBIADOS EN LA INSTANCIA ORIGINAL. SI DA PROBLEMAS, HABRÁ 
        //QUE MONTAR UN DUPLICADO REAL DE LOS ATRIBUTOS-OBJETO QUE ALTEREMOS.
        nuevo.setID(antiguo.getID());
        nuevo.setName(antiguo.getName());
        nuevo.source   = antiguo.source;
        nuevo.dest     = antiguo.dest;
        nuevo.inverted = antiguo.inverted;
        nuevo.setUpdates(antiguo.getUpdates());

        //Esto es cosecha nuestra
        nuevo.setCol(sdsimulator.Main.NUEVO);

        add(nuevo, coordenadas, 0);
    }
    
    private void agregarMyFrame(Component componentAntiguo){
        //Recuperamos todos los componentes añadidos hasta ahora
        
        //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
        //En la lista, los frames están al final (detrás del resto de componentes)
        //El orden entre los frames es primero el más reciente. Esto es para con-
        //trolar los solapamientos al dibujar.
        Component [] lista = getComponents();

        int posicion = 0;

        for (int i = lista.length - 1; i > 0; i--) {
            //Si no se trata de un frame
            if (!(lista[i] instanceof MyFrame)) {
                posicion = i + 1;
                break;
            }
        }
        //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
        MyFrame antiguo = (MyFrame) componentAntiguo;
        
        //No hay constructor copia ni sobrecarga de clone en XYConstraints.
        XYConstraints coordenadas = antiguo.getXY();
        new XYConstraints();
        coordenadas.setX(antiguo.getXY().getX());
        coordenadas.setY(antiguo.getXY().getY());
        coordenadas.setWidth(antiguo.getXY().getWidth());
        coordenadas.setHeight(antiguo.getXY().getHeight());
                 
        MyFrame nuevo = new MyFrame(coordenadas,antiguo.getName());
               
        //Recuperar todos los atributos del frame
        nuevo.setID(antiguo.getID());
        nuevo.includeMsg  = antiguo.includeMsg;
        nuevo.includeFrm  = antiguo.includeFrm;
        nuevo.separadores = antiguo.separadores;
        nuevo.setGuard(antiguo.getGuard());
        nuevo.setRepeat(antiguo.getRepeat());
        nuevo.colocado = true;
        nuevo.setBlock(antiguo.getBlock());
        nuevo.setVariablesGuarda(antiguo.getVariablesGuarda());
        nuevo.setVariablesRepeat(antiguo.getVariablesRepeat());
        nuevo.setGuard_negada(antiguo.getGuard_negada());

        //Esto es cosecha nuestra
        nuevo.setCol(sdsimulator.Main.NUEVO);

        add(nuevo, coordenadas, posicion);
    }
    
    private void refrescarReferencias(){
    //Vamos a actualizar las referencias de los objetos ya añadidos al panel.
        Component[] lista = getComponents(); 
        
        for (int i = 0; i < lista.length; i++) {
            if(lista[i] instanceof MyLifeLine || lista[i] instanceof MyActor){
                refrescarArrayListMsg(((MyObjects)lista[i]).sendedMsg);
                refrescarArrayListMsg(((MyObjects)lista[i]).receivedMsg);
            }
            else if(lista[i] instanceof MyFrame){
                refrescarArrayListMsg(((MyObjects)lista[i]).includeMsg);
                refrescarArrayListFrm(((MyObjects)lista[i]).includeFrm);
            }
            
            else if(lista[i] instanceof MyMessage){
                int verticalSource = ((MyMessage)lista[i]).source.getX();
                int verticalDest   = ((MyMessage)lista[i]).dest.getX();
                
                ((MyMessage)lista[i]).source = refrescarVertical(verticalSource);
                ((MyMessage)lista[i]).dest   = refrescarVertical(verticalDest);                
            }
        }
    }
                           
    private void refrescarArrayListMsg(ArrayList refrescando){
        //Recorre todo el array list borrando cada referencia (están obsoletas),
        //pero antes, guarda la posición horizontal de la misma, para buscar la 
        //que tiene la misma posición entre los componentes recién creados.
        Component[] todosPanel = getComponents(); 

        for(int i = 0; i < refrescando.size(); i++){
            int horizontal = ((MyMessage)refrescando.get(i)).getY();
            refrescando.remove(i);

            //Buscar el mensaje con la misma posición horizontal
            for (int j = 0; j < todosPanel.length; j++) 
                if(todosPanel[j] instanceof MyMessage && ((MyMessage)todosPanel[j]).getY() == horizontal)
                    refrescando.add(i,todosPanel[j]);
        }
    }
    
    private void refrescarArrayListFrm(ArrayList refrescando){
        //Recorre todo el array list borrando cada referencia (están obsoletas),
        //pero antes, guarda la posición horizontal de la misma, para buscar la 
        //que tiene la misma posición entre los componentes recién creados.
        Component[] todosPanel = getComponents(); 

        for(int i = 0; i < refrescando.size(); i++){
            int horizontal = ((MyFrame)refrescando.get(i)).getY();
            refrescando.remove(i);

            //Buscar el frame con la misma posición horizontal
            for (int j = 0; j < todosPanel.length; j++) 
                if(todosPanel[j] instanceof MyFrame && ((MyFrame)todosPanel[j]).getY() == horizontal)
                    refrescando.add(i,todosPanel[j]);
        }
    }
    
    private MyObjects refrescarVertical(int verticalRefrescando){
        //Dada la coordenada vertical original del origen/destino anteriores, se
        //se devuelve el MyObject que está en esa posición.
        Component[] todosPanel = getComponents();
        for (int i = 0; i < todosPanel.length; i++) {
                if(todosPanel[i] instanceof MyActor || todosPanel[i] instanceof MyLifeLine)
                    if (((MyObjects)todosPanel[i]).getXY().getX() == verticalRefrescando){
                        return (MyObjects)todosPanel[i];
                    }    
        }
        return null;
    }
} 
