/*
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.Dimension;
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 javax.swing.JLabel;

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


/**
   A curved edge for a state transition in a state diagram.
*/
public class StateTransitionEdge extends ShapeEdge
{
   /**
      Sets the label property value.
      @param newValue the new value
   */
   public void setLabel(String newValue)
   {
      labelText = newValue;
   }

   /**
      Gets the label property value.
      @return the current value
   */
   public String getLabel()
   {
      return labelText;
   }

   public void draw(Graphics2D g2)
   {
      g2.draw(getShape());
      drawLabel(g2);
      ArrowHead.V.draw(g2, getControlPoint(), getConnectionPoints().getP2());
   }

   /**
      Draws the label.
      @param g2 the graphics context
   */
   private void drawLabel(Graphics2D g2)
   {
      Rectangle2D labelBounds = getLabelBounds(g2);
      double x = labelBounds.getX();
      double y = labelBounds.getY();
      
      g2.translate(x, y);
      label.paint(g2);
      g2.translate(-x, -y);        
   }

   
   /**
      Gets the bounds of the label text 
      @param g2 the graphics context
      @return the bounds of the label text
   */
   private Rectangle2D getLabelBounds(Graphics2D g2)
   {
      Line2D line = getConnectionPoints();
      Point2D control = getControlPoint();
      double x = control.getX() / 2 + line.getX1() / 4 + line.getX2() / 4;
      double y = control.getY() / 2 + line.getY1() / 4 + line.getY2() / 4;

      label.setText("<html>" + labelText + "</html>");
      label.setFont(g2.getFont());
      Dimension d = label.getPreferredSize();
      label.setBounds(0, 0, d.width, d.height);
   
      final int GAP = 3;
      if (line.getY1() == line.getY2())
         x -= d.getWidth() / 2;
      else if (line.getY1() <= line.getY2())
         x += GAP;
      else
         x -= d.getWidth() + GAP;
      if (line.getX1() == line.getX2())
         y += d.getHeight() / 2;
      else if (line.getX1() <= line.getX2())
         y -= d.getHeight() + GAP;
      else
         y += GAP;
      return new Rectangle2D.Double(x, y, d.width, d.height);
   }   

   /**
      Gets the control point for the quadratic spline.
      @return the control point
   */
   private Point2D getControlPoint()
   {
      Line2D line = getConnectionPoints();
      double t = Math.tan(Math.toRadians(angle));
      double dx = (line.getX2() - line.getX1()) / 2;
      double dy = (line.getY2() - line.getY1()) / 2;
      return new Point2D.Double(
         (line.getX1() + line.getX2()) / 2 + t * dy,
         (line.getY1() + line.getY2()) / 2 - t * dx);         
   }
   
   public Shape getShape()
   {
      Line2D line = getConnectionPoints();
      Point2D control = getControlPoint();
      GeneralPath p = new GeneralPath();
      p.moveTo((float)line.getX1(), (float)line.getY1());
      p.quadTo((float)control.getX(), (float)control.getY(), (float)line.getX2(), (float)line.getY2());      
      return p;
   }

   public Rectangle2D getBounds(Graphics2D g2)
   {
      Rectangle2D r = super.getBounds(g2);
      r.add(getLabelBounds(g2));
      return r;
   }
   
   public Line2D getConnectionPoints()
   {
      Direction d1;
      Direction d2;

      if (getStart() == getEnd())
      {
         angle = 60;
         d1 = Direction.EAST.turn(-30);
         d2 = Direction.EAST.turn(30);
      }
      else
      {
         angle = 10;
         Rectangle2D start = getStart().getBounds();
         Rectangle2D end = getEnd().getBounds();
         Point2D startCenter = new Point2D.Double(
            start.getCenterX(),
            start.getCenterY());
         Point2D endCenter = new Point2D.Double(
            end.getCenterX(),
            end.getCenterY());
         d1 = new Direction(startCenter, endCenter).turn(-5);
         d2 = new Direction(endCenter, startCenter).turn(5);
      }
      Point2D p = getStart().getConnectionPoint(d1);
      Point2D q = getEnd().getConnectionPoint(d2);

      return new Line2D.Double(p, q);
   }

   private double angle;
   private String labelText = "";
   
   private static JLabel label = new JLabel();
}
