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 Edge_transition 

{
    //public static final int    WIDTH = 7;

    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 Edge_transition(Node_Rectangular n1, Node_Rectangular n2) 
    { 
    	this("", n1, n2); 
    }

    public Edge_transition(String aLabel, Node_Rectangular n1, Node_Rectangular n2) 
    {
    	type_edge = "RECTANGULAR";
    	label = aLabel;
        startNode = n1;
        endNode = n2;
        selected = false;
        equation = "abc..";
        xpos_equation = 0;
    	ypos_equation = 0;

    	shift_text_x = 99;
        shift_text_y = -45;
        
    	
    	manual_startPt = false;
        
    }
  /*  
    public Node_Rectangular getStart()
    {
       return startNode;
    }

    public Node_Rectangular getEnd()
    {
       return endNode;
    }
    */
    
    /*****************************************************************************/
    
    
    public Edge_transition(DecisionObj obj1, DecisionObj obj2, Point p1, Point p2, int indice_start, int indice_end) 
    { 
    	this("", obj1, obj2, p1, p2, indice_start, indice_end); 
    }
    
    
    public Edge_transition(String aLabel, DecisionObj obj1, DecisionObj obj2, Point p1, Point p2, int indice_start, int indice_end) 
    {
    	type_edge = "DECISION";
        label = aLabel;
        startDecision = obj1;
        endDecision = obj2;
        
        this.indice_start = indice_start;
        this.indice_end = indice_end;
        
        selected = false;
        equation = "abc..";
        xpos_equation = 0;
    	ypos_equation = 0;

    	shift_text_x = 99;
        shift_text_y = -45;
        
        ancrage_start = p1;
        ancrage_end = p2;
    	
        
    	manual_startPt = false;
        
    }
 
    
    public Edge_transition(DecisionObj obj1, Node_Rectangular n, Point p1, int indice_start, Point p2) 
    {
    	this("", obj1, n, p1, indice_start, p2 ); 
    }
    
    public Edge_transition(String aLabel, DecisionObj obj1, Node_Rectangular n, Point p1, int indice_start, Point p2) 
    {
    	
    	type_edge = "CONNECTION_MIXTE";
        label = aLabel;
        startDecision = obj1;
        endNode = n;
        this.indice_start = indice_start;
        this.indice_end = 0;
        
        selected = false;
        equation = "abc..";
        
    }
    
    
    
    public void draw(Graphics2D g2)
	{
    	
		//g2.setColor(Color.GREEN);
		//g2.drawLine(startNode.getX1(), startNode.getY1(), endNode.getX1(), endNode.getY1());
		
		
		ArrayList points = getPoints();
	      
	    // Stroke oldStroke = g2.getStroke();
	    //g2.setStroke(lineStyle.getStroke());

		 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 void draw_transistion_decision(Graphics2D g2)
  	{
  		
  		/* ArrayList points = getPoints_decision();

  		 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);*/
    	
    	
    	
    	//ArrayList points = new ArrayList();
    	//points.add(ancrage_start);
    	//points.add(ancrage_end);
    	
    	// g2.drawLine(ancrage_start.x , ancrage_start.y , ancrage_end.x , ancrage_end.y );
    	
    //	ArrayList points = getPoints_decision();

   /* 	
    	 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);
      */	
    	
    	ArrayList points = new ArrayList();
    	Point p2 = new Point();
    	Point p3 = new Point();
    	
    	int pt_startx = ancrage_start.x;
    	int pt_starty = ancrage_start.y;
    	int pt_endx = ancrage_end.x;
    	int pt_endy = ancrage_end.y;

    	// quadrant 
    	if( ancrage_start.x > ancrage_end.x )
    	{
    	
        	if( ancrage_start.y > ancrage_end.y )
        	{
        		
        	}
        	if( ancrage_start.y < ancrage_end.y )
        	{
        		System.out.println("Tartuffe");
        		
        		int xdiff = Math.abs(pt_startx - pt_endx);
            	int ydiff = Math.abs(pt_starty - pt_endy);
            	
            	int xmiddle = xdiff / 2;
            	int ymiddle = ydiff / 2;
            	
            	p2.setLocation(pt_startx, pt_starty + ymiddle);
            	p3.setLocation(pt_endx, pt_endy - ymiddle);
        	}
        	
    		
    	}
    	if( ancrage_start.x < ancrage_end.x )
    	{
    		
    		if( ancrage_start.y > ancrage_end.y )
        	{
        		
        	}
        	if( ancrage_start.y < ancrage_end.y )
        	{
        		System.out.println("Bingo");
        		
        		int xdiff = Math.abs(pt_startx - pt_endx);
            	int ydiff = Math.abs(pt_starty - pt_endy);
            	
            	int xmiddle = xdiff / 2;
            	int ymiddle = ydiff / 2;
            	
            	p2.setLocation(pt_startx, pt_starty + ymiddle);
            	p3.setLocation(pt_endx, pt_endy - ymiddle);
        		
        	}
    	}
    	
    	
    	points.add(ancrage_start);
    	points.add(p2);
    	points.add(p3);
    	points.add(ancrage_end);
    	
    	 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()
    {
    	Rectangle2D start = new Rectangle2D.Double(startNode.getX1(), startNode.getY1(), startNode.getWidth(), startNode.getHeight() );
    	Rectangle2D end = new Rectangle2D.Double(endNode.getX1(), endNode.getY1(), endNode.getWidth(), endNode.getHeight() );
    	
        return getPath( start,  end);
    }
    
   /* 
    public ArrayList<Point2D> getPoints_decision()
    {
    	Rectangle2D start = new Rectangle2D.Double(startNode.getX1(), startNode.getY1(), startNode.getWidth(), startNode.getHeight() );
    	Rectangle2D end = new Rectangle2D.Double(endNode.getX1(), endNode.getY1(), endNode.getWidth(), endNode.getHeight() );
    	
        return getPath( ancrage_start,  ancrage_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;
    }

    /**
       Gets the points at which a line joining two rectangles
       is bent according to a bent style.
       @param start the starting rectangle
       @param end the ending rectangle
       @return an array list of points at which to bend the
       segmented line joining the two rectangles
    */
    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;
    }
    
    
    private GeneralPath getSegmentPath()
    {
       ArrayList points = getPoints();
       
       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());
       }
       return path;
    }
    
    public Node_Rectangular getStartNode() 
    { 
    	return startNode; 
   	}

    public Node_Rectangular getEndNode() 
    { 
    	return endNode; 
   	}
    
    public DecisionObj getStartDecision()
    {
       return startDecision;
    }

    public DecisionObj getEndDecision()
    {
       return endDecision;
    }
    
    public Point get_ancrage_start()
    {
    	return ancrage_start;
    }
    
    public Point get_ancrage_end()
    {
    	return ancrage_end;
    }
    
    public void set_ancrage_start(Point pt)
    {
    	ancrage_start = pt;
    }
    
    public void set_ancrage_end(Point pt)
    {
    	ancrage_end = pt;
    }
    
    
    
    public int get_indice_start()
    {
    	return indice_start;
    }
    
    public int get_indice_end()
    {
    	return indice_end;
    }
    
}
