import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.Point2D;
import java.util.Vector;


public class LoopbackObj 
{
	   private Vector<Point> stateBorderPts;
	   public Point startPt, endPt, startCtrlPt,endCtrlPt;
	   private int startStateIndex,endStateIndex;
	   private CubicCurve2D.Double loop;
	   private  double alpha;
	   public String label;
	 
       double angleStart;
       double angleEnd; 
	   
	   private boolean	selected = false;
	   
	   private int selectStatus = 0;
	   public int NONE = 0;
	   public static final int START = 1;
	   public static final int STARTCTRL = 2;
	   public static final int ENDCTRL = 3;
	   public static final int END = 4;
	   
	   private int xTemp, yTemp, tempSI,tempEI,lengthS,lengthE;
	   private double ctrlAngleS, ctrlAngleE;
	   
	   int x = 0;
	   int y = 0;
	   int x0  = 0;
	   int y0  = 0;
	   int x1  = 0;
	   int y1 =  0;
	   
	   int[] xP =  {0,0,0}; 
       int[] yP = {0,0,0}; 
       
       public LoopbackObj()
	   {
	   }
    	   
	   public LoopbackObj(String alabel, int x, int y, int x0, int y0, int x1, int y1)
	   {
		   
		   this.label = alabel;
		   this.x = x;
		   this.y = y;
		   this.x0 = x0;
		   this.y0 = y0;
		   this.x1 = x1;
		   this.y1 = y1;
		   selected = false;
		   
		   setEndPts(x,y);
	       loop = new CubicCurve2D.Double(startPt.getX(),startPt.getY(),startCtrlPt.getX(),startCtrlPt.getY(),endCtrlPt.getX(),endCtrlPt.getY(),endPt.getX(),endPt.getY());
	 
	       alpha = getAngle(endCtrlPt,endPt);
	       
	       double adj = Math.PI/6;

	       int[] temp_x = {(int)endPt.getX(),(int)endPt.getX() + (int)(13*Math.cos(alpha + adj)),(int)endPt.getX() + (int)(13*Math.cos(alpha - adj))};
	       int[] temp_y = {(int)endPt.getY(),(int)endPt.getY() - (int)(13*Math.sin(alpha + adj)),(int)endPt.getY() - (int)(13*Math.sin(alpha - adj))};
      
		   this.xP = temp_x; 
		   this.yP = temp_y; 
		   
	   }
	   
	   public void setLabel(String newLabel) 
	   { 
		   label = newLabel; 
	   }
	   
	   public CubicCurve2D.Double get_loop()
	   {
		   return loop;
	   }
	   
	   public int[] get_array_xP()
	   {
		   return xP;
	   }
	   
	   public int[] get_array_yP()
	   {
		   return yP;
	   }
	   
	   private void setEndPts(int x, int y)
	   {
	        //find start point on oval closest to click point
	        stateBorderPts = getBorderPts();
	        Point createPt = new Point(x,y);
	        double temp;
	        double max = 1000000;
	        for(int i = 0; i < 36; i++)
	        {
	            temp = createPt.distanceSq(stateBorderPts.get(i));
	            if (temp < max)
	            {
	                startStateIndex = i;
	                max = temp;
	            }
	        }

	        // store two points on oval
	        startPt = stateBorderPts.get(startStateIndex);
	        endStateIndex = startStateIndex + 5;
	        if(endStateIndex > 35)
	            endStateIndex = endStateIndex - 36;
	        endPt = stateBorderPts.get(endStateIndex);

	        //angle control points are from points on oval
	        //double 
	        angleStart = startStateIndex*2*Math.PI/36;
	        angleEnd = endStateIndex*2*Math.PI/36;


	        //find distance from points on oval to control point
	        int dist = (int) Math.sqrt(get_size());

	        //scaling
	        dist = (int) (dist*.65);

	        //set up control points
	        startCtrlPt = new Point();
	        endCtrlPt = new Point();
	        startCtrlPt.setLocation((int) (dist*Math.cos(angleStart)) + startPt.getX(), dist*Math.sin(angleStart) + startPt.getY());
	        endCtrlPt.setLocation((int) (dist*Math.cos(angleEnd)) + endPt.getX(), dist*Math.sin(angleEnd) + endPt.getY());


	    }
	   
	   public Vector<Point> getBorderPts() 
	    {
	        Vector<Point> borderPts = new Vector<Point>(36);
	        
	        int w = x1 - x0;
	        int h = y1 - y0;
	        
	        for (int i = 0; i < 36; i++)
	        {
	            int x = (int) ((x0 + w / 2) + (w / 2)  * Math.cos((double) (2 * Math.PI / 36) * i));
	            int y = (int) ((y0 + h / 2) + (h / 2)  * Math.sin((double) (2 * Math.PI / 36) * i));
	            Point coord = new Point(x, y);
	            borderPts.add(i, coord);
	        }
	        
	        return borderPts;
	    }  
	
	   public int get_size() 
	   {
	        int a = (x1 - x0) * (y1 - y0);
	        System.out.println(" --------- " + a );  
		     
	        return a;
	   }
	   
	   
	   public double getAngle(Point outer, Point inner)
	   {
	       int dx = (int) outer.getX() - (int) inner.getX();
	       int dy = -((int) outer.getY() - (int) inner.getY());
	       double alpha = 0;

	       if(dx == 0)
	       {
	           if(dy <= 0)
	               alpha = 3*Math.PI/2;
	           else
	               alpha = Math.PI/2;
	       }
	       //1st q
	       else if (dx > 0 && dy > 0)
	           alpha = Math.atan((double) dy/dx);
	       //4th q
	       else if (dx > 0 && dy <= 0)
	       {
	           if(dy == 0)
	               alpha = 0;
	           else
	               alpha = 2*(Math.PI) + Math.atan((double) dy/(dx));
	       }
	       //2nd, 3rd q
	       else if (dx < 0)
	           alpha = (Math.PI)+ Math.atan((double) dy/dx);
	       return alpha;
	   }
	   
	   public void LooptoggleSelected() 
	   { 
		   selected = !selected; 
			System.out.println("Transaction selected " + selected);
	   }

	   
/*	   
	   public void draw_loopback(Graphics2D g2D, int x0, int y0, int x1, int y1)
	    {
	          
	    	int x_ = 0; //500;
	      	int y_ = 1; // 307;
	            
	      	Loopback obj_loop = new Loopback( x_,  y_,  x0,  y0,  x1,  y1);
	    	
	        //setEndPts(x_,y_);
	        //loop = new CubicCurve2D.Double(startPt.getX(),startPt.getY(),startCtrlPt.getX(),startCtrlPt.getY(),endCtrlPt.getX(),endCtrlPt.getY(),endPt.getX(),endPt.getY());
	        g2D.setColor(Color.BLACK);
	        
	        
	        g2D.draw( obj_loop.get_loop());
	        
	        g2D.drawOval(x0, y0, x1 - x0, y1 - y0);
	        
	        int[] xP = obj_loop.get_array_xP();
	        int[] yP = obj_loop.get_array_yP();
	        
	        g2D.drawPolygon(xP,yP,3);
	        g2D.fillPolygon(xP,yP,3);
	    }
	*/   
	   
	   public void draw_loopback(Graphics2D g2D)
	   {
		   // encre de selection
		   if(selected )
           {
               g2D.setColor(Color.red);
               g2D.fillRect((int)startPt.getX()-3,(int)startPt.getY()-3,7,7);
               g2D.fillRect((int)endPt.getX()-3,(int)endPt.getY()-3,7,7);
               g2D.fillRect((int)startCtrlPt.getX()-3,(int)startCtrlPt.getY()-3,7,7);
               g2D.fillRect((int)endCtrlPt.getX()-3,(int)endCtrlPt.getY()-3,7,7);
               g2D.drawLine((int)startPt.getX(),(int)startPt.getY(),(int)startCtrlPt.getX(),(int)startCtrlPt.getY());
               g2D.drawLine((int)endPt.getX(),(int)endPt.getY(),(int)endCtrlPt.getX(),(int)endCtrlPt.getY());
           }
	       
		   // affiche la boucle
           g2D.setColor(Color.BLACK);
           
           // pour le debug
           loop = new CubicCurve2D.Double(startPt.getX(),startPt.getY(),startCtrlPt.getX(),startCtrlPt.getY(),endCtrlPt.getX(),endCtrlPt.getY(),endPt.getX(),endPt.getY());
	       /*
           System.out.println( " ** "  + 
					startPt.getX() + " " +
					startPt.getY() + " " +
					endPt.getX() + " " +
					endPt.getY()
					);  
           */
           g2D.draw( loop);

           // recalculer  les points de la fléche
           double alpha = getAngle(endCtrlPt,endPt);
           double adj = Math.PI/6;
           int[] xP = {(int)endPt.getX(),(int)endPt.getX() + (int)(13*Math.cos(alpha + adj)),(int)endPt.getX() + (int)(13*Math.cos(alpha - adj))};
           int[] yP = {(int)endPt.getY(),(int)endPt.getY() - (int)(13*Math.sin(alpha + adj)),(int)endPt.getY() - (int)(13*Math.sin(alpha - adj))};
           
           // affiche la fléche
           g2D.drawPolygon(xP,yP,3);
           g2D.fillPolygon(xP,yP,3);
	   }
	   
	   /*
	   public boolean detection_point_loopback(int x, int y) 
	   {
		   selectStatus = NONE;
		   
		   //check control points
           if(startPt.getX()-x <= 4 && startPt.getX()-x >= -4 && startPt.getY()-y <= 4 && startPt.getY()-y >= -4)
               selectStatus = START;
           if(startCtrlPt.getX()-x <= 4 && startCtrlPt.getX()-x >= -4 && startCtrlPt.getY()-y <= 4 && startCtrlPt.getY()-y >= -4)
               selectStatus = STARTCTRL;
           if(endCtrlPt.getX()-x <= 4 && endCtrlPt.getX()-x >= -4 && endCtrlPt.getY()-y <= 4 && endCtrlPt.getY()-y >= -4)
               selectStatus = ENDCTRL;
           if(endPt.getX()-x <= 4 && endPt.getX()-x >= -4 && endPt.getY()-y <= 4 && endPt.getY()-y >= -4)
               selectStatus = END;
          
        	   
        	if(selectStatus == NONE)
                   return false;
            else
                   return true;
        	  
	   }
	   */
	   
	   public void calculationLoopbackObj(int xcentre, int ycentre)
	   {
           int radius = 50;
           
           x = xcentre;
		   y = ycentre;
           x0  = xcentre - radius;
           y0  = ycentre - radius;
           x1  = xcentre + radius;
           y1 =  ycentre + radius;
		   
		   setEndPts(x,y);
	       loop = new CubicCurve2D.Double(startPt.getX(),startPt.getY(),startCtrlPt.getX(),startCtrlPt.getY(),endCtrlPt.getX(),endCtrlPt.getY(),endPt.getX(),endPt.getY());
	       
	       //System.out.println("Draw interactif " + xcentre + " " + ycentre + " " + startPt.getX() + " " + startPt.getY() + " " + endPt.getX() + "  " + endPt.getY() );  
	       
	       alpha = getAngle(endCtrlPt,endPt);
	       double adj = Math.PI/6;
	       int[] temp_x = {(int)endPt.getX(),(int)endPt.getX() + (int)(13*Math.cos(alpha + adj)),(int)endPt.getX() + (int)(13*Math.cos(alpha - adj))};
	       int[] temp_y = {(int)endPt.getY(),(int)endPt.getY() - (int)(13*Math.sin(alpha + adj)),(int)endPt.getY() - (int)(13*Math.sin(alpha - adj))};
      
		   this.xP = temp_x; 
		   this.yP = temp_y; 
	   }
	   
	   public void drawing(Graphics2D g2D)
	   {
	        
		   if(selected == true)
           {
               g2D.setColor(Color.red);
               g2D.fillRect((int)startPt.getX()-3,(int)startPt.getY()-3,7,7);
               g2D.fillRect((int)endPt.getX()-3,(int)endPt.getY()-3,7,7);
               g2D.fillRect((int)startCtrlPt.getX()-3,(int)startCtrlPt.getY()-3,7,7);
               g2D.fillRect((int)endCtrlPt.getX()-3,(int)endCtrlPt.getY()-3,7,7);
               g2D.drawLine((int)startPt.getX(),(int)startPt.getY(),(int)startCtrlPt.getX(),(int)startCtrlPt.getY());
               g2D.drawLine((int)endPt.getX(),(int)endPt.getY(),(int)endCtrlPt.getX(),(int)endCtrlPt.getY());
    	       System.out.println("TRACE LOOP");  
           }
		   
		    g2D.setColor(Color.BLACK);
	        g2D.draw(loop);
	    }
	   
	   	public boolean detection_loop(double x, double y)
	    {
	    	BasicStroke bs = new BasicStroke(10);
	        if(bs.createStrokedShape(loop).contains(new Point2D.Double(x,y)))
	        {
	        	return true;
	        }
	        return false;
	    }
	   	
	    public void adjustPosition(int x, int y, int xcentre, int ycentre) 
	    {
/*
	            if(selectStatus == START)
	            {
	                Point currPt = new Point(x,y);
	                double temp;
	                double max = 1000000;
	                for(int i = 0; i < 36; i++)
	                {
	                    temp = currPt.distanceSq(stateBorderPts.get(i));
	                    if (temp < max)
	                    {
	                        startStateIndex = i;
	                        max = temp;
	                    }
	                }
	                startPt.setLocation(stateBorderPts.get(startStateIndex).getX(),stateBorderPts.get(startStateIndex).getY());
	            }
	            if(selectStatus == STARTCTRL)
	                startCtrlPt.setLocation(x,y);
	            if(selectStatus == ENDCTRL)
	                endCtrlPt.setLocation(x,y);
	            if(selectStatus == END)
	            {
	                Point currPt = new Point(x,y);
	                double temp;
	                double max = 1000000;
	                for(int i = 0; i < 36; i++)
	                {
	                    temp = currPt.distanceSq(stateBorderPts.get(i));
	                    if (temp < max)
	                    {
	                        endStateIndex = i;
	                        max = temp;
	                    }
	                }
	                endPt.setLocation(stateBorderPts.get(endStateIndex).getX(),stateBorderPts.get(endStateIndex).getY());
	            }
*/	            

	            // allow loopback to rotate around state

	    			//Point c = state.getRealCenter(myPage);
	    		
	    			// recalculer les points sur le bord du cercle car le centre à changer
	    	 		stateBorderPts = getBorderPts();
	    	
	    			Point c = new Point(xcentre, ycentre);
		  	    			
	                double initAngle = getAngle(new Point(xTemp, yTemp),c);

	                double currAngle = getAngle(new Point(x,y),c);
	                int step = (int)-Math.round((currAngle-initAngle)/((2*Math.PI)/36));

	                if(step != 0)
	                {
	                    startStateIndex = tempSI + step;
	                    endStateIndex = tempEI + step;
	                    if(startStateIndex > 35)
	                        startStateIndex -= 36;
	                    if(endStateIndex > 35)
	                        endStateIndex -= 36;
	                    if(startStateIndex < 0)
	                        startStateIndex += 36;
	                    if(endStateIndex < 0)
	                        endStateIndex += 36;
	                 
	        	        angleStart = startStateIndex*2*Math.PI/36;
	        	        angleEnd = endStateIndex*2*Math.PI/36;

	                    //set up points
	                    startPt = stateBorderPts.get(startStateIndex);
	                    endPt = stateBorderPts.get(endStateIndex);
	                    startCtrlPt.setLocation((int) (lengthS*Math.cos(ctrlAngleS-step*(2*Math.PI/36)) + startPt.getX()), (int)(-lengthS*Math.sin(ctrlAngleS-step*(2*Math.PI/36)) + startPt.getY()));
	                    endCtrlPt.setLocation((int) (lengthE*Math.cos(ctrlAngleE-step*(2*Math.PI/36)) + endPt.getX()), (int)(-lengthE*Math.sin(ctrlAngleE-step*(2*Math.PI/36)) + endPt.getY()));
	                
	                    System.out.println("TRACE");
	                }


	            loop.setCurve(startPt.getX(),startPt.getY(),startCtrlPt.getX(),startCtrlPt.getY(),endCtrlPt.getX(),endCtrlPt.getY(),endPt.getX(),endPt.getY());
	            
	            System.out.println( " ** "  + 
										angleStart + " " + 
										angleEnd   + " " +
	            						startPt.getX() + " " +
	            						startPt.getY() + " " +
	            						startCtrlPt.getX() + " " +
	            						startCtrlPt.getY() + " " +
	            						endCtrlPt.getX() + " " +
	            						endCtrlPt.getY() + " " +
	            						endPt.getX() + " " +
	            						endPt.getY()
	            						);  
	              
	    }
	    	         
	    public void setSelectStatus(int x, int y) 
	    {
	    	xTemp = x;
	        yTemp = y;
	        tempSI = startStateIndex;
	        tempEI = endStateIndex;
	        ctrlAngleS = getAngle(startCtrlPt,startPt);
	        ctrlAngleE = getAngle(endCtrlPt,endPt);
	        lengthS = (int)Math.round(startCtrlPt.distance(startPt));
	        lengthE = (int)Math.round(endCtrlPt.distance(endPt));
	    }
	    
	    
	     
	    public int getLoopStartPtX()
	    {
	    	return	(int) startPt.getX();
	    }
	   
	    public int getLoopStartPtY()
	    {
	    	return	(int) startPt.getY();

	    }
	    
	    public int getLoopEndPtX()
	    {
	    	return	(int) endPt.getX();
	    	
	    }
	   
	    public int getLoopEndPtY()
	    {
	    	return	(int) endPt.getY();

	    }
	  
	    public double getAngleStart()
	    {
	    	return angleStart;
	    }
	  
	    public double getAngleEnd()
	    {
	    	 return angleEnd; 
	    }
	    
	    
	    public void traitement(int xcentre, int ycentre)
		   {
	           int radius = 50;
	           
	           x = xcentre;
			   y = ycentre;
	           //x0  = xcentre - radius;
	           //y0  = ycentre - radius;
	           //x1  = xcentre + radius;
	           //y1 =  ycentre + radius;
	           
	           int start_x = x + 25 ;
	           int start_y = y - 40;
	           int end_x = x + 35;
	           int end_y = y - 30;
	          
		       int dist = (int) Math.sqrt(get_size());

		       //scaling
		       dist = (int) (dist*.65);

		       startPt.setLocation(start_x, start_y);
		       endPt.setLocation(end_x, end_y);
		       
		       
		       startCtrlPt = new Point();
		       endCtrlPt = new Point();
		       startCtrlPt.setLocation((int) (dist*Math.cos(angleStart)) + startPt.getX(), dist*Math.sin(angleStart) + startPt.getY());
		       endCtrlPt.setLocation((int) (dist*Math.cos(angleEnd)) + endPt.getX(), dist*Math.sin(angleEnd) + endPt.getY());
	           
		       //startCtrlPt.setLocation((int) (dist*Math.cos(angleStart)) + start_x, dist*Math.sin(angleStart) + start_y );
		       //endCtrlPt.setLocation((int) (dist*Math.cos(angleEnd)) + end_x, dist*Math.sin(angleEnd) +  end_y);
	           
		       loop = new CubicCurve2D.Double(startPt.getX(),startPt.getY(),startCtrlPt.getX(),startCtrlPt.getY(),endCtrlPt.getX(),endCtrlPt.getY(),endPt.getX(),endPt.getY());
		       
		       
			   //loop = new CubicCurve2D.Double(start_x , start_y,startCtrlPt.getX(),startCtrlPt.getY(),endCtrlPt.getX(),endCtrlPt.getY(),end_x, end_y );
		       
		       alpha = getAngle(endCtrlPt,endPt);
		       double adj = Math.PI/6;
		       int[] temp_x = {(int)endPt.getX(),(int)endPt.getX() + (int)(13*Math.cos(alpha + adj)),(int)endPt.getX() + (int)(13*Math.cos(alpha - adj))};
		       int[] temp_y = {(int)endPt.getY(),(int)endPt.getY() - (int)(13*Math.sin(alpha + adj)),(int)endPt.getY() - (int)(13*Math.sin(alpha - adj))};
	      
			   this.xP = temp_x; 
			   this.yP = temp_y; 
		   }
	
	    
	    public void debug_loop()
	    {
		       int dist = (int) Math.sqrt(get_size());
		       dist = (int) (dist*.65);
		       startCtrlPt = new Point();
		       endCtrlPt = new Point();
		       startCtrlPt.setLocation((int) (dist*Math.cos(angleStart)) + startPt.getX(), dist*Math.sin(angleStart) + startPt.getY());
		       endCtrlPt.setLocation((int) (dist*Math.cos(angleEnd)) + endPt.getX(), dist*Math.sin(angleEnd) + endPt.getY());
		       loop = new CubicCurve2D.Double(startPt.getX(),startPt.getY(),startCtrlPt.getX(),startCtrlPt.getY(),endCtrlPt.getX(),endCtrlPt.getY(),endPt.getX(),endPt.getY());
		       alpha = getAngle(endCtrlPt,endPt);
		       double adj = Math.PI/6;
		       int[] temp_x = {(int)endPt.getX(),(int)endPt.getX() + (int)(13*Math.cos(alpha + adj)),(int)endPt.getX() + (int)(13*Math.cos(alpha - adj))};
		       int[] temp_y = {(int)endPt.getY(),(int)endPt.getY() - (int)(13*Math.sin(alpha + adj)),(int)endPt.getY() - (int)(13*Math.sin(alpha - adj))};
			   this.xP = temp_x; 
			   this.yP = temp_y; 
	    }
	    
	    
	    public void recalculation()
	    {
	    	
	    	   int dist = (int) Math.sqrt( 100 * 100);
		       dist = (int) (dist*.65);
		       startCtrlPt = new Point();
		       endCtrlPt = new Point();
		       startCtrlPt.setLocation((int) (dist*Math.cos(angleStart)) + startPt.getX(), dist*Math.sin(angleStart) + startPt.getY());
		       endCtrlPt.setLocation((int) (dist*Math.cos(angleEnd)) + endPt.getX(), dist*Math.sin(angleEnd) + endPt.getY());
		       loop = new CubicCurve2D.Double(startPt.getX(),startPt.getY(),startCtrlPt.getX(),startCtrlPt.getY(),endCtrlPt.getX(),endCtrlPt.getY(),endPt.getX(),endPt.getY());
		       alpha = getAngle(endCtrlPt,endPt);
		       double adj = Math.PI/6;
		       int[] temp_x = {(int)endPt.getX(),(int)endPt.getX() + (int)(13*Math.cos(alpha + adj)),(int)endPt.getX() + (int)(13*Math.cos(alpha - adj))};
		       int[] temp_y = {(int)endPt.getY(),(int)endPt.getY() - (int)(13*Math.sin(alpha + adj)),(int)endPt.getY() - (int)(13*Math.sin(alpha - adj))};
			   this.xP = temp_x; 
			   this.yP = temp_y; 
	    }
}
