/*
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;

import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

import com.horstmann.violet.framework.Direction;
import com.horstmann.violet.framework.ShapeEdge;

/**
   An S- or C-shaped edge with an arrowhead.
*/
public class ObjectReferenceEdge extends ShapeEdge
{
   public void draw(Graphics2D g2)
   {
      g2.draw(getShape());
      Line2D line = getConnectionPoints();
      double x1;
      double x2 = line.getX2();
      double y = line.getY2();
      if (isSShaped())
         x1 = x2 - ENDSIZE;
      else
         x1 = x2 + ENDSIZE;
      ArrowHead.BLACK_TRIANGLE.draw(g2, new Point2D.Double(x1, y), 
         new Point2D.Double(x2, y));      
   }

   public Shape getShape()
   {
      Line2D line = getConnectionPoints();

      double y1 = line.getY1();
      double y2 = line.getY2();
      double xmid = (line.getX1() + line.getX2()) / 2;
      double ymid = (line.getY1() + line.getY2()) / 2;
      GeneralPath p = new GeneralPath();
      if (isSShaped())
      {
         double x1 = line.getX1() + ENDSIZE;
         double x2 = line.getX2() - ENDSIZE;
         
         p.moveTo((float)line.getX1(), (float)y1);
         p.lineTo((float)x1, (float)y1);
         p.quadTo((float)((x1 + xmid) / 2), (float)y1, (float)xmid, (float)ymid);
         p.quadTo((float)((x2 + xmid) / 2), (float)y2, (float)x2, (float)y2);
         p.lineTo((float)line.getX2(), (float)y2);
      }
      else // reverse C shaped
      {
         double x1 = Math.max(line.getX1(), line.getX2()) + ENDSIZE;
         double x2 = x1 + ENDSIZE;
         p.moveTo((float)line.getX1(), (float)y1);
         p.lineTo((float)x1, (float)y1);
         p.quadTo((float)x2, (float)y1, (float)x2, (float)ymid);
         p.quadTo((float)x2, (float)y2, (float)x1, (float)y2);
         p.lineTo((float)line.getX2(), (float)y2);
      }
      return p;
   }

   public Line2D getConnectionPoints()
   {
      Rectangle2D b = getEnd().getBounds();
      Point2D p = getStart().getConnectionPoint(Direction.EAST);
      if (isSShaped())
         return new Line2D.Double(p, getEnd().getConnectionPoint(Direction.WEST));
      else 
         return new Line2D.Double(p, getEnd().getConnectionPoint(Direction.EAST));
   }

   /**
      Tests whether the node should be S- or C-shaped.
      @return true if the node should be S-shaped
   */
   private boolean isSShaped()
   {
      Rectangle2D b = getEnd().getBounds();
      Point2D p = getStart().getConnectionPoint(Direction.EAST);
      return b.getX() >= p.getX() + 2 * ENDSIZE;
   }

   private static final int ENDSIZE = 10;
}
