/*
Violet - A program for editing UML diagrams.

Copyright (C) 2002 Cay S. Horstmann (http://horstmann.com)

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

package com.horstmann.violet.framework;

import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RectangularShape;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;


/**
   A node that has a rectangular shape.
*/
public abstract class RectangularNode extends AbstractNode
{
   public Object clone()
   {
      RectangularNode cloned = (RectangularNode)super.clone();
      cloned.bounds = (Rectangle2D)bounds.clone();
      return cloned;
   }

   public void translate(double dx, double dy)
   {
      bounds.setFrame(bounds.getX() + dx,
         bounds.getY() + dy, 
         bounds.getWidth(), 
         bounds.getHeight());
      super.translate(dx, dy);
   }

   public boolean contains(Point2D p)
   {
      return bounds.contains(p);
   }

   public Rectangle2D getBounds()
   {
      return (Rectangle2D)bounds.clone();
   }

   public void setBounds(Rectangle2D newBounds)
   {
      bounds = newBounds;
   }

   public void layout(Graph g, Graphics2D g2, Grid grid)
   {
      grid.snap(bounds);
   }

   public Point2D getConnectionPoint(Direction d)
   {
      double slope = bounds.getHeight() / bounds.getWidth();
      double ex = d.getX();
      double ey = d.getY();
      double x = bounds.getCenterX();
      double y = bounds.getCenterY();
      
      if (ex != 0 && -slope <= ey / ex && ey / ex <= slope)
      {  
         // intersects at left or right boundary
         if (ex > 0) 
         {
            x = bounds.getMaxX();
            y += (bounds.getWidth() / 2) * ey / ex;
         }
         else
         {
            x = bounds.getX();
            y -= (bounds.getWidth() / 2) * ey / ex;
         }
      }
      else if (ey != 0)
      {  
         // intersects at top or bottom
         if (ey > 0) 
         {
            x += (bounds.getHeight() / 2) * ex / ey;
            y = bounds.getMaxY();
         }
         else
         {
            x -= (bounds.getHeight() / 2) * ex / ey;
            y = bounds.getY();
         }
      }
      return new Point2D.Double(x, y);
   }

   private void writeObject(ObjectOutputStream out)
      throws IOException
   {
      out.defaultWriteObject();
      writeRectangularShape(out, bounds);
   }

   /**
      A helper method to overcome the problem that the 2D shapes
      aren't serializable. It writes x, y, width and height
      to the stream.
      @param out the stream
      @param s the shape      
   */
   private static void writeRectangularShape(
      ObjectOutputStream out, 
      RectangularShape s)
      throws IOException
   {
      out.writeDouble(s.getX());
      out.writeDouble(s.getY());
      out.writeDouble(s.getWidth());
      out.writeDouble(s.getHeight());
   }

   private void readObject(ObjectInputStream in)
      throws IOException, ClassNotFoundException
   {
      in.defaultReadObject();
      bounds = new Rectangle2D.Double();
      readRectangularShape(in, bounds);
   }
   
   /**
      A helper method to overcome the problem that the 2D shapes
      aren't serializable. It reads x, y, width and height
      from the stream.
      @param in the stream
      @param s the shape whose frame is set from the stream values
   */
   private static void readRectangularShape(ObjectInputStream in,
      RectangularShape s)
      throws IOException
   {
      double x = in.readDouble();
      double y = in.readDouble();
      double width = in.readDouble();
      double height = in.readDouble();
      s.setFrame(x, y, width, height);
   }

   public Shape getShape()
   {
      return bounds;
   }
   
   private transient Rectangle2D bounds;
}
