
/*
 * Canvas.java
 *
 * Created on April 18, 2001, 1:24 AM
 */
package cse605;
/**
 *
 * @author  adev
 * @version 
 */
import java.io.*;
import java.util.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.font.*;

public class Canvas extends JPanel implements MouseListener, MouseMotionListener, ActionListener, Cloneable, Serializable{
    /** Creates new Canvas */
    public static final int CREATE_RESISTOR = 1001;
    public static final int CREATE_BATTERY = 1002;
    public static final int CREATE_WIRE = 1003;
    public static final int SERIES_RESISTOR = 1004;
    public static final int PARALLEL_RESISTOR = 1005;
    public static final int DELETE = 1006;
    public static final int MOVE = 1007;
    public static final int DO_NOTHING = 0;
    private boolean moveActivated = false;
    private boolean centerSelected = false;
    private boolean isDragged = false;
    private static int count = 0;
    private static int delay, blinks;
    private static int totalDelay;
    private static javax.swing.Timer timer, timer1, timer2, timer3, timer4, timer5, timer6, timer7, timer8, timer9, timer10, timer11;
    public LinkedList adjMatrix = new LinkedList();
    public int task;
    private Memento myMemento; 
    public boolean compiled = false;
    private LinkedList[] compList ;
    public boolean flowVisible = false;
    public boolean isPrinting = false;
    private JScrollPane container;
    private boolean isAllSelected=false;
    private boolean areaChanged;
    public Rectangle area;
    private CobUI parent ;
    private Rectangle selectRect;
    private int selectRect_X, selectRect_Y;
    private JTextArea c2TextArea ;
    public Canvas(Memento mmto, Color bgColor, CobUI par) {
        myMemento = mmto;
        parent = par;
        task = DO_NOTHING;
        setLayout(new BorderLayout());
        setBackground(bgColor);
        addMouseListener(this);
        addMouseMotionListener(this);
        area = new Rectangle(0,0);
	clearAll();        
    }
    
    public void changeBgColor(Color c){
        setBackground(c);        
    }

    public void setMemento(Memento mem)
    {
        myMemento = mem;
    }

    public void mouseClicked(MouseEvent evt) {
       if(task==CREATE_RESISTOR) createResistor(evt.getX(),evt.getY());
       else if(task==CREATE_BATTERY) createBattery(evt.getX(),evt.getY());
       else if(task== MOVE){ 
           task=DO_NOTHING; 
	   clearSelection(); 
	   storeCurrentState();
	   parent.unselectButtons();
        }

   }
   
   /**
    * Needed for MouseListener.
    * @param evt the MouseEvent
    */
   public void mousePressed(MouseEvent evt) {
       //  if right clicked       
       if( evt.getModifiers() == evt.BUTTON3_MASK )
       {
           boolean componentClicked = false;
           Edge clickedEdge = null;
           Node clickedNode = null;

           ListIterator _enum = adjMatrix.listIterator();
           Node _node;
           while (_enum.hasNext() && !centerSelected) {
	     _node = (Node) _enum.next();
             if(_node.contains(evt.getPoint())){
                clickedNode = _node ;
                break;
             }
             for(int i=0; i<_node.edges.size(); i++){
                Edge edge = ((Edge)_node.edges.get(i)) ;
                componentClicked = edge.centerSelected(evt.getX(), evt.getY(), false) ;
                if(componentClicked){
                    clickedEdge = edge ;
                    break;
                }
             }
            }// end while

           if(clickedNode!=null){
               openComponentPopup(evt, clickedNode);
               return ;
           }
           else if(clickedEdge!=null){
               openComponentPopup(evt, clickedEdge);
               return ;
           }
           else {
               openComponentPopup(evt);
               return ;               
           }
       }// end right click tasks
       
       if(task==MOVE){
        for(int i=0; i<adjMatrix.size(); i++){
           Node node = (Node)adjMatrix.get(i);
           if(node.isSelected){
               node.setToMove(evt.getX(),evt.getY());
               flowVisible= false; 
           }
        }
       }
       
       if(task!=DO_NOTHING) return;

/*
 *  if node is clicked:
 *  1.  Select it
 *  2.  Make it Draggable
 *       or
 *  1.  Deselect it
 */
       ListIterator enum = adjMatrix.listIterator();
       Node node;
       boolean nodeClicked = false;
       while (enum.hasNext()) {
	 node = (Node) enum.next();
         if(node.contains(evt.getPoint())){
             flowVisible= false; 
             nodeClicked = true;
             if(!node.isSelected) {
                 node.select();
                 node.isDraggable = true;
             }
             else{
                 node.disSelect();
//                 if(!node.isDraggable) node.disSelect();
             }
             repaint();
             moveActivated = true;             
         }
       }
//       moveActivated = true;
       
// centre of edge cilicked :
/*
 *  If center of the edge is clicked :
 *  1.  mark centerSelected
 *  2.  activate moveActivated
 *  3.  mark nodes draggable
 *  4.  Set nodes to move
 */
        centerSelected = false;
        ListIterator _enum = adjMatrix.listIterator();
        Node _node;
        while (_enum.hasNext() && !centerSelected) {
	  _node = (Node) _enum.next();
          for(int i=0; i<_node.edges.size(); i++){
             centerSelected = ((Edge)_node.edges.get(i)).centerSelected(evt.getX(), evt.getY(), true) ;
             if(centerSelected) break;
          }
        }
        if(centerSelected){
            moveActivated = true;
            for(int i=0; i<adjMatrix.size(); i++){
               Node n = (Node)adjMatrix.get(i);
               if(n.isDraggable){
                   n.setToMove(evt.getX(),evt.getY());
                   flowVisible= false; 
               }
            }
            repaint();
        }
        
        selectRect_X = evt.getX();
        selectRect_Y = evt.getY();
        selectRect = new Rectangle(0,0,0,0);
   }
   
   /**
    * Needed for MouseListener.
    * @param evt the MouseEvent
    */
   public void mouseReleased(MouseEvent evt) {
//        System.out.println("\tMouse Released");

       //  if right clicked       
       if( evt.getModifiers() == evt.BUTTON3_MASK )
       {
           repaint();
           return ;
       }// end right click tasks

       if(task==MOVE){
        for(int i=0; i<adjMatrix.size(); i++){
           Node node = (Node)adjMatrix.get(i);
           if(node.isSelected){
               node.unsetToMove();
           }
        }
       }


        if(task!=DO_NOTHING){ 
            return;
        }
        
       ListIterator enum = adjMatrix.listIterator();
       Node node;
       boolean nodeClicked = false;
       while (enum.hasNext()) {
	 node = (Node) enum.next();
         if(node.contains(evt.getPoint())){
             nodeClicked = true;
             if(node.isSelected) {
                if(node.isDraggable && isDragged) node.disSelect();
                node.isDraggable = false;
             }
//             repaint();
         }
       }
       
       if(centerSelected)
       {
           centerSelected=false;
           for(int i =0; i< adjMatrix.size(); i++){
               Node n = (Node)adjMatrix.get(i);
               if(n.isDraggable){
                   n.isDraggable = false;
                   n.unsetToMove();
                   if(isDragged) n.disSelect();
               }
           }       
       }
           
       if(isDragged){ 
           for(int i =0; i< adjMatrix.size(); i++){
               Node n = (Node)adjMatrix.get(i);
               if(n.isDraggable){
                   n.disSelect();
                   n.isDraggable = false;
                   n.unsetToMove();
               }
           }
           storeCurrentState();
           isDragged = false;
           repaint();
       }
       moveActivated = false;

       int count = 0;
       boolean merged = false;
       while ( count < adjMatrix.size() ) {
           Node n = (Node)adjMatrix.get(count++);
           boolean isStored = false;
           for(int i = count; i< adjMatrix.size(); i++){
               Node _n = (Node)adjMatrix.get(i);
               if( n.contains(new Point2D.Float(_n.x,_n.y)) ){
                   //merge n and _n
//                   adjMatrix.remove(i);
//                   adjMatrix.remove(n);
                   merged = true;
                   Node newNode = new Node(n.x, n.y);
                   n.childID = newNode.nodeID;
                   _n.childID = newNode.nodeID;
                   newNode.parentID1 = n.nodeID;
                   newNode.parentID2 = _n.nodeID;
                   ListIterator enumer = n.edges.listIterator();
                   while (enumer.hasNext()) {
                       Edge edg = (Edge)enumer.next();
                       Node[] ns = edg.getNodes();
                       if(ns[0].nodeID == n.nodeID) edg.exchangeNode(newNode, Edge.LEFT_NODE, "");
                       else if(ns[1].nodeID == n.nodeID) edg.exchangeNode(newNode, Edge.RIGHT_NODE, "");
              	       newNode.edges.add( edg );
//                       if(!adjMatrix.contains(newNode)) adjMatrix.add(newNode);
                   }
                   ListIterator _enumer = _n.edges.listIterator();                   
                   while (_enumer.hasNext()) {
                       Edge edg = (Edge)_enumer.next();
                       Node[] ns = edg.getNodes();
                       if(ns[0].nodeID == _n.nodeID) edg.exchangeNode(newNode, Edge.LEFT_NODE, "");
                       else if(ns[1].nodeID == _n.nodeID) edg.exchangeNode(newNode, Edge.RIGHT_NODE, "");
              	       newNode.edges.add( edg );
                   }
                   storeCurrentState();
                   adjMatrix.remove(i);
                   adjMatrix.remove(n);
                   adjMatrix.add(newNode);
                   storeCurrentState();
                   for(int k =0; k< adjMatrix.size(); k++)
                   {
                       Node nd = (Node)adjMatrix.get(k);
                       for(int j = 0; j < nd.edges.size(); j++)
                       {
                           Edge edg = (Edge)nd.edges.get(j) ;
                           if(nd.edges.indexOf(edg)!=nd.edges.lastIndexOf(edg) )
                               do{
                               }while(nd.edges.remove(edg));// remove the duplicate edge
//                           System.out.println(k+", "+j+"->"+ ((Edge)nd.edges.get(j)).getID() );
                       }
                   }
                   repaint();
                   return;
               }
           }//end for
       }//end while
       if(merged){ 
           repaint();
           return;
       }
       
       if(((int)selectRect.getX())!=0 && ((int)selectRect.getY())!=0)
       {
	  repaint();
       }
       selectRect = null;
   }
   
   /**
    * Needed for MouseListener.
    * @param evt the MouseEvent
    */
   public void mouseEntered(MouseEvent evt) {
      // nothing needed here
   }
   
   /**
    * Needed for MouseListener.
    * @param evt the MouseEvent
    */
   public void mouseExited(MouseEvent evt) {
      // nothing needed here
   }

    public void mouseDragged(java.awt.event.MouseEvent p1) {
        
        if(selectRect!=null && !moveActivated){
            int X, Y, ex, ey, h, w;
            ex = p1.getX();
            ey = p1.getY();
            X = (ex > selectRect_X) ? selectRect_X:ex;
            Y = (ey > selectRect_Y) ? selectRect_Y:ey;
            w = Math.abs(selectRect_X-ex) ;
            h = Math.abs(selectRect_Y-ey) ;
            selectRect = new Rectangle(X,Y,w,h);
            mouseSelect();
        }

        if(task==MOVE || moveActivated){
            isDragged = true;
            shift(p1.getX(), p1.getY());
            return;
        }
    }    
    
    public void mouseMoved(java.awt.event.MouseEvent p1) {
    }

  public void createResistor(int x, int y)
   {
	Object[] input;
	int value;

	input = newEdgeInput("Resistor");
	if(input == null )
	  {
	    task = DO_NOTHING;
	    parent.unselectButtons();
	    return;
	  }

	//Create nodes:	
        Node l_node = new Node(x,y);
        Node r_node = new Node(x+Resistor.STD_WIDTH,y);

        Resistor res = new Resistor((String)input[0], l_node, r_node);

	res.assignCurrent((String)input[1]);

	if(input[2]!=null){
	  res.removeAllInstanceConstriant();
	  for(int i=0 ; i< ((String[])input[2]).length ; i++)
	    res.addInstanceConstriant( ((String[])input[2])[i] );
	}

	if(input[3]!=null){
	  Resistor.removeAllConstraints();
	  for(int i=0 ; i< ((String[])input[3]).length ; i++)
	    Resistor.addConstraints( ((String[])input[3])[i] );
	}
	
//      updateAdjMatrix
        l_node.edges.add(res);
        r_node.edges.add(res);
        adjMatrix.add(l_node);
        adjMatrix.add(r_node);
        task = DO_NOTHING;
        repaint();
        storeCurrentState();
	parent.unselectButtons();
   }

  /*   
   public void addSeriesResistor()
   {
       ListIterator enum = adjMatrix.listIterator();
       Node[] node = new Node[adjMatrix.size()];       
       int count = 0;
       boolean nodeClicked = false;
       while (enum.hasNext()) {
           Node n = (Node)enum.next();
           if(n.isSelected) node[count++] = n;
       }
//       if(count==2) addSeries(node[0], node[1]);
       if(count == 1) addSeries(node[0]);
       else if(count ==0) addSeries();
       else{
      	   JOptionPane.showMessageDialog(null,"Cannot create resistor in series to more than one component.","ERROR", JOptionPane.ERROR_MESSAGE); 
       }
       task = DO_NOTHING;
   }

   public void addSeries(Node l_node, Node r_node)
   {
       Edge e = getCommonEdge(l_node,r_node);
       if(e!=null){
           Node _r_node = r_node.getClone();
           int value = Integer.parseInt(JOptionPane.showInputDialog("Enter the resistance of the resistor :"));
           Node m_node = new Node((int)(l_node.x + _r_node.x)/2 , (int)(l_node.y+_r_node.y)/2);//middle node

           //Assigning parent of middle node
           m_node.parentID1 = r_node.nodeID;
           e.exchangeNode(m_node, e.RIGHT_NODE,"add");

           //replace existing r_node by its clone 
           for(int i = 0; i< _r_node.edges.size(); i++)
           {
                Edge edg = (Edge)_r_node.edges.get(i);
                Node[] ns = edg.getNodes();
                if(ns[0].nodeID == _r_node.nodeID) edg.exchangeNode(_r_node, Edge.LEFT_NODE, "");
                else if(ns[1].nodeID == _r_node.nodeID) edg.exchangeNode(_r_node, Edge.RIGHT_NODE, "");
           }
           
           // remove common edge
           for(int i=0; i<_r_node.edges.size();i++){
              if( ((Edge)_r_node.edges.get(i)).getID().equals(e.getID()) ){ 
                 _r_node.edges.remove(i);
              }
            }
           Resistor res = new Resistor(value, m_node, _r_node);
           m_node.edges.add(res);
           _r_node.edges.add(res);


           adjMatrix.remove(r_node);
           adjMatrix.add(_r_node);
           adjMatrix.add(m_node);

            l_node.disSelect();
            _r_node.disSelect();
            storeCurrentState();
            repaint();
       }
       else{// no common element
           System.out.println("No common element - Can't do anything about this selection");
      	   JOptionPane.showMessageDialog(null,"Cannot create resistor in series. Select a single component.","ERROR", JOptionPane.ERROR_MESSAGE);            
       }       
   }
  */

   public Edge getCommonEdge(Node n1, Node n2)
   {
       for(int i=0; i< n1.edges.size(); i++){
           Edge e1 = (Edge)n1.edges.get(i);
           for(int j=0; j<n2.edges.size(); j++){
               Edge e2 = (Edge)n2.edges.get(j);
               if(e1.getID().equals(e2.getID())) return e1;
           }
       }
       return null;
   }

  /*   
   public void addSeries(Node l_node)
   {
       if(l_node.edges.size()==1){
           Node r_node = new Node(l_node.x+Resistor.STD_WIDTH, l_node.y);
           int value = Integer.parseInt(JOptionPane.showInputDialog("Enter the resistance of the resistor :"));
           Resistor res = new Resistor(value, l_node, r_node);
//         updateAdjMatrix
           l_node.edges.add(res);
           r_node.edges.add(res);
           adjMatrix.add(r_node);
           l_node.disSelect();
           storeCurrentState();
           repaint(); 
        }
       else{
           //display error message : more than two edges in the node. 
       }
   }
   
   public void addSeries()
   {
       Resistor res = createResistor(30, 30);
       int value = Integer.parseInt(JOptionPane.showInputDialog("Enter the resistance of the resistor :"));
       Node l_node = res.r_node;
       Node r_node = new Node(l_node.x+Resistor.STD_WIDTH, l_node.y);
       Resistor r_res = new Resistor(value, l_node, r_node);
//      updateAdjMatrix
       l_node.edges.add(r_res);
       r_node.edges.add(r_res);
//       System.out.println("\nr_node ID = "+r_node.nodeID + " no. of edges = "+r_node.edges.size());
       adjMatrix.add(r_node);
       storeCurrentState();
       repaint();
   }

   public void addParallelResistor()
   {
       ListIterator enum = adjMatrix.listIterator();
       Node[] node = new Node[adjMatrix.size()];       
       int count = 0;
       boolean nodeClicked = false;
       while (enum.hasNext()) {
           Node n = (Node)enum.next();
           if(n.isSelected) node[count++] = n;
       }
       if(count==2) addParallel(node[0], node[1], 40);
       else{
           //Error
           System.out.println("*ERROR*   Select exactly two node on the same circuit");
           task = DO_NOTHING;
       }
   }
   
   public void addParallel(Node n1, Node n2, int dy){
       Node l_node = new Node(n1.x, n1.y + dy);
       Node r_node = new Node(n2.x, n2.y + dy);
       int value = Integer.parseInt(JOptionPane.showInputDialog("Enter the resistance of the resistor :"));
       Resistor res = new Resistor(value, l_node, r_node);
       l_node.edges.add(res);
       r_node.edges.add(res);
//     make copies of n1 and n2 for different reference
       Node _n1 = n1.getClone();
       Node _n2 = n2.getClone();
//     replace existing n1 and n2 by their clones 
       for(int i = 0; i< _n1.edges.size(); i++)
       {
           Edge e = (Edge)_n1.edges.get(i);
           Node[] ns = e.getNodes();
           if(ns[0].nodeID == _n1.nodeID) e.exchangeNode(_n1, Edge.LEFT_NODE, "");
           else if(ns[1].nodeID == _n1.nodeID) e.exchangeNode(_n1, Edge.RIGHT_NODE, "");
       }
       
       for(int i = 0; i< _n2.edges.size(); i++)
       {
           Edge e = (Edge)_n2.edges.get(i);
           Node[] ns = e.getNodes();
           if(ns[0].nodeID == _n2.nodeID) e.exchangeNode(_n2, Edge.LEFT_NODE, "");
           else if(ns[1].nodeID == _n2.nodeID) e.exchangeNode(_n2, Edge.RIGHT_NODE, "");
       }
              
       createWire(_n1, l_node);
       createWire(_n2, r_node);
       adjMatrix.remove(n1);
       adjMatrix.remove(n2);
       adjMatrix.add(_n1);
       adjMatrix.add(_n2);
       adjMatrix.add(l_node);
       adjMatrix.add(r_node);
       storeCurrentState();
       repaint();
   }

  */

   public void createBattery(int x, int y)
   {
	Object[] input;
	int value;

	input = newEdgeInput("Battery");
	if(input == null )
	  {
	    task = DO_NOTHING;
	    parent.unselectButtons();
	    return;
	  }
	
        Node l_node = new Node(x,y);
        Node r_node = new Node(x+Battery.STD_WIDTH,y);

        Battery bat = new Battery((String)input[0], l_node, r_node);

	bat.assignCurrent((String)input[1]);

	if(input[2]!=null){
	  bat.removeAllInstanceConstriant();
	  for(int i=0 ; i< ((String[])input[2]).length ; i++)
	    bat.addInstanceConstriant( ((String[])input[2])[i] );
	}

	if(input[3]!=null){
	  Battery.removeAllConstraints();
	  for(int i=0 ; i< ((String[])input[3]).length ; i++)
	    Battery.addConstraints( ((String[])input[3])[i] );
	}


//      updateAdjMatrix
        l_node.edges.add(bat);
        r_node.edges.add(bat);
        adjMatrix.add(l_node);
        adjMatrix.add(r_node);
        task = DO_NOTHING;
        storeCurrentState();
        repaint();
	parent.unselectButtons();
   }

   public void createWire(Node n1, Node n2)
   {
        Wire wire = new Wire(n1,n2);
        n1.disSelect();
        n2.disSelect();
        n1.edges.add(wire);
        n2.edges.add(wire);
        task = DO_NOTHING;
        storeCurrentState();
        repaint();
   }


   public void testDrawWire()
   {
       ListIterator enum = adjMatrix.listIterator();
       Node[] node = new Node[adjMatrix.size()];
       int count = 0;
       boolean nodeClicked = false;
       while (enum.hasNext()) {
           Node n = (Node)enum.next();
           if(n.isSelected) node[count++] = n;
       }
       if(count==2) createWire(node[0], node[1]);
       else{
	  JOptionPane.showMessageDialog(null,"Please select the two nodes which you want\nto join and then press Wire button","ERROR", JOptionPane.ERROR_MESSAGE);
          task = DO_NOTHING;
       }
   }
   
   public void setToMove()
   {
       task = MOVE;
   }

   public void shift(int newX, int newY)
   {
       if(moveActivated){
           if(centerSelected){
            for(int i=0; i<adjMatrix.size(); i++){
                Node node = ((Node)adjMatrix.get(i));
                if(node.isDraggable){
                    node.changePosition(newX, newY);
                }
            }
            repaint();
            return;
           }
           else{
            for(int i=0; i<adjMatrix.size(); i++){
                Node node = ((Node)adjMatrix.get(i));
                if(node.isDraggable){
                    node.changePosition(newX, newY);
                    repaint();
                    return;
                }
            }
           }//end else
           
        return;        
       }

        for(int i=0; i<adjMatrix.size(); i++){
            Node node = ((Node)adjMatrix.get(i));
            if(node.isSelected){
                node.changePosition(newX, newY);
            }
        }

        //check if merging:
        for(int i=0; i<adjMatrix.size(); i++){
            Node node = ((Node)adjMatrix.get(i));
        }
        repaint();
   }

   public void delete()
   {
       LinkedList list = new LinkedList();

       for(int i=0; i< adjMatrix.size();i++)
       {
           Node n1 = (Node)adjMatrix.get(i);
           if(n1.isSelected)
           {
//               System.out.println("Size of node : "+ n1.nodeID +" is : "+ n1.edges.size());
               for(int j = 0 ; j < n1.edges.size(); j++)
               {
                   Edge e = (Edge) n1.edges.get(j);
                   if(e.bothEndsSelected()){
                       Node[] ns = e.getNodes();
                       ns[0].edges.remove(e);
                       ns[1].edges.remove(e);
                       list.add(ns[0]);
                       list.add(ns[1]);
                   }
               }
           }
       }
       
       for(int i = 0; i < list.size() ; i++){
           ((Node)list.get(i)).disSelect() ;
       }


//       System.out.println(" adj size = "+ adjMatrix.size());
       int i = 0;
       while(i<adjMatrix.size())
       {
//           System.out.println("Edges in node :"+((Node)adjMatrix.get(i)).nodeID+" = "+((Node)adjMatrix.get(i)).edges.size());
           if( ((Node)adjMatrix.get(i)).edges.size()==0) adjMatrix.remove(i);
           else i++;
       }
//       System.out.println(" adj size = "+ adjMatrix.size());
       storeCurrentState();
       repaint();
       task = DO_NOTHING;
   }

   public void clearSelection()
   {
       for(int i=0; i<adjMatrix.size();i++){
          ((Node)adjMatrix.get(i)).disSelect();
       }
       repaint();
       isAllSelected=false;
   }

    public void clearAll()
    {
        adjMatrix = new LinkedList();
        Resistor.setCount(0);
        Battery.setCount(0);
        Wire.setCount(0);
        Node.setCount(0);
	ElecComponent.setCurrCount(0);
        storeCurrentState();
        repaint();
    }

    public void selectAll()
    {
        for(int i =0; i<adjMatrix.size(); i++) ((Node)adjMatrix.get(i)).select();
        repaint();
       isAllSelected=true;    
    }

    private void mouseSelect()
    {
        for(int i=0; i<adjMatrix.size(); i++){
            Node n = (Node)adjMatrix.get(i);
            if(n.x>selectRect.x && n.x < selectRect.x+selectRect.width && n.y>selectRect.y && n.y < selectRect.y+selectRect.height){
                n.select();
                //set the identification for the mode of selection
                n.rectSelected = true;
            }
            else{
                if(n.rectSelected){
                    n.disSelect();
                    n.rectSelected = false;
                }
            }
        }
        repaint();
    }
    
   public void paintComponent(Graphics g) {
       try{
         if(areaChanged){
           scrollRectToVisible( new Rectangle(container.getSize()) );
           setPreferredSize( area.getSize() );
           container.revalidate();
           container.repaint();
//          System.out.println("circuit area X = "+ area.width +" Y ="+ area.height);
//          System.out.println(" canvas area X = "+ new Rectangle(container.getSize()).width +" Y ="+ new Rectangle(container.getSize()).height);
           return;
          }
	}
	catch (Exception exp){
	   // do nothing
	}
      actualPaintComponent(g);
   } // end paint

   public void actualPaintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2 = (Graphics2D) g;

      ListIterator enum = adjMatrix.listIterator();
      Node node;
      while (enum.hasNext()) {
	 node = (Node) enum.next();
	 g2.setColor(node.getColor());
	 g2.fill(node);
         for(int i = 0; i< node.edges.size(); i++)
            ((Edge)(node.edges.get(i))).draw(g);
      }

      if(flowVisible && isPrinting){
              for(int i=0; i< adjMatrix.size(); i++){
                Node n = (Node)adjMatrix.get(i);
                g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                            RenderingHints.VALUE_ANTIALIAS_ON);

                g2.setRenderingHint(RenderingHints.KEY_RENDERING,
                            RenderingHints.VALUE_RENDER_QUALITY);
                int fontStyle = Font.ITALIC ;
                FontRenderContext frc = g2.getFontRenderContext();
                Font f = new Font("Times", fontStyle, 10);
                String s = new String("n"+ n.nodeID+", V"+n.nodeID);
                TextLayout tl = new TextLayout(s, f, frc);
                g2.setColor(new Color(179,17,179) );
                tl.draw(g2, n.x - 10, n.y - 10);
                for(int j=0; j< n.edges.size(); j++) ((Edge)n.edges.get(j)).showVals( g );
              }
//          showDirectedFlow();
      }
      
      if(selectRect!=null){ 
         g2.setColor(Color.lightGray);
         g.drawRect(selectRect.x, selectRect.y, selectRect.width, selectRect.height);
      }

   }   

    public void actionPerformed(ActionEvent e) {
    }
    
    public void storeCurrentState(){
        LinkedList list = new LinkedList();
        for(int i=0; i<adjMatrix.size(); i++){
            list.add( ((Node)adjMatrix.get(i)).getClone() );
        }
        myMemento.put(list);
    }

    public void saveCurrentState(){
        LinkedList list = new LinkedList();
        for(int i=0; i<adjMatrix.size(); i++){
            list.add( ((Node)adjMatrix.get(i)).getClone() );
        }
        myMemento.put(list);
    }

    public void retrievePrevState(){

        replaceAdjMatrix( myMemento.getPrevious() );
        for(int i=0; i<adjMatrix.size(); i++){
            ((Node)adjMatrix.get(i)).disSelect();
        }
        establishAssociation("B");
        repaint();
    }

    public void retrieveNextState(){
        replaceAdjMatrix( myMemento.getNext() );
        for(int i=0; i<adjMatrix.size(); i++){
            ((Node)adjMatrix.get(i)).disSelect();
        }
        establishAssociation("F");
        repaint();
    }

    private void establishAssociation(String flag)
    {
        for(int i=0; i<adjMatrix.size(); i++){
            Node node = (Node)adjMatrix.get(i);


            for(int j=0; j<node.edges.size(); j++){
               Edge neighbor = (Edge)node.edges.get(j);
               Node[] peerNodes = neighbor.getNodes();

               if( peerNodes[0].nodeID == node.nodeID){
                   neighbor.exchangeNode(node, Edge.LEFT_NODE, "");
               }
               else if( peerNodes[1].nodeID == node.nodeID){
                   neighbor.exchangeNode(node,Edge.RIGHT_NODE, "");
               }

               if(flag.equals("F")){
                   if( peerNodes[0].nodeID == node.parentID1){
                       neighbor.exchangeNode(node, Edge.LEFT_NODE, "");
                   }
                   else if( peerNodes[1].nodeID == node.parentID1){
                       neighbor.exchangeNode(node,Edge.RIGHT_NODE, "");
                   }
                   if( peerNodes[0].nodeID == node.parentID2){
                       neighbor.exchangeNode(node, Edge.LEFT_NODE, "");
                   }
                   else if( peerNodes[1].nodeID == node.parentID2){
                       neighbor.exchangeNode(node,Edge.RIGHT_NODE, "");
                   }
               }
               if(flag.equals("B")){
                   if( peerNodes[0].nodeID == node.childID ){
                       neighbor.exchangeNode(node, Edge.LEFT_NODE, "");
                   }
                   else if( peerNodes[1].nodeID == node.childID ){
                       neighbor.exchangeNode(node, Edge.RIGHT_NODE, "");
                   }
               }

            }

        }
    }



    public boolean finalize(CobCode cobCode)
    {
        compList = cobCode.identifyComponents(adjMatrix) ;
        if(compList!=null){
            blink();
        }//end if
        else{
           JOptionPane.showMessageDialog(null,"No Circuit Drawn","ERROR", JOptionPane.ERROR_MESSAGE);
           return false;
        }
        return true;
    }

    private void blink()
    {
        delay = 200;
        blinks = 6;
        timer = new javax.swing.Timer(delay, new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                if(isAllSelected) {
                  clearSelection();
                }
                else{
                  selectAll();
                }
                blinks--;
                if( blinks<1){
                 timer.stop();
                 clearSelection();		 
	         timer = new javax.swing.Timer(100, new ActionListener() {
	            public void actionPerformed(ActionEvent evt) {
//	               clearSelection();
        	       compile(compList);
		       timer.stop();
		    }
		 });
		 timer.start();
		 
                }
            }
         });
        timer.start();
    }

    private void compile(LinkedList[] compList)
    {
            int id = 1;
                for(int i =0; i<adjMatrix.size(); i++) ((Node)adjMatrix.get(i)).makeCurrentList();

                for(int i=0; i< compList.length; i++)
                {
                    LinkedList list  = (LinkedList)compList[i];
                    for(int j = 0; j< list.size(); j++)
                    {
                        ((Edge)list.get(j)).passCurrentToNodes();
                    }
                }
            flowVisible= true;
            showDirectedFlow();

    }

    private void showDirectedFlow(){
              for(int i=0; i< adjMatrix.size(); i++){
                Node n = (Node)adjMatrix.get(i);
                Graphics g = getGraphics();
                Graphics2D g2 = (Graphics2D) g;
                g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                            RenderingHints.VALUE_ANTIALIAS_ON);

                g2.setRenderingHint(RenderingHints.KEY_RENDERING,
                            RenderingHints.VALUE_RENDER_QUALITY);
			    
//                int fontStyle = Font.ITALIC ;
//                FontRenderContext frc = g2.getFontRenderContext();
//                Font f = new Font("Times", fontStyle, 10);
//                String s = new String("n"+ n.nodeID+", V"+n.nodeID);
//                TextLayout tl = new TextLayout(s, f, frc);
//                g2.setColor(new Color(179,17,179) );
//                tl.draw(g2, n.x - 10, n.y - 10);
                for(int j=0; j< n.edges.size(); j++) ((Edge)n.edges.get(j)).showVals( g );
              }
    }

    public void setContainer(JScrollPane cont)
    {
        container = cont;
    }
    
    public void replaceAdjMatrix(LinkedList list)
    {
        adjMatrix = list;
        int maxResCount = 0, maxBatCount = 0, maxWireCount = 0, maxNodeCount = 0, maxCurrCount = 0;
        if(list.size()>0){
            maxNodeCount = ((Node)list.get(0)).getIDVal();
            for(int i = 0; i< list.size() ; i++)
            {
                Node node = (Node)list.get(i) ;
                if(node.getIDVal() > maxNodeCount){
                    maxNodeCount = node.getIDVal();
                }
                for(int j = 0; j< node.edges.size() ; j++)
                {
                    Edge edge = (Edge)node.edges.get(j) ;
		    
		    int ival = edge.getCurrIDVal() ;
                    if(ival > maxCurrCount) maxCurrCount = ival ;
		    
                    if(edge.getType().equals("Resistor")){
                        int cval = edge.getIDVal() ;
                        if(cval > maxResCount) maxResCount = cval ;
                    }
                    else if(edge.getType().equals("Battery")){
                        int cval = edge.getIDVal() ;
                        if(cval > maxBatCount) maxBatCount = cval ;
                    }
                    else if(edge.getType().equals("Wire")){
                        int cval = edge.getIDVal() ;
                        if(cval > maxWireCount) maxWireCount = cval ;
                    }
                    else{
                    }
		    
                }//end for j
            }//end for i           
        }// end if

        Resistor.setCount(maxResCount);
        Battery.setCount(maxBatCount);
        Wire.setCount(maxWireCount);
        Node.setCount(maxNodeCount);
	ElecComponent.setCurrCount(maxCurrCount);
    }
    
    public void modifyArea()
    {
        int maxX = 0, maxY=0;
        for(int i =0; i < adjMatrix.size(); i++)
        {
            Node node = (Node)adjMatrix.get(i);
            if(maxX < node.x+node.w/2)  maxX = (int)(node.x+node.w/2) ;
            if(maxY < node.y+node.h/2)  maxY = (int)(node.y+node.h/2) ;
        }
        if( area.height != maxY+30 || area.width != maxX+30 ){
            area = new Rectangle(maxX+30, maxY+30);
            areaChanged = true;
        }
        else areaChanged = false;
    }

    private void openComponentPopup(MouseEvent e, Node n)
    {
        final Node node  = n;
        Component parent = this;
	final JPopupMenu menu = new JPopupMenu("Node");
        menu.setInvoker(parent);

        menu.add(new AbstractAction("About"){
	    public void actionPerformed(ActionEvent evt){
                String text = "";
                text +="Node ID : "+node.nodeID;
                text +="\nNumber of edges linked to this node : "+node.edges.size();
                String cText = "";
                LinkedList list = Node.getConstraints();
                for(int i=0; i<list.size(); i++)
                    cText+=(String)list.get(i)+"\n";
                text+="\n____________________";
                text+="\nConstraints :\n"+cText;                
                JOptionPane.showMessageDialog(null, text);
                menu.setVisible(false);
	    }
	  });

          menu.add(new AbstractAction("Change"){
	    public void actionPerformed(ActionEvent evt){
                modifyNode();
                menu.setVisible(false);
	    }
	  });

          menu.show(parent, e.getX(), e.getY());          
    }
    
    private void openComponentPopup(MouseEvent e, Edge edg)
    {
        final Edge edge = edg;
        Component parent = this;
	final JPopupMenu menu = new JPopupMenu("Edge - "+edge.getType());
        menu.setInvoker(parent);

        menu.add(new AbstractAction("Change"){
	    public void actionPerformed(ActionEvent evt){
                modifyEdge(edge);
                menu.setVisible(false);
	    }
	  });

          menu.add(new AbstractAction("Delete"){
	    public void actionPerformed(ActionEvent evt){
                // select nodes at both the ends :
                Node[] nodes = edge.getNodes();
                nodes[0].select();
                nodes[1].select();
                delete();
                menu.setVisible(false);
	    }
	  });

        menu.add(new AbstractAction("About"){
	    public void actionPerformed(ActionEvent evt){
                String text = "";
                text +="Edge Type : "+edge.getType();
                text +="\n\nEdge ID : "+edge.getID();
                text +="\nValue : "+edge.getValue();
		text +="\nCurrent : "+edge.getCurrent();
                text +="\n\nLeft node : "+((Node)(edge.getNodes()[0])).nodeID;
                text +="\nRight node : "+((Node)(edge.getNodes()[1])).nodeID;

                String lcText = "";
		String[] clist = edge.getInstanceConstraint();
		for(int i=0; i<clist.length; i++)
		  lcText+= clist[i]+"\n";
		if(clist.length==0)
		  lcText+= "NIL\n";
                text+="\n____________________";
                text+="\nInstance Constraints :\n"+lcText;

                String cText = "";
                if(edge.getType().equals("Resistor")){
                    LinkedList list = Resistor.getConstraints();
                    for(int i=0; i<list.size(); i++)
                        cText+=(String)list.get(i)+"\n";
                }
                else if(edge.getType().equals("Battery")){ 
                    LinkedList list = Battery.getConstraints();
                    for(int i=0; i<list.size(); i++)
                        cText+=(String)list.get(i)+"\n";
                }
                else if(edge.getType().equals("Wire")){ 
                    LinkedList list = Wire.getConstraints();
                    for(int i=0; i<list.size(); i++)
                        cText+=(String)list.get(i)+"\n";
                }
                text+="\n____________________";
                text+="\nType Constraints :\n"+cText;
                JOptionPane.showMessageDialog(null, text);
                menu.setVisible(false);
	    }
	  });
        menu.show(parent, e.getX(), e.getY());          
    }
    
    private void openComponentPopup(MouseEvent e)
    {
        final Canvas parent = this;
	final JPopupMenu menu = new JPopupMenu("Drawing Canvas");
        menu.setInvoker(parent);

        menu.add( parent.parent.saveAction.getAction()) ;
        menu.add( parent.parent.saveAsAction.getAction()) ;
        menu.add( parent.parent.closeAction.getAction()) ;
        menu.addSeparator();
        menu.add( parent.parent.runAction.getAction()) ;
        menu.add( parent.parent.compileAction.getAction()) ;
        menu.addSeparator();
        menu.add( parent.parent.bgAction.getAction()) ;
        menu.show(parent, e.getX(), e.getY());
    }

    private void modifyNode()
    {
        String message = "Modify the constraints for the Nodes";
/*
 *      Constraints
 */     
        String cText = "";
        LinkedList list = Node.getConstraints();
        for(int i=0; i<list.size(); i++)
                cText+=(String)list.get(i)+"\n";
        
        JTextArea cTextArea = new JTextArea(cText,4,30);
        JPanel cPane = new JPanel();
        cPane.add(new JScrollPane(cTextArea));
        cPane.setBorder( BorderFactory.createEmptyBorder(20,20,20,20) );
        cPane.setBorder(BorderFactory.createTitledBorder( "Constraints for Node" ));        
        int result;
        result = JOptionPane.
        showOptionDialog(this,
                          new Object[] { message, cPane},
                          "Node properties", JOptionPane.OK_CANCEL_OPTION,
                          JOptionPane.QUESTION_MESSAGE, null, null, null);
    }



    private Object[] newEdgeInput(String type )
    {
        String message = "Please enter following values for the "+ type;
	Object input[];
	final String t = type;
	boolean validInput = false;

        if(type.equals("Wire")){ 
	  return null;
        }


/*
 *      Resistance/Voltage Value
 */
        JTextField valField = new JTextField( "" );
        JPanel valPane = null, currPane ;
	valPane = new JPanel(new GridLayout(1,2)) ;
	if(type.equals("Resistor") )
	  valPane.add( new JLabel("Resistance") );
	else if(type.equals("Battery"))
	  valPane.add( new JLabel("Voltage") );
	valPane.add(valField);
/*
 *      Current Value
 */
        JTextField currField = new JTextField( "" );
        currPane = new JPanel(new GridLayout(1,2)) ;
        currPane.add( new JLabel("Current ( "+ "I"+ (ElecComponent.getIcount()+1)+ " )") );
        currPane.add(currField);
        
/*
 *      Constraints
 */
        String cText = "";
        if( type.equals("Resistor") ){
            LinkedList list = Resistor.getConstraints();
            for(int i=0; i<list.size(); i++)
                cText+=(String)list.get(i)+"\n";
        }
        else if( type.equals("Battery") ){ 
            LinkedList list = Battery.getConstraints();
            for(int i=0; i<list.size(); i++)
                cText+=(String)list.get(i)+"\n";
        }

	String instanceVariables = " ";
	instanceVariables += "Instance Variables :\t";
	instanceVariables += "I"+(ElecComponent.getIcount()+1)+",  ";
	if(type.equals("Resistor"))
	  instanceVariables += "R"+(Resistor.count+1)+",  ";
	else if(type.equals("Battery"))
	  instanceVariables += "B"+(Battery.count +1)+",  ";

	instanceVariables += "V.left,  V.right";
	JTextField ivField = new JTextField(instanceVariables);
	ivField.setDisabledTextColor(Color.darkGray);
	ivField.setBackground(Color.lightGray);
	ivField.setEnabled(false);
	JPanel ivPane = new JPanel(new GridLayout(1,1) );
	ivPane.add( ivField );
        
        JTextArea c1TextArea = new JTextArea("",4,30);
        JPanel c1Pane = new JPanel(new BorderLayout());
        c1Pane.add(new JScrollPane(c1TextArea), BorderLayout.NORTH);
        c1Pane.add( ivPane, BorderLayout.SOUTH);
        c1Pane.setBorder( BorderFactory.createEmptyBorder(20,20,20,20) );
        c1Pane.setBorder(BorderFactory.createTitledBorder( "Constraint for this "+type));
        
        c2TextArea = new JTextArea(cText,4,30);
        final Color textAreaColor = c2TextArea.getBackground();
        c2TextArea.setBackground(Color.lightGray);
        c2TextArea.setDisabledTextColor(Color.darkGray);
        c2TextArea.setEnabled(false);


        final JRadioButton rbut = new JRadioButton("Change");
        rbut.addActionListener(new ActionListener() {
    	 public void actionPerformed(ActionEvent e) {
             if(rbut.isSelected()) {
                 c2TextArea.setEnabled(true);
                 c2TextArea.setBackground(textAreaColor);
             }
             else  {
                 c2TextArea.setEnabled(false);
                 c2TextArea.setBackground(Color.lightGray);
             }
	 }
        });
        
 	String globalVariables = " ";
	globalVariables += "Global Variables :\t";
	if(type.equals("Resistor"))
	  globalVariables += "I,  R,  N1.V,  N2.V";
	else if(type.equals("Battery"))
	  globalVariables += "B,  N1.V,  N2.V";

	
	JTextField gvField = new JTextField(globalVariables);
	gvField.setDisabledTextColor(Color.darkGray);
	gvField.setBackground(Color.lightGray);
	gvField.setEnabled(false);
        JPanel gvPane = new JPanel(new GridLayout(1,1));
	gvPane.add( gvField );
	
	

        JPanel c2Pane = new JPanel(new BorderLayout());
        c2Pane.add(rbut,  BorderLayout.NORTH);
        c2Pane.add(new JScrollPane(c2TextArea),  BorderLayout.CENTER);
	c2Pane.add( gvPane,  BorderLayout.SOUTH);
        c2Pane.setBorder( BorderFactory.createEmptyBorder(20,20,20,20) );
        c2Pane.setBorder(BorderFactory.createTitledBorder( "Constraint for "+type+" Type" ));

	input = null;
	while(!validInput)
	  {
	    int result;
	    validInput = true;
	    input = new Object[4];
	    input[0] = null;
	    result = JOptionPane.
	      showOptionDialog(this,
                      new Object[] { message, getHelpDropdown(type), valPane, currPane, new JPanel(), c1Pane, new JPanel(), new JPanel(), c2Pane},
                      "New "+type+" properties", JOptionPane.OK_CANCEL_OPTION,
                      JOptionPane.QUESTION_MESSAGE, null, null, null);

	    if(result==JOptionPane.OK_OPTION ){
	      input[0] = valField.getText();
	      input[1] = currField.getText();

	      input[2] = c1TextArea.getText();
	      StringTokenizer st = new StringTokenizer((String)input[2],";\n", false);

	      if( st.countTokens() > 0 ){
		int count=0;
		LinkedList cl = new LinkedList();
		while(st.hasMoreTokens())
		  {
		    String tok = st.nextToken();
		    StringTokenizer testTok = new StringTokenizer(tok);
		    if(testTok.countTokens() > 0)
		      cl.add( tok + ";");
		  }
		String[] localConstraints = new String[cl.size()];
		for(int i=0; i< cl.size(); i++) 
		  localConstraints[i] = (String)cl.get(i);
		input[2] = localConstraints;
	      }
	      else input[2] = null;


	      input[3] = c2TextArea.getText();
	      st = new StringTokenizer((String)input[3],";\n", false);
	      if( st.countTokens() > 0 ){
		int count=0;
		LinkedList cl = new LinkedList();
		while(st.hasMoreTokens())
		  {
		    String tok = st.nextToken();
		    StringTokenizer testTok = new StringTokenizer(tok);
		    if(testTok.countTokens() > 0)
		      cl.add( tok + ";");
		  }
		String[] globalConstraints = new String[cl.size()];
		for(int i=0; i< cl.size(); i++) 
		  globalConstraints[i] = (String)cl.get(i);
		input[3] = globalConstraints;
	      }
	      else input[3] = null;

	      /*
	       * Check if the Non-Integer value was input.
	       * Use this only if needed 
	       *
	       
	      try{
		if(!input[0].equals(""))
		  Integer.parseInt((String)input[0]);
		else input[0] = "?";
	      }
	      catch(NumberFormatException nfe){
		JOptionPane.showMessageDialog(null,"Non-Integer value entered as "+type+" value.\nPlease enter Integer value","ERROR", JOptionPane.ERROR_MESSAGE);		
		validInput = false;
	      }

	      try{
		if(!input[1].equals(""))
		  Integer.parseInt((String)input[1]);
		else input[1] = "?";
	      }
	      catch(NumberFormatException nfe){
		JOptionPane.showMessageDialog(null,"Non-Integer value entered as current value.\nPlease enter Integer value","ERROR", JOptionPane.ERROR_MESSAGE);		
		validInput = false;
	      }
	      
	      *
	      *
	      */

	    }
	    else{
	      return null;
	    }
	  }//end while
	return input;
    }

    
    
    private void modifyEdge(Edge edge)
    {
        String message = "Please enter following values for the "+ edge.getType();
	Object input[];
	boolean validInput = false;
	JPanel valPane = null, currPane ;
	final Edge edg = edge;

/*
 *      Resistance/Voltage Value
 */ 
	JTextField valField = null;
        if(!edge.getType().equals("Wire")){
	  if(!edge.getValue().equals("?"))
	    {
	       String val = String.valueOf(edge.getValue());
//	       if(val.endsWith("x")) val = "";
	       valField = new JTextField( val ) ;
	    }
	  else
	    valField = new JTextField("");

	  if(!edge.getType().equals("Wire")){
            valPane = new JPanel(new GridLayout(1,2)) ;
            if(edge.getType().equals("Resistor") )
	      valPane.add( new JLabel("Resistance") );
            else if(edge.getType().equals("Battery"))
	      valPane.add( new JLabel("Voltage") );
	    
            valPane.add(valField);
	  }
	}

/*
 *      Current Value
 */
        JTextField currField;
	if( !( edge.getCurrent()==null || edge.getCurrent().equals("?") || edge.getCurrent().equals("") ))
	  currField = new JTextField( edge.getCurrent() );
	else
	  currField = new JTextField("");

        currPane = new JPanel(new GridLayout(1,3)) ;
        currPane.add( new JLabel("Current ( "+ edge.getCurrentID() + " )") );
        currPane.add(currField);


/*
 *      Instance Constraints
 */
        String icText = "";
        String[] iclist = edge.getInstanceConstraint();
        for(int i=0; i<iclist.length; i++) icText+=iclist[i]+"\n";

	String instanceVariables = " ";
	instanceVariables += "Instance Variables :\t";
	instanceVariables += edge.getCurrentID()+",  ";
	if(!edge.getType().equals("Wire"))
	  instanceVariables += edge.getID()+",  ";
	instanceVariables += "V.left,  V.right";
	JTextField ivField = new JTextField(instanceVariables);
	ivField.setDisabledTextColor(Color.darkGray);
	ivField.setBackground(Color.lightGray);
	ivField.setEnabled(false);
	JPanel ivPane = new JPanel(new GridLayout(1,1) );
	ivPane.add( ivField );
	
        JTextArea c1TextArea = new JTextArea(icText,4,30);
        JPanel c1Pane = new JPanel(new BorderLayout());
        c1Pane.add(new JScrollPane(c1TextArea), BorderLayout.NORTH);
	c1Pane.add( ivPane,  BorderLayout.SOUTH);
	
        c1Pane.setBorder( BorderFactory.createEmptyBorder(20,20,20,20) );
        c1Pane.setBorder(BorderFactory.createTitledBorder( "Constraint for "+edge.getType()+" "+edge.getID() ));
        
/*
 *      Type Constraints
 */
        String cText = "";
        if(edge.getType().equals("Resistor")){
            LinkedList list = Resistor.getConstraints();
            for(int i=0; i<list.size(); i++)
                cText+=(String)list.get(i)+"\n";
        }
        else if(edge.getType().equals("Battery")){ 
            LinkedList list = Battery.getConstraints();
            for(int i=0; i<list.size(); i++)
                cText+=(String)list.get(i)+"\n";
        }
        else if(edge.getType().equals("Wire")){ 
            LinkedList list = Wire.getConstraints();
            for(int i=0; i<list.size(); i++)
                cText+=(String)list.get(i)+"\n";
        }
        
        c2TextArea = new JTextArea(cText,4,30);
        final Color textAreaColor = c2TextArea.getBackground();
        c2TextArea.setBackground(Color.lightGray);
        c2TextArea.setDisabledTextColor(Color.darkGray);
        c2TextArea.setEnabled(false);

        final JRadioButton rbut = new JRadioButton("Change");
        rbut.addActionListener(new ActionListener() {
    	 public void actionPerformed(ActionEvent e) {
             if(rbut.isSelected()) {
                 c2TextArea.setEnabled(true);
                 c2TextArea.setBackground(textAreaColor);
             }
             else  {
                 c2TextArea.setEnabled(false);
                 c2TextArea.setBackground(Color.lightGray);
             }
	 }
        });

 	String globalVariables = " ";
	globalVariables += "Global Variables :\t";
	if(edge.getType().equals("Resistor"))
	  globalVariables += "I,  R,  N1.V,  N2.V";
	else if(edge.getType().equals("Battery"))
	  globalVariables += "B,  N1.V,  N2.V";
	else if(edge.getType().equals("Wire"))
	  globalVariables += "I,  R,  N1.V,  N2.V";
	
	JTextField gvField = new JTextField(globalVariables);
	gvField.setDisabledTextColor(Color.darkGray);
	gvField.setBackground(Color.lightGray);
	gvField.setEnabled(false);
        JPanel gvPane = new JPanel(new GridLayout(1,1));
	gvPane.add( gvField );
	

        JPanel c2Pane = new JPanel(new BorderLayout() );
	c2Pane.add(rbut,  BorderLayout.NORTH);
        c2Pane.add(new JScrollPane(c2TextArea),  BorderLayout.CENTER);
	c2Pane.add(gvPane,  BorderLayout.SOUTH);
        c2Pane.setBorder( BorderFactory.createEmptyBorder(20,20,20,20) );
        c2Pane.setBorder(BorderFactory.createTitledBorder( "Constraint for "+edge.getType()+" Type" ));

	input = null;
	while(!validInput)
	  {
	    validInput = true;
	    input = new Object[4];
	    input[0] = null;
	    int result;
	    if(!edge.getType().equals("Wire")){
	      result = JOptionPane.showOptionDialog(this,
                             new Object[] { message, getHelpDropdown(edge.getType()), valPane, currPane,new JPanel(), c1Pane, new JPanel(),new JPanel(), c2Pane},
                             edge.getType()+" "+edge.getID()+" properties", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null);
	    }
	    else{
	      result = JOptionPane.
		showOptionDialog(this,
                             new Object[] { message, getHelpDropdown("Wire"), currPane, new JPanel(), c1Pane, new JPanel(),new JPanel(), c2Pane},
                             edge.getType()+" "+edge.getID()+" properties", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null);
	    }

	    
	    if(result==JOptionPane.OK_OPTION ){
	      if(!edge.getType().equals("Wire"))
		input[0] = valField.getText();

	      input[1] = currField.getText();
	      
	      input[2] = c1TextArea.getText();
	      StringTokenizer st = new StringTokenizer((String)input[2],";\n", false);

	      if( st.countTokens() > 0 ){
		int count=0;
		LinkedList cl = new LinkedList();
		while(st.hasMoreTokens())
		  {
		    String tok = st.nextToken();
		    StringTokenizer testTok = new StringTokenizer(tok);
		    if(testTok.countTokens() > 0)
		      cl.add( tok + ";");
		  }
		String[] localConstraints = new String[cl.size()];
		for(int i=0; i< cl.size(); i++) 
		  localConstraints[i] = (String)cl.get(i);
		input[2] = localConstraints;
	      }
	      else input[2] = null;


	      input[3] = c2TextArea.getText();
	      st = new StringTokenizer((String)input[3],";\n", false);
	      if( st.countTokens() > 0 ){
		int count=0;
		LinkedList cl = new LinkedList();
		while(st.hasMoreTokens())
		  {
		    String tok = st.nextToken();
		    StringTokenizer testTok = new StringTokenizer(tok);
		    if(testTok.countTokens() > 0)
		      cl.add( tok + ";");
		  }
		String[] globalConstraints = new String[cl.size()];
		for(int i=0; i< cl.size(); i++) 
		  globalConstraints[i] = (String)cl.get(i);
		input[3] = globalConstraints;
	      }
	      else input[3] = null;


	      /*
	       * Check if the Non-Integer value was input.
	       * Use this only if needed 
	       *

	      if(!edge.getType().equals("Wire")){
		try{
		  if(!input[0].equals(""))
		    Integer.parseInt((String)input[0]);
		  else input[0] = "?";
		}
		catch(NumberFormatException nfe){
		JOptionPane.showMessageDialog(null,"Non-Integer value entered as "+ edge.getType() +" value.\nPlease enter Integer value","ERROR", JOptionPane.ERROR_MESSAGE);

		  validInput = false;
		}
	      }// end if != wire



	      try{
		if(!input[1].equals(""))
		  Integer.parseInt((String)input[1]);
		else input[1] = "?";
	      }
	      catch(NumberFormatException nfe){
		JOptionPane.showMessageDialog(null,"Non-Integer value entered as current value.\nPlease enter Integer value","ERROR", JOptionPane.ERROR_MESSAGE);		
		validInput = false;
	      }

	      *
	      *
	      */

	    }
	    else{
	      return;
	    }
	  }//end while

	  if(!edge.getType().equals("Wire")){
	    edge.setValue( (String)input[0] );
          }

	  edge.assignCurrent((String)input[1]);
  

	  if(input[2]!=null){
	    edge.removeAllInstanceConstriant();
	    for(int i=0 ; i< ((String[])input[2]).length ; i++)
	      edge.addInstanceConstriant( ((String[])input[2])[i] );
	  }
	  else edge.removeAllInstanceConstriant();


	  if(input[3]!=null){
	    if(edge.getType().equals("Resistor")){
	      Resistor.removeAllConstraints();
	      for(int i=0 ; i< ((String[])input[3]).length ; i++)
		Resistor.addConstraints( ((String[])input[3])[i] );
	    }
	    else if(edge.getType().equals("Battery")){
	      Battery.removeAllConstraints();
	      for(int i=0 ; i< ((String[])input[3]).length ; i++)
		Battery.addConstraints( ((String[])input[3])[i] );
	    }
	    else if(edge.getType().equals("Wire")){
	      Wire.removeAllConstraints();
	      for(int i=0 ; i< ((String[])input[3]).length ; i++)
		Wire.addConstraints( ((String[])input[3])[i] );
	    }
	  }
	  else{
	    if(edge.getType().equals("Resistor")){
	      Resistor.removeAllConstraints();
	    }
	    else if(edge.getType().equals("Battery")){
	      Battery.removeAllConstraints();
	    }
	    else if(edge.getType().equals("Wire")){
	      Wire.removeAllConstraints();
	    }
	  }
	  
     }
     
     private void showInstanceInputHelp(String type)
     {
     	String text = "";
	if(type.equals("Resistor"))
	{
	    text += "Help on Input for Resistors\n";
	    text += "---------------------------\n\n";
	    text += "Enter resistance value(if known) against field marked \"Resistor\"\n";
	    text += "Enter current value(if known) against field marked \"Current\"\n";
	    text += "Leave these columns blank if the values are not known.\n\n";
	    text += "Instance Constraints:\nInsert the constraints that you want to put over this Resistor.\nYou can put more than one constraint. Make sure that every\nconstraint ends with a semi-colon(;).\nThe variables should be picked from the list given below the\ninput text box.\ne.g.\n          I3 = 2*R3;\n          V.left > V.right;\n\n";
	    text += "Type Constraints:\nInsert the constraints that you want to put over the Resistor\ntype. These constraints will apply over all the resistors that\nyou put in the circuit. You can put more than one constraint.\nThe input text-box contains the default constraints. Make\nsure that every constraint ends with a semi-colon(;).\nThe variables should be picked from the list given below\nthe input text box. \ne.g.\n         I * R = (N1.V - N2.V);\n         R < 5*I;\n";
	}
	else if(type.equals("Battery"))
	{
	    text += "Help on Input for Batteries\n";
	    text += "---------------------------\n\n";
	    text += "Enter voltage value(if known) against field marked \"Voltage\"\n";
	    text += "Enter current value(if known) against field marked \"Current\"\n";
	    text += "Leave these columns blank if the values are not known.\n\n";
	    text += "Instance Constraints:\n";
	    text += "Insert the constraints that you want to put over this Battery.\n";
	    text += "You can put more than one constraint. Make sure that every \n";
	    text += "constraint ends with a semi-colon(;). The variables should be \n";
	    text += "picked from the list given below the input text box. \ne.g.\n";
	    text += "          I2 < 25;\n          B > 13;\n\n";
	    text += "Type Constraints:\n";
	    text += "Insert the constraints that you want to put over the Battery \n";
	    text += "type. These constraints will apply over all the batteries that\n";
	    text += "you put in the circuit. You can put more than one constraint. \n";
	    text += "The input text-box contains the default constraints. Make sure\n";
	    text += "that every constraint ends with a semi-colon(;). The variables\n";
	    text += "should be picked from the list given below the input text box.\n";
	    text += "e.g.\n          B = (N1.V - N2.V);\n          B < 100;\n";
	}
	else if(type.equals("Wire"))
	{
	    text += "Help on Input for Wires\n";
	    text += "-----------------------\n\n";
	    text += "Enter current value(if known) against field marked \"Current\"\n";
	    text += "Leave this columns blank if the values are not known.\n\n";
	    text += "Instance Constraints:\nInsert the constraints that you want to put over this Resistor. You can put more than one constraint. Make sure that every constraint ends with a semi-colon(;).\nThe variables should be picked from the list given below the input text box. \ne.g.      I6 < 25;\n\n";
	    text += "Type Constraints:\nInsert the constraints that you want to put over the Wire type. These constraints will apply over all the batteries that you put in the circuit. You can put more than one constraint. The input text-box contains the default constraints. Make sure that every constraint ends with a semi-colon(;).\nThe variables should be picked from the list given below the input text box. \ne.g.      N1.V = N2.V;\n";
	}
	else return;
	
	JOptionPane.showMessageDialog(null, text);	
     }
     
     private JComboBox getHelpDropdown(String type)
     {
     	JComboBox helpBox;
     	if(type.equals("Resistor"))
	{
	    String list[] = {"Help", "Value", "Current", "Instance Constraints", "Type Constraints"};
	    helpBox = new JComboBox(list);
	    helpBox.addActionListener(new ActionListener() {
              public void actionPerformed(ActionEvent e) {
	        JComboBox cb = (JComboBox)e.getSource() ;
                String pick = (String)((cb).getSelectedItem());
		if(pick.equals("Value"))
		{
		    String text = "";
		    text += "Help on Input for Resistor\n";
		    text += "---------------------------\n\n";
		    text += "Value :\n";
		    text += "Enter resistance value(if known) in ohms against field\n";
		    text += "marked \"Value\". The units shouldn't be entered.\n\n";
		    text += "Leave this column blank if the values are not known.";
		    JOptionPane.showMessageDialog(null, text);
		}
		else if(pick.equals("Current"))
		{
		    String text = "";
		    text += "Help on Input for Resistor\n";
		    text += "---------------------------\n\n";
		    text += "Current :\n";
		    text += "Enter current value(if known) in amps. against field \n";
		    text += "marked \"Current\". The units shouldn't be entered.\n\n";
		    text += "Leave this column blank if the values are not known.";
		    JOptionPane.showMessageDialog(null, text);			    		
		}
		else if(pick.equals("Instance Constraints"))
		{
		    String text = "";
		    text += "Help on Input for Resistor\n";
		    text += "---------------------------\n\n";
		    text += "Instance Constraints:\n";
		    text += "Insert the constraints that you want to put over this\n";
		    text += "Resistor. You can put more than one constraint. Make\n";
		    text += "sure that every constraint ends with a semi-colon(;).\n";
		    text += "The variables should be picked from the list given below\n";
		    text += "the input text box.\n";
		    text += "e.g.\n          I3 = 2*R3;\n          V.left > V.right;";
		    JOptionPane.showMessageDialog(null, text);	

		}
		else if(pick.equals("Type Constraints"))
		{
		    String text = "";
		    text += "Help on Input for Resistor\n";
		    text += "---------------------------\n\n";
		    text += "Type Constraints:\n";
		    text += "Insert the constraints that you want to put over the\n";
		    text += "Resistor type. These constraints will apply over all\n";
		    text += "the resistors that you put in the circuit. You can put\n";
		    text += "more than one constraint. The input text-box contains \n";
		    text += "the default constraints. Make sure that every constraint\n";
		    text += "ends with a semi-colon(;). The variables should be picked\n";
		    text += "from the list given below the input text box. \n";
		    text += "e.g.\n         I * R = (N1.V - N2.V);\n         R < 5*I;\n";		
		    JOptionPane.showMessageDialog(null, text);
		}
		else{
		 /* do nothing */
		}
		cb.setSelectedIndex(0);
              }
            });
	
	}
	else if(type.equals("Battery"))
	{
	    String list[] = {"Help", "Value", "Current", "Instance Constraints", "Type Constraints"};
	    helpBox = new JComboBox(list);	    	
	    helpBox.addActionListener(new ActionListener() {
              public void actionPerformed(ActionEvent e) {
	        JComboBox cb = (JComboBox)e.getSource() ;
                String pick = (String)((cb).getSelectedItem());
		if(pick.equals("Value"))
		{
		    String text = "";
		    text += "Help on Input for Battery\n";
		    text += "---------------------------\n\n";
		    text += "Value :\n";
		    text += "Enter voltage value(if known) in volts against field\n";
		    text += "marked \"Value\". The units shouldn't be entered.\n\n";
		    text += "Leave this column blank if the values are not known.";
		    JOptionPane.showMessageDialog(null, text);
		}
		else if(pick.equals("Current"))
		{
		    String text = "";
		    text += "Help on Input for Battery\n";
		    text += "---------------------------\n\n";
		    text += "Current :\n";
		    text += "Enter current value(if known) in amps. against field \n";
		    text += "marked \"Current\". The units shouldn't be entered.\n\n";
		    text += "Leave this column blank if the values are not known.";
		    JOptionPane.showMessageDialog(null, text);	
		    		
		}
		else if(pick.equals("Instance Constraints"))
		{
		    String text = "";
		    text += "Help on Input for Battery\n";
		    text += "---------------------------\n\n";
		    text += "Instance Constraints:\n";
		    text += "Insert the constraints that you want to put over this\n";
		    text += "Battery. You can put more than one constraint. Make \n";
		    text += "sure that every constraint ends with a semi-colon(;).\n";
		    text += "The variables should be picked from the list given below\n";
		    text += "the input text box. \ne.g.\n";
		    text += "          I2 < 25;\n          B > 13;\n\n";
		    JOptionPane.showMessageDialog(null, text);	

		}
		else if(pick.equals("Type Constraints"))
		{
		    String text = "";
		    text += "Help on Input for Resistors\n";
		    text += "---------------------------\n\n";
		    text += "Type Constraints:\n";
		    text += "Insert the constraints that you want to put over the\n";
		    text += "Battery type. These constraints will apply over all \n";
		    text += "the batteries that you put in the circuit. You can put\n";
		    text += "more than one constraint. The input text-box contains\n";
		    text += "the default constraints. Make sure that every constraint\n";
		    text += "ends with a semi-colon(;). The variables should be picked\n";
		    text += "from the list given below the input text box.\n";
		    text += "e.g.\n          B = (N1.V - N2.V);\n          B < 100;\n";
		    JOptionPane.showMessageDialog(null, text);	
		}
		else{
		 /* do nothing */
		}
		cb.setSelectedIndex(0);
              }
            });
	    
	}
	
	else if(type.equals("Wire"))
	{
	    String list[] = {"Help", "Current", "Instance Constraints", "Type Constraints"};
	    helpBox = new JComboBox(list);	    	
	    helpBox.addActionListener(new ActionListener() {
              public void actionPerformed(ActionEvent e) {
	        JComboBox cb = (JComboBox)e.getSource() ;
                String pick = (String)((cb).getSelectedItem());

		if(pick.equals("Current"))
		{
		    String text = "";
		    text += "Help on Input for Wire\n";
		    text += "-----------------------\n\n";
		    text += "Current :\n";
		    text += "Enter current value(if known) against field marked \n";
		    text += "\"Value\". The units shouldn't be entered.\n\n";
		    text += "Leave this column blank if the values are not known.\n\n";
		    JOptionPane.showMessageDialog(null, text);	
		    		
		}
		else if(pick.equals("Instance Constraints"))
		{
		    String text = "";
		    text += "Help on Input for Wire\n";
		    text += "-----------------------\n\n";
		    text += "Instance Constraints:\n";
		    text += "Insert the constraints that you want to put over this\n"; 
		    text += "Resistor. You can put more than one constraint. Make \n";
		    text += "sure that every constraint ends with a semi-colon(;).\n";
		    text += "The variables should be picked from the list given \n";
		    text += "below the input text box. \ne.g.      I6 < 25;";
		    JOptionPane.showMessageDialog(null, text);	

		}
		else if(pick.equals("Type Constraints"))
		{
		    String text = "";
		    text += "Help on Input for Wire\n";
		    text += "-----------------------\n\n";
		    text += "Type Constraints:\n";
		    text += "Insert the constraints that you want to put over the \n";
		    text += "Wire type. These constraints will apply over all the \n";
		    text += "wires that you put in the circuit. You can put more \n";
		    text += "than one constraint. The input text-box contains the \n";
		    text += "default constraints. Make sure that every constraint \n";
		    text += "ends with a semi-colon(;). The variables should be \n";
		    text += "picked from the list given below the input text box. \n";
		    text += "e.g.      N1.V = N2.V;\n";
		    JOptionPane.showMessageDialog(null, text);	
		}
		else{
		 /* do nothing */
		}
		cb.setSelectedIndex(0);
              }
            });

	}
     	else helpBox = null;
	
	return helpBox;
     }
     


}
