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

package sdsimulator.runnable;
import myuml.*;
import java.util.*;

/**
 *
 * @author Miguel Herreros
 */
public class FrameParEjecutable extends FrameEjecutable{
    private int[]   subpasosBloques; //guarda el número de paso por el que va al
                                     //ejecutar cada bloque.
    private Vector  bloquesComponentesEjecutables; //guarda referencias a los componentes
                                                   //ejecutables de cada bloque.
    
    public FrameParEjecutable(MyFrame myFrame, VectorOrdenado eventos, ContextoEjecucion contexto, AsincronosPendientes asincronos){
        super(myFrame,eventos,contexto,asincronos);
        subpasosBloques=limpiarSubpasosBloques();
        bloquesComponentesEjecutables=bloquesEjecutables();
    }
    
    //..........................................................................
    /**Devuelve un arreglo que contiene tantos enteros como bloques. Cada uno
     * de estos enteros representa el número de componente ejecutable de cada 
     * bloque que estamos ejecutando. Inicialmente valen 0.
     * @return
     */
    private int[] limpiarSubpasosBloques(){
        int[] retorno = new int[numBloques()];
        for (int i=0; i<retorno.length; i++)
            retorno[i]=0;
        return retorno;
    }    

    //..........................................................................
    @Override 
    public ResultadoEjecucion run(){
        return runStep();
    }
    
    //..........................................................................
    /** La ejecución de este bloque es especial. Vamos a ejecutar todos los com-
     *  ponentes ejecutables a la vez.
     */
    @Override
    public ResultadoEjecucion runStep(){
        switch (indiceEjecucion){
            case -1: return detectadoComienzo();                     
            case  0: myFrame.setCol(sdsimulator.Main.PENDIENTE);
            default: indiceEjecucion++;
                     return ejecutarTodos();
        }
    }
    
    //..........................................................................
    @Override
    protected ResultadoEjecucion detectadoComienzo(){
        ResultadoEjecucion retorno=new ResultadoEjecucion();
        
        retorno.x=getX();
        retorno.y=getY();
        
        myFrame.setCol(sdsimulator.Main.EN_CURSO);
        indiceEjecucion++;
                     
        retorno.traza = bundle.getString("FRAME");
        retorno.traza+= myFrame.getName();
        retorno.traza+= bundle.getString("FRAME1");
        retorno.traza+= myFrame.getID();
        retorno.traza+= bundle.getString("FRAME2");
        
        return retorno;
    }
    
    //¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨
    /**Devuelve true si todos los componentes ejecutables del frame están comple-
     * tamente ejecutados (sin tener en cuenta el bloque al que pertenecen).
     * @return
     */
    private boolean todosCompletados(){
        for (int i=0; i<componentesEjecutables.size(); i++)
            if (!((ComponenteEjecutable)componentesEjecutables.get(i)).completado())
                return false;
        
        return true;
    }
    
    //¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨
    /**Ejecuta a la vez un paso de un componente ejecutable de cada uno de los 
     * bloques que lo contienen. Por lo tanto, las coordenadas que ponemos son 
     * la mitad del frame par.
     * @return
     */
    private ResultadoEjecucion ejecutarTodos(){
        int numBloques = numBloques(); 
        ResultadoEjecucion retorno=new ResultadoEjecucion();
                  
        retorno.x = myFrame.getX();
        retorno.y =(myFrame.getY() + myFrame.getHeight()) / 2;
        
        if (todosCompletados()){
            for (int i=0; i<bloquesComponentesEjecutables.size();i++){
                //todosCompletado devolvía cierto cuando los últimos componentes
                //habían sido ejecutados. Por lo que al no entrar a ejecutarTodos
                //no se llamaba a su postrun. Cuando un bloque tenía más sentencias
                //que el resto, le pasaba sólo a su último componente. Cuando hay más
                //de un bloque con el mismo n´º de componentes, le pasaba a los últimos
                //de cada bloque. Ejecutaremos algún postrun de más, pero da igual, por-
                //que sólo cambia el color.
                Vector bloqueComponentes =(Vector)bloquesComponentesEjecutables.get(i);
                if (bloqueComponentes.size() > 0){ //en los bloques vacíos esto no es necesario
                    ComponenteEjecutable ultimo = (ComponenteEjecutable)bloqueComponentes.get(bloqueComponentes.size()-1);
                    ultimo.postRun();
                }
            }
            return super.detectadoFinal();
        }
  
        for (int i=0; i<numBloques; i++){
            Vector bloqueComponentes = (Vector) bloquesComponentesEjecutables.get(i);
            retorno.traza+=runBloqueComponentes(bloqueComponentes, i);
        }
        
        return retorno;
    }
    
    //¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨
    /**Ejecuta un paso del bloque que recibe como parámetro y devuelve el resul-
     * tado de esa ejecución como String. Cuando no queda nada que ejecutar en el 
     * bloque, devuelve la cadena vacía.
     * @param bloqueComponentes
     * @param numBloque
     * @return
     */
    private String runBloqueComponentes(Vector bloqueComponentes, int numBloque){
        String retorno="";
        String separador=calculaSeparador(numBloque);
        ComponenteEjecutable componenteEjecutable;
        int subpasoBloque = subpasosBloques[numBloque];
        
        if (subpasoBloque >= bloqueComponentes.size())
            return "";
           
        componenteEjecutable=(ComponenteEjecutable) bloqueComponentes.get(subpasoBloque);
               
        if (componenteEjecutable.completado()){
           componenteEjecutable.postRun(); 
           subpasosBloques[numBloque]=++subpasoBloque;
               
           if (subpasoBloque>=bloqueComponentes.size())
              return "";
           
           componenteEjecutable=(ComponenteEjecutable) bloqueComponentes.get(subpasoBloque);
        }
        
        ResultadoEjecucion aux = componenteEjecutable.run();
        retorno+= super.dentroDe(componenteEjecutable) + aux.traza + separador;
                
        asincronos.add(componenteEjecutable);//no se añadirá si no es un mensaje asíncrono.    
        
        return retorno;
    }
    //..........................................................................
    /** Si es el último bloque, no devuelve separador, porque no contiene sentencias.
     *  Si los bloques posteriores al bloque de entrada están terminados, no se de-
     *  vuelve separador.
     *  Es competencia del GlobalEjecutable colocar el último separador, ya que 
     *  en realidad corresponde al final del paso del frame (el resto de separa-
     *  dores los crea el frame porque uno de sus pasos, puede derivar en varios 
     *  subpasos internos.
     */
    private String calculaSeparador(int numBloque){
        if (numBloque==super.numBloques()-1)
           return "";
        
        else{
            boolean todosBloquesPosterioresTerminados=true;
            for (int i=numBloque+1; i<super.numBloques();i++){
                Vector bloqueComponentes =(Vector)bloquesComponentesEjecutables.get(i);
                for (int j=0; j<bloqueComponentes.size();j++){
                    ComponenteEjecutable componenteEjecutable=(ComponenteEjecutable)(bloqueComponentes.get(j));
                    if (!componenteEjecutable.completado())
                        todosBloquesPosterioresTerminados = false;
                }
            }
        
            if (!todosBloquesPosterioresTerminados)    
                return bundle.getString("SEPARADOR_EVENTOS");
            else
                return "";
        }
    }
    //¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨
    /**Deja el frame par listo para ejecutar de nuevo.
     */
    @Override 
    public void reset(){
        super.reset();
        subpasosBloques=limpiarSubpasosBloques();
    }
}
