// (c) MIT 2003.  All rights reserved.

package rec.fsm;

///////////////////////////////////////////////////////////////////////////////
//
// FILE:	NodeRemover.java
//
// AUTHOR:      Luke Weisman
//              luke@ai.mit.edu
//
// DATE:	June, 1998
//
// COPYRIGHT:	Massachusetts Institute of Technology
//		All rights reserved.
//
//
///////////////////////////////////////////////////////////////////////////////


import java.util.*;
import rec.util.*;
import rec.sys.*;
import rec.core.*;

public class NodeRemover extends Aligner
{

  public NodeRemover()
  {
  }


  public boolean recognize( Surface s, Widget w )
  {
    Node n = null;

    // somehow get the node to remove
    Widget ta = ( (WSelection)w ).getWidget();
    if ( ta instanceof rec.fsm.Node )
      n = (Node)ta;

    // if there was a node to remove, do so
    if ( n != null )
      {
	s.removeWidget( w );

	removeNode( s, n );

	return true;
      }

    // we did nothing.
    return false;
  }


  
  public static void removeNode( Surface surf, Node n )
  {
    // get a handle on all edges incident on node
    Vector edges = n.getEdges();
    Vector in = new Vector();
    Vector out = new Vector();
    
    String mid = makeMid( n );

    // find incoming and outgoing edges and stash them.
    Iterator e = edges.iterator();
    while( e.hasNext() )
      {
	Edge ed = (Edge)e.next();

	if ( ed.full() )
	  {
	    if ( ed.getNode( true ).equals( ed.getNode(false) ) )
	      continue;
	    
	    if ( ed.isHead(n) )
	      {
		if ( ed.hasArrowhead( true ) )
		  in.addElement( ed );
		if ( ed.hasArrowhead( false ) )
		  out.addElement( ed );
	      }
	    else 
	      {
		if ( ed.hasArrowhead( false ) )
		  in.addElement( ed );
		if ( ed.hasArrowhead( true ) )
		  out.addElement( ed );
	      }
	  }
      }

    // connect up edges which went through node.
    int s_in = in.size();
    int s_out = out.size();
    for ( int i = 0; i < s_in; i++ )
      {
	for ( int j = 0; j < s_out; j++ )
	  {
	    // we have edge i hitting node and edge j leaving 
	    // (no sense of directionality)
	    Edge e1 = (Edge)in.elementAt( i );
	    Edge e2 = (Edge)out.elementAt( j );

	    // if for an edge, n is the head, then the other node is the tail
	    Node n1 = (e1.isHead(n)) ? e1.getNode(false) : e1.getNode( true );
	    Node n2 = (e2.isHead(n)) ? e2.getNode(false) : e2.getNode( true );
	    
	    // so if there is no edge going from from(i) to to(j)
	    // make one!
	    Assert.check( n2 != null, "n2 == null: " + e2 );

	    Edge ed = null;

	    if ( !n1.equals( n2 ) )
	      ed = new Edge( n1, n2, surf );
	    else
	      ed = new Edge( n1, surf );
	      
	    ed.setName( fixName( e1.getName(), mid, e2.getName() ) );

	    surf.addWidget( ed, true );

	    ed.addArrowhead( false );
	  }
      }

    int s = edges.size();
    for ( int i = 0; i < s; i++ )
      {
	//Console.writeln( "Removing " +  edges.elementAt( i ) );
	surf.removeWidget( (Edge)edges.elementAt( i ) );
      }

    // remove the node, all the edges will freak out, etc.
    // this is okay.
    surf.removeWidget( n );

  }



  public static String makeMid( Node n )
  {
    String s = null;
    Iterator e = n.getEdgesTo( n ).iterator();
    while ( e.hasNext() )
      {
	Edge ed = (Edge)e.next();
	String edn = ed.getName();
	if ( s != null )
	  s += " | " + edn;
	else
	  s = edn;
      }
    
    if ( s != null )
      s = "(" + s + ")*";
    
    return s;
  }

  public static String fixName( String in, String mid, String out )
  {
    if ( in.indexOf( ' ' ) != -1 )
      in = "(" + in + ")";
    if ( out.indexOf( ' ' ) != -1 )
      out = "(" + out + ")";

    if ( mid == null )
      mid = "";

    return in + mid + out;
  }





  public Iterator getInputTypes()
  {
    Vector v = new Vector();

    v.addElement( "rec.core.WSelection" );

    return( v.iterator() );
  }

  public Iterator getOutputTypes()
  {
    Vector v = new Vector();
    v.addElement( "rec.fsm.Node" );

    return v.iterator();
  }
  
}


