package gizmoball.game;

import java.util.*;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

import physics.*;

/**
 * Unit tests for the polygonal gizmos
 *
 * @author <a href="mailto:amdragon@mit.edu">Austin Clements</a>
 * @version $Id: PolygonalGizmoTest.java,v 1.2 2004/04/28 02:51:52 amthrax Exp $
 */
public class PolygonalGizmoTest extends TestCase {
    private static final double TOLERANCE = 0.01;

    BallGizmo ball;

    /**
     * A test bumper that's meant to have its geometry set by the test
     * cases.
     */
    private class TestBumper extends AbstractGizmoWithPolygonalGeometry {
        public TestBumper() {
            super("Test Bumper", Vect.ZERO);
        }

        public boolean tick(double time) {
            return false;
        }

        public void fireTrigger(AbstractTrigger trigger) {
        }
    }

    public PolygonalGizmoTest(String name) {
        super(name);
    }

    public static Test suite() {
        return new TestSuite(PolygonalGizmoTest.class);
    }

    protected void setUp() {
        ball = new BallGizmo();
        ball.setPosition(new Vect(0, -1 - ball.getCircle().getRadius()));
        ball.setVelocity(new Vect(0, 1));
    }

    public void testCollidabilitiy() {
        TestBumper tb1 = new TestBumper();

        // Use a triangular geometry with apex at origin
        tb1.setGeometry(new Vect[]
            {new Vect(0,0), new Vect(1,1), new Vect(-1,1)});

        // Test collidability
        assertEquals(Collidability.NEVER_COLLIDE,
                     tb1.canCollideWith(new TestBumper()));
        assertEquals(Collidability.CAN_COLLIDE, tb1.canCollideWith(ball));
    }

    public void testPointCollision() {
        TestBumper tb1 = new TestBumper();

        // Use a triangular geometry with apex at origin
        tb1.setGeometry(new Vect[]
            {new Vect(0,0), new Vect(1,1), new Vect(-1,1)});

        // Test time
        assertEquals(1.0, tb1.timeUntilCollisionWith(ball), TOLERANCE);

        // Test collision
        ball.setPosition(new Vect(0, - ball.getCircle().getRadius()));
        tb1.collide(ball);
        assertEquals(0.0, ball.getVelocity().x(), TOLERANCE);
        assertEquals(-1.0, ball.getVelocity().y(), TOLERANCE);
    }

    public void testFaceCollision() {
        TestBumper tb1 = new TestBumper();

        // Use a triangular geometry with horizontal face at origin
        tb1.setGeometry(new Vect[]
            {new Vect(-1,0), new Vect(1,0), new Vect(0,1)});

        // Test time
        assertEquals(1.0, tb1.timeUntilCollisionWith(ball), TOLERANCE);

        // Test collision
        ball.setPosition(new Vect(0, - ball.getCircle().getRadius()));
        tb1.collide(ball);
        assertEquals(0.0, ball.getVelocity().x(), TOLERANCE);
        assertEquals(-1.0, ball.getVelocity().y(), TOLERANCE);
    }

    public void testAngledFaceCollision() {
        TestBumper tb1 = new TestBumper();

        // Use a triangular geometry with horizontal face at origin
        double offset = ball.getCircle().getRadius()/Math.sqrt(2);
        tb1.setGeometry(new Vect[]
            {new Vect(1+offset,-1+offset),
             new Vect(1+offset,1+offset),
             new Vect(-1+offset, 1+offset)});
        ball.setPosition(new Vect(0, -1));

        // Test time
        assertEquals(1.0, tb1.timeUntilCollisionWith(ball), TOLERANCE);

        // Test collision
        ball.setPosition(new Vect(0, 0));
        tb1.collide(ball);
        assertEquals(-1.0, ball.getVelocity().x(), TOLERANCE);
        assertEquals(0.0, ball.getVelocity().y(), TOLERANCE);
    }

    public void testRotation() {
        TestBumper tb1 = new TestBumper();

        // Use a triangular geometry with apex at origin
        tb1.setGeometry(new Vect[]
            {new Vect(0,0), new Vect(1,1), new Vect(-1,1)});

        Vect[] vs = tb1.getGeometry();
        assertEquals(3, vs.length);
        assertEquals(new Vect(0,0), vs[0]);
        assertEquals(1, vs[1].x(), TOLERANCE);
        assertEquals(1, vs[1].y(), TOLERANCE);
        assertEquals(-1, vs[2].x(), TOLERANCE);
        assertEquals(1, vs[2].y(), TOLERANCE);

        tb1.setOrientation(Angle.DEG_45);
        vs = tb1.getGeometry();
        assertEquals(3, vs.length);
        assertEquals(new Vect(0,0), vs[0]);
        assertEquals(0, vs[1].x(), TOLERANCE);
        assertEquals(Math.sqrt(2), vs[1].y(), TOLERANCE);
        assertEquals(-Math.sqrt(2), vs[2].x(), TOLERANCE);
        assertEquals(0, vs[2].y(), TOLERANCE);
    }
}
