import java.awt.geom.Path2D;
import java.awt.geom.AffineTransform;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.*;

public class GSpring extends Spring implements Draggable {
   private static final double xPoints[]={0,0.10, 0.125, 0.175, 0.225, 0.275, 0.325, 
                                          0.375, 0.425, 0.475, 0.525,0.575,0.625,
                                          0.675,0.725,0.775,0.825,0.875, 0.90,1.0};
   private static final double yPoints[]={0,0,-0.1,0.1,-0.1,0.1,-0.1,0.1,-0.1,0.1,
                                          -0.1,0.1,-0.1,0.1,-0.1,0.1,-0.1,0.1,0,0};
   private static final Path2D.Double polyline = 
                      new Path2D.Double(Path2D.WIND_EVEN_ODD,xPoints.length);
   private Path2D.Double shape;
   private Color color = Color.BLACK;
   private Vector2D graphicsPosA =null;  // to draw a spring we need
   private Vector2D graphicsPosB =null;  // extremes well definied 
                                      // when it is not connected
   
   static {  // static initialization block
      polyline.moveTo (xPoints[0], yPoints[0]);
      for (int index = 1; index < xPoints.length;index++)
         polyline.lineTo(xPoints[index], yPoints[index]);
   }
   public GSpring(float restLength, float stiffness) {
      super(restLength, stiffness);
      graphicsPosA = new Vector2D(0,restLength);
      graphicsPosB = new Vector2D(restLength,restLength);      
      AffineTransform at = AffineTransform.getTranslateInstance(0,0);
      Vector2D v = getVector();
      at.rotate(v.getX(), v.getY());
      at.scale(v.module(), restLength*restLength/v.module());
      shape = (Path2D.Double) at.createTransformedShape(polyline);
   }
      
   public void draw (Graphics2D g){
      Vector2D a=getPositionA();
      double ax = a.getX();
      double ay = a.getY();
      Vector2D v = getVector();
      AffineTransform at = AffineTransform.getTranslateInstance(ax, ay);
      at.rotate(v.getX(), v.getY());
      at.scale(v.module(), restLength*restLength/v.module());
      shape = (Path2D.Double) at.createTransformedShape(polyline);
      g.setColor(color);
      g.draw(shape);
   }
   public boolean contains(double x, double y){
      return shape.contains(x,y);
   }
   public void drag(double x, double y){
      Vector2D a=getPositionA();
      Vector2D b=getPositionB();
      double da = Math.abs(a.getX()-x)+Math.abs(a.getY()-y); // distance to a
      double db = Math.abs(b.getX()-x)+Math.abs(b.getY()-y); // distance to a
      if (da < db) {
         detachBlock_a();
         graphicsPosA.moveTo(x,y);
      }
      else {
         detachBlock_b();
         graphicsPosB.moveTo(x,y);
      }
   }
   public Vector2D getPositionA() {
      Vector2D p = super.getPositionA();
      if (p != null) 
         return p;
      else
         return graphicsPosA;
   }
   public Vector2D getPositionB() {
      Vector2D p = super.getPositionB();
      if (p != null) 
         return p;
      else
         return graphicsPosB;
   }
   public void updateState(){
      if (block_a==null && block_b==null) return;
      if (block_a!=null) {
         Vector2D v = getVector().unitary().times(restLength);
         graphicsPosB = getPositionA().plus(v);
         return;
      }
      if (block_b!=null) {
         Vector2D v = getVector().unitary().times(restLength);
         graphicsPosA = getPositionB().minus(v);
         return;
      }
         
   }
   public void attachNearElement(double x, double y, BlockSpringConfiguration bsc){
      Vector2D a=getPositionA();
      if ((a.getX()==x) && (a.getY()==y)) {
         GBlock block = bsc.findBlock(x,y);
         if (block!=null) attachBlock_a(block);
         else 
         return;
      }
      Vector2D b=getPositionB();
      if ((b.getX()==x) && (b.getY()==y))  {
         GBlock block = bsc.findBlock(x,y);
         if (block!=null) attachBlock_b(block);
         return;
      }
   }
   public void setSelectedColor() {
      color = Color.RED;
   }
   public void setDefaultColor() {
      color = Color.BLACK;
   }
}