import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.*;
import java.util.ArrayList;
import java.util.Vector;


public class TransitionObj 
{
	
	private ChartObj	    		startOnj, endOnj;
	private String					type_transition;
	
	/******************/
   
    private String	    			label;
    private String					type_edge;
  //  private Node_Rectangular	    startNode, endNode;
    
    private DecisionObj			    startDecision, endDecision;
    
    private int						indice_start;
    private int						indice_end;
    

    private Point         	    	ancrage_start;
    private Point           	  	ancrage_end;
    
    private boolean     			selected;
    private String					equation;	
    private	int 					xpos_equation;
	private int 					ypos_equation;
    private boolean					manual_startPt;
    private boolean 				config_text_condition;
    
    int text_x = 0;
    int text_y = 0;
    int width_string = 0;
    int height_string = 0;
    
    int shift_text_x = 0;
    int shift_text_y = 0;
    
    boolean shift_text_auto = true;
    boolean shift_text_manual = false;
    
    private static final int MIN_SEGMENT = 10;
    
    String mode_edge = "HVH";
    
    //STRAIGHT, HV, VH, HVH, VHV;

    /*****************************************************************************/
    
    public TransitionObj(ChartObj obj1, ChartObj obj2, String type) 
    { 
    	this.startOnj = obj1;
    	this.endOnj = obj2;
    	this.type_transition = type;
    	
    }
    
    /*****************************************************************************/
    
    public void draw_transition(Graphics2D g2)
	{

    	
//		type_transition = "ONLY_ACTIVITY_OBJ";
//		type_transition = "ACTIVITY_DECISION_OBJ";
//		type_transition = "DECISION_ACTIVITY_OBJ";
//		type_transition = "ONLY_DECISION_OBJ";

    	
    	if(type_transition == "ONLY_ACTIVITY_OBJ")
    	{
	    	ArrayList points = getPoints(1);
			GeneralPath path = new GeneralPath();
		    Point2D p = (Point2D) points.get(points.size() - 1);
		    path.moveTo((float) p.getX(), (float) p.getY());
		     
		    for (int i = points.size() - 2; i >= 0; i--)
		    {
		    	p = (Point2D) points.get(i);
		        path.lineTo((float) p.getX(), (float) p.getY());
		    }
			
		    g2.draw(path);
    	}
    	
    	if(type_transition == "ONLY_DECISION_OBJ")
    	{
    		ArrayList points = getPoints(2);
			GeneralPath path = new GeneralPath();
		    Point2D p = (Point2D) points.get(points.size() - 1);
		    path.moveTo((float) p.getX(), (float) p.getY());
		     
		    for (int i = points.size() - 2; i >= 0; i--)
		    {
		    	p = (Point2D) points.get(i);
		        path.lineTo((float) p.getX(), (float) p.getY());
		    }
			
		    g2.draw(path);
    	}
    	
    	
    	if(type_transition == "ACTIVITY_DECISION_OBJ")
    	{
    		ArrayList points = getPoints(3);
			GeneralPath path = new GeneralPath();
		    Point2D p = (Point2D) points.get(points.size() - 1);
		    path.moveTo((float) p.getX(), (float) p.getY());
		     
		    for (int i = points.size() - 2; i >= 0; i--)
		    {
		    	p = (Point2D) points.get(i);
		        path.lineTo((float) p.getX(), (float) p.getY());
		    }
			
		    g2.draw(path);
    	}
    	
    	
    	if(type_transition == "DECISION_ACTIVITY_OBJ")
    	{
    		ArrayList points = getPoints(4);
			GeneralPath path = new GeneralPath();
		    Point2D p = (Point2D) points.get(points.size() - 1);
		    path.moveTo((float) p.getX(), (float) p.getY());
		     
		    for (int i = points.size() - 2; i >= 0; i--)
		    {
		    	p = (Point2D) points.get(i);
		        path.lineTo((float) p.getX(), (float) p.getY());
		    }
			
		    g2.draw(path);
    	}
    	
	}
    
    public ArrayList<Point2D> getPoints(int type)
    {
    	Rectangle2D start = null;
    	Rectangle2D end = null;
    	
    	if(type == 1)
    	{	
    		 start = new Rectangle2D.Double(startOnj.getX1(), startOnj.getY1(), startOnj.getWidth_Activity(), startOnj.getHeight_Activity() );
    		 end = new Rectangle2D.Double(endOnj.getX1(), endOnj.getY1(), endOnj.getWidth_Activity(), endOnj.getHeight_Activity() );
    	}
    	
    	if(type == 2)
    	{
    		start = new Rectangle2D.Double(startOnj.getP1().getX(), startOnj.getP2().getY() , startOnj.getWidth_Decision(), startOnj.getHeight_Decision() );
        	end = new Rectangle2D.Double(endOnj.getP1().getX(), endOnj.getP2().getY() , endOnj.getWidth_Decision(), endOnj.getHeight_Decision() );
    	}
    	
    	if(type == 3)
    	{
   		 	start = new Rectangle2D.Double(startOnj.getX1(), startOnj.getY1(), startOnj.getWidth_Activity(), startOnj.getHeight_Activity() );
        	end = new Rectangle2D.Double(endOnj.getP1().getX(), endOnj.getP2().getY() , endOnj.getWidth_Decision(), endOnj.getHeight_Decision() );
    	}
    	
    	if(type == 4)
    	{
    		start = new Rectangle2D.Double(startOnj.getP1().getX(), startOnj.getP2().getY() , startOnj.getWidth_Decision(), startOnj.getHeight_Decision() );
    		end = new Rectangle2D.Double(endOnj.getX1(), endOnj.getY1(), endOnj.getWidth_Activity(), endOnj.getHeight_Activity() );
    	}
    	
    	 return getPath( start,  end);
    }
    
 
  
    
    
    public ArrayList<Point2D> getPath(Rectangle2D start, Rectangle2D end)
    {
       ArrayList<Point2D> r = xxx_getPath(mode_edge, start, end);
       if (r != null) return r;

       if (mode_edge == "HVH") r = xxx_getPath("VHV", start, end);
       else if (mode_edge == "VHV") r = xxx_getPath("HVH", start, end);
       else if (mode_edge == "HV") r = xxx_getPath("VH", start, end);
       else if (mode_edge == "VH") r = xxx_getPath("HV", start, end);
       if (r != null) return r;

       //return getPath("STRAIGHT", start, end);
       return null;
    }

   
    private static Point2D[] connectionPoints(Rectangle2D r)
    {
       Point2D[] a = new Point2D[4];
       a[0] = new Point2D.Double(r.getX(), r.getCenterY());
       a[1] = new Point2D.Double(r.getMaxX(), r.getCenterY());
       a[2] = new Point2D.Double(r.getCenterX(), r.getY());
       a[3] = new Point2D.Double(r.getCenterX(), r.getMaxY());
       return a;
    }

   
    private static ArrayList<Point2D> xxx_getPath(String mode_edge,  Rectangle2D s, Rectangle2D e)
    {
       ArrayList<Point2D> r = new ArrayList<Point2D>();
       if (mode_edge == "STRAIGHT")
       {
          Point2D[] a = connectionPoints(s);
          Point2D[] b = connectionPoints(e);
          Point2D p = a[0];
          Point2D q = b[0];
          double distance = p.distance(q);
          //for (int i = 0; i < a.length; i++)
          for (Point2D point1 : a)
             //for (int j = 0; j < b.length; j++)
             for (Point2D point2 : b)
             {
                double d = point1.distance(point2);
                if (d < distance)
                {
                   p = point1; q = point2;
                   distance = d;
                }
             }
          r.add(p);
          r.add(q);
       }
       else if (mode_edge == "HV")
       {
          double x1;
          double x2 = e.getCenterX();
          double y1 = s.getCenterY();
          double y2;
          if (x2 + MIN_SEGMENT <= s.getX())
             x1 = s.getX();
          else if (x2 - MIN_SEGMENT >= s.getMaxX())
             x1 = s.getMaxX();
          else return null;
          if (y1 + MIN_SEGMENT <= e.getY())
             y2 = e.getY();
          else if (y1 - MIN_SEGMENT >= e.getMaxY())
             y2 = e.getMaxY();
          else return null;
          r.add(new Point2D.Double(x1, y1));
          r.add(new Point2D.Double(x2, y1));
          r.add(new Point2D.Double(x2, y2));
       }
       else if (mode_edge == "VH")
       {
          double x1 = s.getCenterX();
          double x2;
          double y1;
          double y2 = e.getCenterY();
          if (x1 + MIN_SEGMENT <= e.getX())
             x2 = e.getX();
          else if (x1 - MIN_SEGMENT >= e.getMaxX())
             x2 = e.getMaxX();
          else return null;
          if (y2 + MIN_SEGMENT <= s.getY())
             y1 = s.getY();
          else if (y2 - MIN_SEGMENT >= s.getMaxY())
             y1 = s.getMaxY();
          else return null;
          r.add(new Point2D.Double(x1, y1));
          r.add(new Point2D.Double(x1, y2));
          r.add(new Point2D.Double(x2, y2));
       }
       else if (mode_edge == "HVH")
       {
          double x1;
          double x2;
          double y1 = s.getCenterY();
          double y2 = e.getCenterY();
          if (s.getMaxX() + 2 * MIN_SEGMENT <= e.getX())
          {
             x1 = s.getMaxX();
             x2 = e.getX();
          }
          else if (e.getMaxX() + 2 * MIN_SEGMENT <= s.getX())
          {
             x1 = s.getX();
             x2 = e.getMaxX();
          }
          else return null;
          if (Math.abs(y1 - y2) <= MIN_SEGMENT)
          {
             r.add(new Point2D.Double(x1, (y1 + y2) / 2));
             r.add(new Point2D.Double(x2, (y1 + y2) / 2));
          }
          else
          {
             r.add(new Point2D.Double(x1, y1));
             r.add(new Point2D.Double((x1 + x2) / 2, y1));
             r.add(new Point2D.Double((x1 + x2) / 2, y2));
             r.add(new Point2D.Double(x2, y2));
          }
       }
       else if (mode_edge == "VHV")
       {
          double x1 = s.getCenterX();
          double x2 = e.getCenterX();
          double y1;
          double y2;
          if (s.getMaxY() + 2 * MIN_SEGMENT <= e.getY())
          {
             y1 = s.getMaxY();
             y2 = e.getY();
          }
          else if (e.getMaxY() + 2 * MIN_SEGMENT <= s.getY())
          {
             y1 = s.getY();
             y2 = e.getMaxY();

          }
          else return null;
          if (Math.abs(x1 - x2) <= MIN_SEGMENT)
          {
             r.add(new Point2D.Double((x1 + x2) / 2, y1));
             r.add(new Point2D.Double((x1 + x2) / 2, y2));
          }
          else
          {
             r.add(new Point2D.Double(x1, y1));
             r.add(new Point2D.Double(x1, (y1 + y2) / 2));
             r.add(new Point2D.Double(x2, (y1 + y2) / 2));
             r.add(new Point2D.Double(x2, y2));
          }
       }
       else return null;
       return r;
    }

    
    public ChartObj getStartObj() 
    { 
    	return startOnj; 
   	}

    public ChartObj getEndObj() 
    { 
    	return endOnj; 
   	}
    
    
    public ChartObj otherEndFrom(ChartObj obj) 
    {
        if (startOnj == obj)
            return endOnj;
        else
            return startOnj;
    }
    
}
