/**
   This panel holds nodes and manages node selection
   and movement.
   @author Dr. Horstmann
   @author Jason Chan (modifying Dr. Horstmann's original code)
   @author Sugiharto Widjaja (modifying Dr. Horstmann's original code)
*/
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
import java.util.*;

public class NodePanel extends JPanel
{
   /**
      Constructs a node panel with no nodes.
   */
   public NodePanel()
   {
      nodes = new ArrayList();

      addMouseListener(new
         MouseAdapter()
         {
            public void mousePressed(MouseEvent event)
            {
               Node n = find(event.getPoint());
               if (n != null)
               {
                  if (!event.isShiftDown())
                     setSelected(false);
                  n.setSelected(!n.isSelected());
                  lastMousePoint = event.getPoint();
               }
               repaint();
            }
         });

      addMouseMotionListener(new
         MouseMotionAdapter()
         {
            public void mouseDragged(MouseEvent event)
            {
               Point mousePoint = event.getPoint();
               for (int i = 0; i < nodes.size(); i++)
               {
                  Node n = (Node)nodes.get(i);
                  if (n.isSelected())
                     n.translate(
                        mousePoint.getX() - lastMousePoint.getX(),
                        mousePoint.getY() - lastMousePoint.getY());
                     repaint();
               }
               lastMousePoint = mousePoint;
               revalidate();
               repaint();
            }
         });
   }

   public Dimension getPreferredSize()
   {
      Rectangle2D r = new Rectangle2D.Double();
      for (int i = 0; i < nodes.size(); i++)
      {
         AbstractObjectNode n = (AbstractObjectNode)nodes.get(i);
         r.add(n.getRectangle());
      }
      return new Dimension((int)r.getWidth(), (int)r.getHeight());
   }

   /**
      Adds a node to the panel.
      @param aNode the node to add
   */
   public void add(Node aNode)
   {
      nodes.add(aNode);
      revalidate();
      repaint();
   }

   /**
      Removes all selected nodes from the panel.
   */
   public void removeSelected()
   {
      for (int i = nodes.size() - 1; i >= 0; i--)
      {
         Node n = (Node)nodes.get(i);
         if (n.isSelected()) nodes.remove(i);
      }
      repaint();
   }

   /**
      Selects or deselects all nodes in this panel.
      @param b true for selection, false for deselection
   */
   public void setSelected(boolean b)
   {
      for (int i = 0; i < nodes.size(); i++)
      {
         Node n = (Node)nodes.get(i);
         n.setSelected(b);
      }
      repaint();
   }

   /**
      Expands all selected nodes in this panel.
   */
   public void expandSelected()
   {
      for (int i = 0; i < nodes.size(); i++)
      {
         AbstractObjectNode n = (AbstractObjectNode)nodes.get(i);
         if (n.isSelected())
            n.expand(this);
      }
   }

   /**
      Finds a node containing a given point.
      @param aPoint the point for which to find an enclosing node
      @return the first node that contains the given point, or
      null if no node contains it
   */
   public Node find(Point2D aPoint)
   {
      for (int i = 0; i < nodes.size(); i++)
      {
         Node n = (Node)nodes.get(i);
         if (n.contains(aPoint)) return n;
      }
      return null;
   }

   /**
      Finds the object node that represents the given
      object.
      @param obj an object
      @return the object node that represents obj, or
      null if there is no such node in this panel
   */
   public AbstractObjectNode findObject(Object obj)
   {
      for (int i = 0; i < nodes.size(); i++)
      {
         AbstractObjectNode n = (AbstractObjectNode)nodes.get(i);
         if (n.getObject() == obj)
            return n;
      }
      return null;
   }

   /**
      Find the class in the ArrayList according to the given class name
      @param cn the name of the class
      @return the class object node, null if not found
   */
   public AbstractObjectNode findObject(String cn)
   {
	   for (int i = 0; i < nodes.size(); i++)
       {
		   AbstractObjectNode n = (AbstractObjectNode)nodes.get(i);
            if (n.getClassName() == cn)
               return n;
         }
         return null;
   }

   /**
      Paint the actual UML diagram of all classes including the relationship edges
      @param g the Graphics object
   */
   public void paintComponent(Graphics g)
   {
      super.paintComponent(g);
      Graphics2D g2 = (Graphics2D) g;
      ArrayList checklist =new ArrayList();
      //System.out.println(nodes.size());
      for (int i = 0; i < nodes.size(); i++)
      {
         AbstractObjectNode n = (AbstractObjectNode)nodes.get(i);
         n.draw(g2);
      }

		//CHECKING relationship. HAve to draw all node first
		//before checking otherwise it wouldn't
		//find the points to draw the arrow
	   for(int j=0; j<nodes.size(); j++)
	   {
	  	   AbstractObjectNode n2 = (AbstractObjectNode)nodes.get(j);
	 	   for (int k = 1; k< nodes.size(); k++)
	 	   {
		  	   AbstractObjectNode temp3 = (AbstractObjectNode)nodes.get(k);
	 		   ObjectNode t1 = (ObjectNode)temp3;
            Color c = g2.getColor();
            g2.setColor(Color.red);
	 		   if (n2 != t1 )
	 		   {
			   	if(n2.getRelationship(t1)==SUPERCLASS)
	 			   {
				   	TriangleEdge edge = new TriangleEdge();
	 				   edge.connect(n2, t1);
	 				   edge.draw(g2);
	 			   }
	 			   else if(n2.getRelationship(t1)==INTERFACE)
	 			   {
					   DashedTriangleEdge edge =new DashedTriangleEdge();
	 				   edge.connect(n2,t1);
	 				   edge.draw(g2);
	 			   }
	 			   else if(n2.getRelationship(t1)==ATTRIBUTE)
	 			   {
	 				   DiamondEdge edge =new DiamondEdge();
	 				   edge.connect(n2,t1);
	 				   edge.draw(g2);
	 			   }
	    	   }
            g2.setColor(c);
		   }
	   }
   }

   // The arraylist containing all the object nodes
   private ArrayList nodes;
   // Indicating a super class
   private final int SUPERCLASS = 1;
   // Indicating an interface
   private final int INTERFACE = 2;
   // Indicating a "has-a" relationship
   private final int ATTRIBUTE = 3;
   // The point which was last clicked at
   private Point lastMousePoint;
}
