package cl.jtv;
/*
 * JTV_SOC.java
 *
 * Created on 1 de mayo de 2003, 06:51 PM
 */

/**
 *
 * @author  Administrador
 * @version 
 */
import java.io.*;
import java.util.*;

public class JTV_SOC {
    
    public static Integer HALT_STATE = new Integer(Integer.MAX_VALUE);
    public static Integer COLGADA_STATE = new Integer(Integer.MIN_VALUE);
    public static int MAX_CICLOS = 40;
    /** Creates new JTV_SOC */
    public class Condicion{
        
        public Integer state;
        public Vector condiciones;
        public Accion accion;
        public Condicion(String condicion){
            
            StringTokenizer st = new StringTokenizer(condicion,":");
            String stringState = st.nextToken();
            if(stringState.equals("h"))
                state = JTV_SOC.HALT_STATE;
            else
                state = new Integer(stringState);
            String conds = st.nextToken();
            st = null;
            st = new StringTokenizer(conds,",");
            condiciones = new Vector();
            while(st.hasMoreTokens()){
                condiciones.add(st.nextToken());
            }
            st = null;
            accion = accion;
        }
        
        public boolean evaluar(Vector cintas){
            
            for(int i=0;i<condiciones.size();i++){
                if(condiciones.get(i).equals("*")) 
                    continue;
                else if(!condiciones.get(i).equals(((Tape)cintas.get(i)).leer()))
                    return false;                
            }
            
            return true;
            
        }
    }
    
    
    public class Accion{
        
        public Integer state;
        public Vector acciones;
        
        public Accion(String accion){
            
            StringTokenizer st = new StringTokenizer(accion,":");
            String stringState = st.nextToken();
            if(stringState.equals("h"))
                state = JTV_SOC.HALT_STATE;
            else
                state = new Integer(stringState);
            String conds = st.nextToken();
            st = null;
            st = new StringTokenizer(conds,",");
            acciones = new Vector();
            while(st.hasMoreTokens()){
                acciones.add(st.nextToken());
            }
            st = null;
        }
        
        public Integer accion(Vector cintas){
            
            for(int i=0;i<acciones.size();i++){
                if(!((Tape)cintas.get(i)).accion((String)acciones.get(i)))
                    return JTV_SOC.COLGADA_STATE;                
            }
            return state;            
        }
        
    }
    
    public class Tape{
        
        
        public String contenido;
        public int indice,numero;
        
        public Tape(int newNumero,String newContenido){
            contenido = new String(newContenido);
            indice = contenido.length()+1;
            numero = newNumero;
            contenido = "#"+contenido+"#";
            //contenido+="#";
        }
        
        public Tape(int newNumero){
            contenido = "#";
            indice = 0;
            numero = newNumero;
        }
        
        
        public boolean accion(String accion){
            
            if(accion.equals("R")){
                indice++;
                if(indice>contenido.length()-1) contenido+="#";
            }
            else if(accion.equals("L"))
                indice--;
            else if(!accion.equals("*")){               
                char[] arreglo = contenido.toCharArray();
                arreglo[indice] = accion.charAt(0);
                contenido = new String(arreglo);
            }
            return indice>=0;
        }
        
        public String leer(){
            
            return contenido.charAt(indice)+"";
            
        }
        
        
        public void print(){
                        
            System.out.println(numero+":"+contenido);
            System.out.print("  ");
            for(int i=0;i<indice;i++) System.out.print(" ");
            System.out.println("-");
            
        }
                       
    }
    
    
    public JTV_SOC(String args[]) {
        
        /*int numero = 1;
        String texto = "hola";
        Tape tape = new Tape(numero,texto);
        tape.accion("R");
        tape.accion("R");
        tape.accion("R");
        tape.accion("R");
        tape.accion("w");
        tape.accion("*");
        tape.accion("L");
        tape.accion("L");
        tape.print();
        
        if(true) return;*/
        
        try{
            //System.out.println("Leyendo Tabla Delta...");
            File file = new File(args[0]);         
            //DataInputStream dis = new DataInputStream(new FileInputStream(file));
            java.io.BufferedReader br = new java.io.BufferedReader(new java.io.FileReader(file));
            String data = "";
            String linea = null;
            //while((linea = dis.readLine())!=null) data+=linea+"\n";
            while((linea = br.readLine())!=null) data+=linea+"\n";
            
            Integer state = null,startState=null;
            int numeroCintas=0;
            StringTokenizer st = new StringTokenizer(data,"@");
            int counter=0;
            Hashtable tablaDelta = new Hashtable();
            while(st.hasMoreElements()){
                linea = ((String)st.nextElement()).trim();
                
                if(counter==0)
                    numeroCintas = Integer.parseInt(linea);
                else if(counter==1)
                    startState = new Integer(linea);
                else{
                    StringTokenizer st2 = new StringTokenizer(linea,"=");
                    Condicion condicion = new Condicion(st2.nextToken());
                    condicion.accion = new Accion(st2.nextToken());
                    if(!tablaDelta.containsKey(condicion.state)){
                        Vector vector = new Vector();
                        vector.add(condicion);
                        tablaDelta.put(condicion.state,vector);
                    }
                    else{
                        Vector vector = (Vector) tablaDelta.get(condicion.state);
                        vector.add(condicion);                       
                    }
                    
                }
                counter++;
            }
            
            
            //System.out.println("Inicializando Cintas...");
            Vector cintas = new Vector();
            for(int i=1;i<=numeroCintas;i++){
                if(i<args.length)
                    cintas.add(new Tape(i,args[i]));
                else
                    cintas.add(new Tape(i));
            }
            System.out.println("Entrada:");
            for(int i=0;i<cintas.size();i++){
                ((Tape)cintas.get(i)).print();
            }
            System.out.println("Ejecutando MT...");
            state = startState;
            
            int ciclos = 0;
            Vector vectorCondicionesVerdaderas = new Vector();
            while(!state.equals(JTV_SOC.COLGADA_STATE) && !state.equals(JTV_SOC.HALT_STATE)){
                //System.out.println("CICLO");
                Vector vectorDelta = (Vector) tablaDelta.get(state);
                Enumeration en = vectorDelta.elements();
                while(en.hasMoreElements()){
                    Condicion condicion = (Condicion) en.nextElement();
                    if(condicion.evaluar(cintas)){
                        vectorCondicionesVerdaderas.add(condicion);
                        //state = condicion.accion.accion(cintas);
                        //break;                        
                    }                   
                }
                int condicionesVerdaderas = vectorCondicionesVerdaderas.size();
                if(condicionesVerdaderas==0){
                    System.out.println("ERROR EN LA EJECUCION: ESTADO NO ENCONTRADO!!!");
                    return;
                }
                else if(condicionesVerdaderas==1){
                    Condicion condicion = (Condicion)vectorCondicionesVerdaderas.get(0);
                    state = condicion.accion.accion(cintas);
                    vectorCondicionesVerdaderas.removeAllElements();
                }
                else if(condicionesVerdaderas>1){
                    System.out.println("Se produjo ND");
                        System.out.print("Existen "+condicionesVerdaderas+" configuraciones diferentes. Elija una:");
                    while(true){                       
                        int input = 0;
                        Vector vectorInput = new Vector();
                        //String strInput = "";
                        while((input=System.in.read())!='\n'){
                            vectorInput.add(input+"");
                            //strInput+=(""+(input-'0'));
                        }
                        //System.out.println(strInput);
                        String strInput = (String) vectorInput.get(0);
                        vectorInput.removeAllElements();
                        int intInput = 0;
                        try{
                            intInput = Integer.parseInt(strInput);
                            intInput-='0';
                        }
                        catch(NumberFormatException ex){
                            System.out.println("Debe ingresar un número entre 1 y "+condicionesVerdaderas);
                        }
                        if(1<=intInput && intInput<=condicionesVerdaderas){
                            Condicion condicion = (Condicion)vectorCondicionesVerdaderas.get(intInput-1);
                            state = condicion.accion.accion(cintas);
                            vectorCondicionesVerdaderas.removeAllElements();
                            for(int i=0;i<cintas.size();i++){
                                ((Tape)cintas.get(i)).print();
                            }
                            break;
                        }
                        else{
                            //System.out.println("intInput="+intInput);
                            System.out.println("Debe ingresar un número entre 1 y "+condicionesVerdaderas);
                        }
                    }
                    /*int indiceSeleccion = 1;
                    Condicion condicion = (Condicion)vectorCondicionesVerdaderas.get(indiceSeleccion);
                    state = condicion.accion.accion(cintas);
                    vectorCondicionesVerdaderas.removeAllElements();*/
                }
                ciclos++;
                if(ciclos==JTV_SOC.MAX_CICLOS){                          
                    for(int i=0;i<cintas.size();i++){
                        ((Tape)cintas.get(i)).print();
                    }
                    System.out.print("Sigue?(s/n):");
                    int input = System.in.read();
                    //System.out.println("input="+input);
                    boolean breakLoop = false;
                    while((input=System.in.read())!='\n'){
                        
                        //if(input!='S' && input!='s'){
                        if(input=='N' || input=='n'){
                            breakLoop = true;
                            //break;
                        }
                        else
                            ciclos = 0;
                        //break;
                    }
                    if(breakLoop){
                        System.out.println("Ejecución Suspendida...");                        
                        break;
                    }
                }
            }
            
            if(state==JTV_SOC.COLGADA_STATE){
                System.out.println("MAQUINA COLGADA!!!");
                return;
            }
            for(int i=0;i<cintas.size();i++){
                ((Tape)cintas.get(i)).print();
            }
            
        }
        catch(Exception ex){
            ex.printStackTrace();
        }
        
    }
    

    /**
    * @param args the command line arguments
    */
    public static void main (String args[]) {
        
        JTV_SOC jtvSOC = new JTV_SOC(args);
        
        
    }
    
    

}
