package cl.jtv;


//Title:        Proyecto Turing Visual

//Version:

//Copyright:    Copyright (c) 1998

//Author:       Marco Antonio Mora Godoy

//Company:      Your Company

//Description:  No admires, CREA!!!!...
import java.awt.*;
import java.awt.geom.Rectangle2D;
//import java.awt.geom.Line2D.*;
import java.awt.font.FontRenderContext;
import java.util.Enumeration;
import java.util.Vector;
import java.util.*;
import javax.swing.JScrollPane;


class Enlace extends Maquina {

  int x1,y1;
  public CondicionEnlace condicionEnlace;
  private java.util.Vector puntos,rectas;
  private Point p0,p1;
  protected Arrow arrow;
  private int w0,h0,w1,h1;
  
  static final Font FONT_TRI10 =  new Font("TIMESROMAN",Font.ITALIC,10);
  
  public static final int COORD_N=0;
  public static final int COORD_S=1;
  public static final int COORD_E=2;
  public static final int COORD_W=3;
  public static final int COORD_NE=4;
  public static final int COORD_NW=5;
  public static final int COORD_SE=6;
  public static final int COORD_SW=7;
  
  public Enlace(int x, int y) {
    super(x,y,0,null,null);
    condicionEnlace = new CondicionEnlace();
    arrow = new Arrow();
    this.puntos = new java.util.Vector();
    //setExtremos();
    this.setIconValue(JTV.MyRenderer.ICONO_ENLACE);
  }
  
  public Enlace(int x, int y, Cinta cin, Maquina prev, Maquina prox) {
    super(x,y,cin,prev,prox);
    condicionEnlace = new CondicionEnlace();
    arrow = new Arrow();
    setExtremos();
    this.setIconValue(JTV.MyRenderer.ICONO_ENLACE);
  }
  
  public Enlace(int x, int y, Cinta cin, Maquina prev, Maquina prox,String _nombre) {
    super(x,y,cin,prev,prox);
    condicionEnlace = new CondicionEnlace();
    arrow = new Arrow();
    p0 = new Point();
    p1 = new Point();
    setExtremos();
    this.setIconValue(JTV.MyRenderer.ICONO_RAMA);
  }

  public Enlace(int x, int y, int _indiceCinta, Maquina prev, Maquina prox) {
    super(x,y,_indiceCinta,prev,prox);
    condicionEnlace = new CondicionEnlace();
    arrow = new Arrow();
    p0 = new Point();
    p1 = new Point();
    this.puntos = new java.util.Vector();
    setExtremos();
    this.setIconValue(JTV.MyRenderer.ICONO_RAMA);
  }
  
  public void setPoints(){
      p0 = new Point();
      p1 = new Point();
      setExtremos();
  }

  public void setExtremos(){
      Rectangle2D rect1 = previa.getBounds();
      Rectangle2D rect2 = proxima.getBounds();
      
      //rect1 = Maquina.FONT_TRI25.getStringBounds(previa.getNombre(),new FontRenderContext(Maquina.FONT_TRI25.getTransform(),true,true));
      //rect2 = Maquina.FONT_TRI25.getStringBounds(proxima.getNombre(),new FontRenderContext(Maquina.FONT_TRI25.getTransform(),true,true));
      
      w0 = (int)rect1.getWidth();
      h0 = (int)rect1.getHeight();
      
      w1 = (int)rect2.getWidth();
      h1 = (int)rect2.getHeight();
      
      if(puntos.isEmpty()){
            //x0 = previa.x0;//+(int)rect1.getWidth();
            //y0 = previa.y0;//-(int)rect1.getHeight()/2+3;
            //x1 = proxima.x0;
            //y1 = proxima.y0;//-(int)rect2.getHeight()/2+3;
            
            /*x0 = previa.x0+(int)rect1.getWidth()/2;
            y0 = previa.y0-(int)rect1.getHeight()/2;
            x1 = proxima.x0+(int)rect2.getWidth()/2;;
            y1 = proxima.y0-(int)rect2.getHeight()/2;*/
            
            //p0.move(x0,y0);
            //p1.move(x1,y1);
            Point puntos[] = getCoord2(w0,h0,w1,h1,previa.x0,previa.y0,proxima.x0,proxima.y0);
            
            p0 = puntos[0];
            p1 = puntos[1];
      }
      else{
            Object[] arrayPuntos = puntos.toArray();
            
            Point pi = (Point) arrayPuntos[0];
            Point pf = (Point) arrayPuntos[arrayPuntos.length-1];
            p0 = getCoord(h0,w0,previa.x0,previa.y0,(int)pi.getX(),(int)pi.getY());
            p1 = getCoord(h1,w1,proxima.x0,proxima.y0,(int)pf.getX(),(int)pf.getY());
      }
       
      //this.agregaPunto((int)p0.getX(),(int)p0.getY()); //added
      //this.agregaPunto((int)p1.getX(),(int)p1.getY()); //added
  }
      
       
  public void accion(){

  
        return;
  }

  public void accion(Cinta _cinta){

  
      return;

      //super.accion();
  }

  public void mover(int dx, int dy){
      
    if(!this.esCiclico()) return;
    
    condicionEnlace.x0+=dx;
    condicionEnlace.y0+=dy;
    
    Object[] arrayPuntos = puntos.toArray();
    for(int i=0;i<arrayPuntos.length;i++)
        ((Point)arrayPuntos[i]).setLocation((int)((Point)arrayPuntos[i]).getX()+dx,(int)((Point)arrayPuntos[i]).getY()+dy);
    
  }
  
  public void moverPrevia(int dx, int dy){

    return;
  }
  
  public void moverProxima(int dx, int dy){

    return;

  }
  
   public void moveRewind(){
     return;
  }
  
   public void moveForward(){
     return;
  }
  
   public void moveForward2(){
     return;
  }
  
  public void deleteMachine(java.util.Vector repository){
                 
      ((EnlaceCompuesto)this.previa.proxima).eliminar(this);
      if(((EnlaceCompuesto)this.previa.proxima).getSize()==0) this.previa.proxima=null;
      repository.remove(this);
  }

  
  
  public void dibujar(Graphics g){
      
    if(Maquina.selectedMachine!=null && this==Maquina.selectedMachine)
        g.setColor(Color.magenta);
    else if(JTV.searchedMachine!=null && this==JTV.searchedMachine)
        g.setColor(Color.pink);
    else if(Maquina.playMachine!=null && this==Maquina.playMachine)
        g.setColor(Color.red);
    else
        g.setColor(Color.black);

    g.setFont(Enlace.FONT_TRI10);

    setExtremos();
    
    if(puntos.isEmpty()){
        
        //g.drawLine(x0,y0,x1,y1);
        //arrow.drawArrow(g,x0,y0,x1,y1);
        g.drawLine((int)p0.getX(),(int)p0.getY(),(int)p1.getX(),(int)p1.getY());
        arrow.drawArrow(g,(int)p0.getX(),(int)p0.getY(),(int)p1.getX(),(int)p1.getY());
        int x0 = (int)p0.getX();
        int y0 = (int)p0.getY();
        int x1 = (int)p1.getX();
        int y1 = (int)p1.getY();
        condicionEnlace.setOperandos();
        Rectangle2D rect = Enlace.FONT_TRI10.getStringBounds(condicionEnlace.getOperandos(),new FontRenderContext(Enlace.FONT_TRI10.getTransform(),true,true));
        double sin=Math.abs(y0-y1)/Math.sqrt(Math.pow(y1-y0,2)+Math.pow(x1-x0,2));
        condicionEnlace.x0 = (x0+x1)/2+3*(int)sin-(int)(rect.getWidth()*(1-sin)/2);
        condicionEnlace.y0 = (y0+y1)/2;
        condicionEnlace.dibujar(g);
        
        
        
    }
    else{
        Point auxPoint0,auxPoint1;
        auxPoint0=p0;
        Enumeration en = puntos.elements();
        while(en.hasMoreElements()){
            auxPoint1 = (Point) en.nextElement();
            if(JTV.estadoJTV==JTV.ESTADO_PUNTERO && !Maquina.running)
                g.fillRect((int)(auxPoint1.getX()-2.5),(int)(auxPoint1.getY()-2.5),5,5);
            
            g.drawLine((int)auxPoint0.getX(),(int)auxPoint0.getY(),(int)auxPoint1.getX(),(int)auxPoint1.getY());
            auxPoint0 = auxPoint1;  
        }
       
        
        g.drawLine((int)auxPoint0.getX(),(int)auxPoint0.getY(),(int)p1.getX(),(int)p1.getY());
        arrow.drawArrow(g,(int)auxPoint0.getX(),(int)auxPoint0.getY(),(int)p1.getX(),(int)p1.getY());
        int x0_ = (int)auxPoint0.getX();
        int y0_ = (int)auxPoint0.getY();
        int x1_ = (int)p1.getX();
        int y1_ = (int)p1.getY();
    
        //g.setFont(Maquina.FONT_TRP13);
        //g.drawString("(" + (getIndiceCinta()+1) + ")",(x0_+x1)/2,(y0_+y1)/2);
        condicionEnlace.setOperandos();
        Rectangle2D rect = Enlace.FONT_TRI10.getStringBounds(condicionEnlace.getOperandos(),new FontRenderContext(Enlace.FONT_TRI10.getTransform(),true,true));
        /*double sin=Math.abs(y0_-y1)/Math.sqrt(Math.pow(y1-y0_,2)+Math.pow(x1-x0_,2));
        condicionEnlace.x0 = (x0_+x1)/2+7*(int)sin-(int)(rect.getWidth()*(1-sin)/2);
        condicionEnlace.y0 = (y0_+y1)/2;*/
        double sin=Math.abs(y0_-y1_)/Math.sqrt(Math.pow(y1_-y0_,2)+Math.pow(x1_-x0_,2));
        condicionEnlace.x0 = (x0_+x1_)/2+7*(int)sin-(int)(rect.getWidth()*(1-sin)/2);
        condicionEnlace.y0 = (y0_+y1_)/2;
        condicionEnlace.dibujar(g);   
    }  
        if(!esCiclico()) super.dibujar(g);
  }
  
  
  public boolean accion(Cinta[] _arrayOfTapes,DiccionarioMetavalores dicMetavalores){
      
      Enumeration en = this.condicionEnlace.operandosIzquierdo.keys();
      try{
        while(en.hasMoreElements()){
            Integer indexCinta = (Integer)en.nextElement();
            Simbolo simbolo = _arrayOfTapes[indexCinta.intValue()].leer();
            condicionEnlace.asignar(simbolo,indexCinta,dicMetavalores);
        }
        return true;
      }
      catch(Exception ex){
          return false;
      }
    
  }

  
  public ResultadoEvaluacion evaluarCondicion(Cinta[] arrayOfTapes,DiccionarioMetavalores dicMetavalores) throws NonSetException{
      
      return this.condicionEnlace.evaluar(arrayOfTapes,dicMetavalores);
        
  }
  
   public int getMaxIndiceCinta(){
             
        Set en = null;
        Enumeration en2 = null;
        if(this.condicionEnlace.operandosDerecho.size()>this.condicionEnlace.operandosIzquierdo.size()){
            en = this.condicionEnlace.operandosDerecho.keySet();
            en2 = this.condicionEnlace.operandosIzquierdo.keys();
        }
        else{
            en = this.condicionEnlace.operandosIzquierdo.keySet();
            en2 = this.condicionEnlace.operandosDerecho.keys();
        }
        
        java.util.List list = new java.util.ArrayList(en);
        while(en2.hasMoreElements()){
            Object obj = en2.nextElement();
            if(!list.contains(obj)) list.add(obj);
        }
        if(list.size()==0) 
            return 0;
        else
            return ((Integer)list.get(list.size()-1)).intValue();       
    }
  
  
  public boolean esCiclico(){
      
      Maquina auxMaquina = this.previa;
      
      while(auxMaquina!=null){ // || !(auxMaquina instanceof Enlace)){
            if(auxMaquina instanceof Enlace) return false;
            if(auxMaquina==this.proxima) return true;
            auxMaquina = auxMaquina.previa;
      } 
      
      
      return false;
      
  }
  
  public void agregaPunto(int x,int y){
  
    //if(puntos.size()<2) //added
        puntos.add(new java.awt.Point(x,y));
    //else //added
        //puntos.add(puntos.size()-1,new java.awt.Point(x,y)); //added
      
  }
  
  
  private static double L1(int h,int w,int x0,int y0,int xi){
      
      return h*xi/w+y0-h/2-(h/w)*(x0+w/2);
      
  }
  
   private static double L2(int h,int w,int x0,int y0,int xi){
      
      return -h*xi/w+y0-h/2+(h/w)*(x0+w/2);
      
  }
  
  
  private static Point getCoord(int h,int w,int x0,int y0,int xi,int yi){
      
      double L1 = Enlace.L1(h,w,x0,y0,xi);
      double L2 = Enlace.L2(h,w,x0,y0,xi);
      
        if(L1>yi && L2>yi)                  //NORTE   
        {   
            //System.out.println("N");
            return new Point(x0+w/2,y0-h+10);
        } 
        else if(L1<yi && L2<yi)             //SUR
        {
            //System.out.println("S"); 
            return new Point(x0+w/2,y0);
        }
        else if(L1>yi && L2<yi)             //ESTE
        {
            //System.out.println("E"); 
            return new Point(x0+w,y0-h/2);
        }
        else if(L1<yi && L2>yi)             //OESTE
        {
            //System.out.println("O"); 
            return new Point(x0,y0-h/2);
        }      
        else if(L1==yi && L2>yi)            //NW
        {
            //System.out.println("NW"); 
            return new Point(x0,y0-h);
        }
        else if(L2==yi && L1>yi)            //NE
        {
            //System.out.println("NE");  
            return new Point(x0+w,y0-h);
        }
        else if(L1==yi && L2<yi)            //SE
        {
            //System.out.println("SE"); 
            return new Point(x0,y0+w);
        }
        else if(L2==yi && L1<yi)            //SW
        {
            //System.out.println("SW"); 
            return new Point(x0,y0);
        }
      
        return new Point();
  } 
  
  public static Point[] getCoord2(int w0,int h0,int w1,int h1,int x0,int y0,int x1,int y1){
      
      Point[] p0 = new Point[4];
      p0[0] = new Point(x0+w0/2,y0-h0+10);   //N
      p0[1] = new Point(x0+w0/2,y0);      //S
      p0[2] = new Point(x0+w0,y0-h0/2);   //E
      p0[3] = new Point(x0,y0-h0/2);      //W
      
      Point[] p1 = new Point[4];
      p1[0] = new Point(x1+w1/2,y1-h1+10);   //N
      p1[1] = new Point(x1+w1/2,y1);      //S
      p1[2] = new Point(x1+w1,y1-h1/2);   //E
      p1[3] = new Point(x1,y1-h1/2);      //W
      
      Hashtable medidas = new Hashtable();
      for(int i=0;i<4;i++)
          for(int j=0;j<4;j++){
              Point[] puntos = new Point[2];
              puntos[0] = p0[i];
              puntos[1] = p1[j];
              medidas.put(new Double(Point.distance(p0[i].getX(),p0[i].getY(),p1[j].getX(),p1[j].getY())),puntos);
          }
        
      
      java.util.List list = new java.util.ArrayList(medidas.keySet());
      java.util.Collections.sort(list);      
      
      return (Point[])medidas.get(list.get(0));      
  }
  
  /*public char getCharTrue(Cinta[] _arrayOfTapes){
        
      return this.condicionEnlace.isEmpty()?0:_arrayOfTapes[this.getIndiceCinta()].leer();
      
  }*/
  
  
  public boolean isMouseClicked(int x,int y){
      
        Object[] puntos = this.puntos.toArray();
        
        if(puntos.length==0 && (new java.awt.geom.Line2D.Double(p0,p1)).intersects(x,y,3,3)) return true;
        
        if(puntos.length!=0){
            if((new java.awt.geom.Line2D.Double(p0,(Point)puntos[0])).intersects(x,y,3,3)) return true;
            if((new java.awt.geom.Line2D.Double((Point)puntos[puntos.length-1],p1)).intersects(x,y,3,3)) return true;
        
            for(int i=0;i<puntos.length-1;i++)
                if((new java.awt.geom.Line2D.Double((Point)puntos[i],(Point)puntos[i+1])).intersects(x,y,3,3)) return true;  
        }
        
        return false;
      
  }
  
  public Point getNearestPoint(int x,int y){
      
      if(puntos.size()==0) return null;
      
      Enumeration en = puntos.elements();
      while(en.hasMoreElements()){
           Point punto = (Point)en.nextElement();
           if(Math.sqrt(Math.pow(punto.getX()-x,2.0)+Math.pow(punto.getY()-y,2.0))<5) return punto;
      }
      
      return null;
       
  }
  
  public void updateBounds(){
      
      return;
      
  }
  
   public boolean esEnlazable(){
        
            return false;
    }
    
    public int showDialog(int numOfTapes,boolean addComando){
        
        DialogEnlace dv = new DialogEnlace(new javax.swing.JFrame (), true,numOfTapes,this,addComando);
        dv.setSize(400,400);
        dv.setVisible(true);
        
        return dv.getReturnStatus();
    }
    
    
    public String getXML() {
        
      String xml = "";
      xml+="<enlace \n";
      xml+="    id=\""+this.idMaquina+"\"\n";
      xml+="    id-previa=\""+this.previa.idMaquina+"\"\n";
      xml+="    id-proxima=\""+this.proxima.idMaquina+"\"\n";
      
      if(this.condicionEnlace.operandosDerecho.size()==0 && this.condicionEnlace.operandosIzquierdo.size()==0 ){
          if(this.puntos.size()==0){
                xml+="/>\n\n";
                return xml;
          }
          xml+=">\n\n";
          Enumeration en = this.puntos.elements();
          while(en.hasMoreElements()){
                Point punto = (Point)en.nextElement();
                xml+="     <punto x=\""+(int)punto.getX()+"\" y=\""+(int)punto.getY()+"\"/>\n";
          }
          xml+="</enlace>\n";
          return xml;
      }
      xml+=">\n\n";
      
      Enumeration en = this.condicionEnlace.operandosDerecho.keys();
      
      while(en.hasMoreElements()){
            Integer indexCinta = (Integer)en.nextElement();
            Vector operandosDerecho = (Vector)this.condicionEnlace.operandosDerecho.get(indexCinta);
            xml+="    <condicion cinta=\""+indexCinta+"\" not=\""+((Boolean)this.condicionEnlace.operandosNots.get(indexCinta)).toString()+"\"";
            if(this.condicionEnlace.operandosIzquierdo.containsKey(indexCinta)){
                String operandoIzquierdo = (String)this.condicionEnlace.operandosIzquierdo.get(indexCinta);
                xml+=" operando-izquierdo=\""+Hellada.symbol2XML(operandoIzquierdo)+"\"";
            }
            
            if(operandosDerecho.size()==0){
                 xml+="/>\n";
                 continue;
            }
            xml+=">\n";
            Enumeration en2 = operandosDerecho.elements();
            while(en2.hasMoreElements()){
                String operandoDerecho = (String)en2.nextElement();
                xml+="          <operando-derecho nombre=\""+Hellada.symbol2XML(operandoDerecho)+"\"/>\n";
            }
            xml+="     </condicion>\n";
      }
      
      en = null;
      en = this.condicionEnlace.operandosIzquierdo.keys();
      
      while(en.hasMoreElements()){
            Integer indexCinta = (Integer)en.nextElement();
            if(this.condicionEnlace.operandosDerecho.containsKey(indexCinta)) continue;
            String operandoIzquierdo = (String)this.condicionEnlace.operandosIzquierdo.get(indexCinta);
            xml+="     <condicion cinta=\""+indexCinta+"\" not=\""+((Boolean)this.condicionEnlace.operandosNots.get(indexCinta)).toString()+"\"";
            xml+=" operando-izquierdo=\""+Hellada.symbol2XML(operandoIzquierdo)+"\"/>\n"; 
      }
      
      en = null;
      en = this.puntos.elements();
      while(en.hasMoreElements()){
            Point punto = (Point)en.nextElement();
            xml+="     <punto x=\""+(int)punto.getX()+"\" y=\""+(int)punto.getY()+"\"/>\n";
      }
      
      xml+="</enlace>\n";
      
      return xml;
  
    }  
    
     public void setScrollBars(JScrollPane scrollPane){
        
        /*int h = scrollPane.getHorizontalScrollBar().getModel().getValue();
        int v = scrollPane.getVerticalScrollBar().getModel().getValue();
        Rectangle rect = scrollPane.getViewportBorderBounds();
        rect.setLocation(h,v);*/
        
        
        this.proxima.setScrollBars(scrollPane);
        /*int x0 = this.proxima.x0;
        int y0 = this.proxima.y0;
        if(!(rect.getMinX()<=x0&&x0<=rect.getMaxX()&&rect.getMinY()<=y0&&y0<=rect.getMaxY())){
            scrollPane.getHorizontalScrollBar().getModel().setValue(x0);
            scrollPane.getVerticalScrollBar().getModel().setValue(y0-(int)Maquina.RECT_INICIAL.getHeight());            
        }*/
    }
  
    /** Getter for property puntos.
     * @return Value of property puntos.
     */
    public java.util.Vector getPuntos() {
        return puntos;
    }
    
    /** Setter for property puntos.
     * @param puntos New value of property puntos.
     */
    public void setPuntos(java.util.Vector puntos) {
        this.puntos = puntos;
    }
    
    public String getLatex(int maxCintas){
      
       return "";
    }
    
    
    public void reemplazaParametro(Hashtable parametros) throws NonSetException{
        
        Enumeration en = condicionEnlace.operandosDerecho.elements();
        while(en.hasMoreElements()){
            Vector operandos = (Vector) en.nextElement();
            Enumeration en2 = operandos.elements();
            if(en2.hasMoreElements()){
                String operando = (String)en2.nextElement();
                if(parametros.containsKey(operando)){
                    Parametro parametro = (Parametro) parametros.get(operando);
                    if(parametro.isSet()){
                        operandos.remove(operando);
                        try{
                            operandos.add(parametro.getNombre());
                        }
                        catch(Exception ex){
                            ex.printStackTrace();
                        }
                    }
                    else
                        throw new NonSetException();
                }
            }           
        }       
    }
    
}