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 GeneralPath transition_path = new GeneralPath();
	
    private boolean     			selected;
    private String					id_start_obj = null;
    private String					id_end_obj = null;
	
	/******************/
   
//    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 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() 
    {
    	
    }
    
    public TransitionObj(ChartObj obj1, ChartObj obj2, String type) 
    { 
    	this.startOnj = obj1;
    	this.endOnj = obj2;
    	this.type_transition = type;
    	
    	
    	this.id_start_obj = obj1.getID();
    	this.id_end_obj = obj2.getID();
    	
    }
    
    /*****************************************************************************/
    
    public void setTypeTransition(String val) { type_transition = val; }
    
    public void setSelected(Boolean val) {selected = val; }
    
    public void setIDStartObj(String val) {id_start_obj = val; }
    
    public String getIDStartObj() {return id_start_obj; }
        
    public void setIDEndObj (String val) {id_end_obj = val; }

    public String getIDEndObj() {return id_end_obj; }
    
    /*****************************************************************************/
    
    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";

    	// couloeur 
		if( selected == true)
		{
			 g2.setColor(Color.RED);
		}
		else
		{	
			 g2.setColor(Color.BLACK);
		}
    	
    	GeneralPath path = new GeneralPath();
    	
    	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);
    	}
    	
    	// sauvegarde
    	transition_path = 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;
    }
    
    
    public boolean detection_transistion(int x, int y)
    {
    	
    	BasicStroke bs = new BasicStroke(10);
        
        if(bs.createStrokedShape(transition_path).contains(new Point2D.Double(x,y)))
        {
        	return true;
        }

        return false;
    }

    public boolean isSelected() { return selected; }
    public void setSelected(boolean val) { selected = val; }
    public void toggleSelected() { selected = !selected; }
       
    
    public void saveTo(PrintWriter aFile) 
    {
    	aFile.println("label");
    	aFile.println( type_transition );
        aFile.println( id_start_obj );
        aFile.println( id_end_obj );
        aFile.println(selected);
    }
   
    public static TransitionObj loadFrom(BufferedReader aFile) throws IOException 
    {
    	
    	TransitionObj   obj = new TransitionObj();
    	
    	String  aLabel = aFile.readLine();
    	obj.setTypeTransition(aFile.readLine());
    	obj.setIDStartObj(aFile.readLine());
    	obj.setIDEndObj(aFile.readLine());
    	obj.setSelected(Boolean.valueOf(aFile.readLine()).booleanValue());
    	
        // graph_chart_obj.
        
        //ChartObj   start =   findObjNamed(aqw);
        
        //xxxobj.setSelected(Boolean.valueOf(aFile.readLine()).booleanValue());
        
        //Node    start = new Node("TEMP");
        //Node    end = new Node("TEMP");

        //start.setLocation(Integer.parseInt(aFile.readLine()), Integer.parseInt(aFile.readLine()));
        //end.setLocation(Integer.parseInt(aFile.readLine()),  Integer.parseInt(aFile.readLine()));

        //recherche l'objet en fonction de son ID
        
        //obj = new EdgeObj(aLabel, start, end);
        
        //obj.setSelected(Boolean.valueOf(aFile.readLine()).booleanValue());

        return obj;
    }
    
   
    
}
