package alfredo.sprite;

import alfredo.geom.Intersection;
import alfredo.geom.Line;
import alfredo.geom.Point;
import alfredo.geom.Polygon;
import alfredo.input.Keys;

/**
 * A Force is a specialized object for sprite movement. It allows a Bounds object to move exactly to another Bounds object
 * based on a preexisting force. This is mainly for accurate collisions.
*/
public class Force {
    Line[] vectors;
    Point center; //The "new" center of the Force; e.g. the location that becomes a Bounds' location when apply() is called
    Bounds handle;
    
    public Force(Bounds bounds, float dx, float dy) {
        Point[] points = bounds.bounds.copyPoints();
        vectors = new Line[points.length];
        for(int i = 0; i < vectors.length; i++) {
            vectors[i] = new Line(points[i], points[i].getTranslation(dx, dy));
        }
        center = bounds.getPosition().getTranslation(dx, dy);
        
        handle = bounds; //The handle that this Force can be applied to.
    }
    
    /**
     * Simply initializes a Force object for use with a certain Bounds but does not actually create an applicable force.
     * @param bounds The relevant Bounds object.
     */
    public Force(Bounds bounds) {
        handle = bounds;
        vectors = new Line[bounds.bounds.points.length];
        for(int i = 0; i < vectors.length; i++) {
            vectors[i] = new Line();
        }
        center = new Point();
    }
    
    private static boolean equalPoints(Point a, Point b) {
        return (Math.abs(a.x - b.x) < 0.0001) && (Math.abs(a.y - b.y) < 0.0001);
    }
    
    /**
     * Causes the Force to "interact" with a Bounds.
     * 
     * Essentially, what this does is checks to see how the Force would cause its handle Bounds to
     * intersect with the specified Bounds object. If it would go inside it, (not having *originated*
     * inside it, of course) then the Force will modify itself to prevent that from happening.
     * 
     * Basically, if a Bounds has a Force applied that has interacted with other Bounds objects, the
     * applied Bounds will have accurate collisions to the extent of direction x/y movement.
     * 
     * It does not, however, interact in terms of other forces, including rotations and gravity.
     * @param b The Bounds to do an interaction with.
     * @return Whether the Force was modified - essentially, whether the parent bounds *is* in fact now "touching" the other object.
     */
    public boolean interact(Bounds b) {
        Polygon p = b.bounds; //Handle for convenience (compiler plz optimize)
        
        Intersection check = new Intersection(); //Passed to Line.intersects() because the intersection point is required for shifting the Force backwards
        boolean modified = false;
        
        for(Line vector : vectors) { //Iterate through lines to check for intersections
            for(Line pLine : p.lines) {
                if(vector.intersects(pLine, check)) { //The force is causing the parent Bounds to move into the new Bounds; take corrective action!
                    //Shorten the Force so that the interaction is pushed back; essentially, move *this* Line's point back
                    //to the intersection point with the other Bounds, and move all others back by an equal amount
                    if(check.type == Intersection.TYPE_POINT) { //Only modify if Intersection is point
                        float dx = check.point.x - vector.end.x;
                        float dy = check.point.y - vector.end.y;
                        for(Line l : vectors) { l.end.translate(dx, dy); } //Translate all lines for future interactions
                        center.translate(dx, dy); //translate the center
                        modified = true;
                    }
                }
            }
        }
        return modified;
    }
    
    /**
     * Applies the force to the Bounds object, causing it to take the new Position determined by the Force.
     */
    public void apply() {
        handle.setLocalPosition(center);
    }
    
    /**
     * Causes the Force, using its old handle as the parent, to load itself with updated positions of its
     * parent so that it can be used for interaction again.
     * 
     * This prevents having to allocate new memory for new Points and new Lines.
     * @param dx The new x translation.
     * @param dy The new y translation.
     */
    public void reforce(float dx, float dy) {
        for(int i = 0; i < vectors.length; i++) {
            vectors[i].start.copyFrom(handle.bounds.points[i]);
            handle.bounds.points[i].getTranslation(dx, dy, vectors[i].end);
        }
        handle.getPosition().getTranslation(dx, dy, center);
    }
}
@@ -550,24 +550,99 @@
 andle;%0A    %0A
+    float x, y; //The amount of x, y force that the Force is applying%0A    %0A
     public F
@@ -675,32 +675,32 @@
 dx, float dy) %7B%0A
-
         Point%5B%5D 
@@ -1063,16 +1063,57 @@
 ied to.%0A
+        %0A        x = dx;%0A        y = dy;%0A
     %7D%0A  
@@ -2693,32 +2693,433 @@
 imize)%0A        %0A
+        float checkdx = b.getLocalX() - handle.getLocalX(); //TODO: Fix all local/global position problems!%0A        float checkdy = b.getLocalY() - handle.getLocalY();%0A        %0A        //If the bounds interacting is in the opposite direction, don't interact%0A        if(((checkdx %3E 0) != (x %3E 0)) && ((checkdy %3E 0) != (y %3E 0))) %7B return false; %7D%0A        //Should this be done with trig maybe?%0A        %0A
         Intersec
@@ -4241,16 +4241,82 @@
  center%0A
+                        x += dx;%0A                        y += dy;%0A
         
@@ -5239,32 +5239,32 @@
 end);%0A        %7D%0A
-
         handle.g
@@ -5304,19 +5304,60 @@
 y, center);%0A
+        %0A        x = dx;%0A        y = dy;%0A
     %7D%0A%7D

Make Force better (?)