package edu.unca.cs.csci202;

import java.awt.geom.Point2D ;

/**
 *
 * @author J Dean Brock <brock@unca.edu>
 * @author C Jordan Mincey <cmincey@unca.edu>
 */
public class RotatedRectangle implements Iterable<Point2D> {

    private float x;
    private float y;
    private float height;
    private float width;
    private float rotation;
    
    private final static String NEGMESSAGE
            = "Negative values not allowed for height or width" ;
    private final static IllegalArgumentException NEGEXCEPTION
            = new IllegalArgumentException(NEGMESSAGE) ;

    /**
     * Constructor for a rectangle that takes five arguments.
     *
     * @param x x coordinate for the center of the rectangle
     * @param y y coordinate for the center of the rectangle
     * @param width width for the rectangle
     * @param height height for the rectangle
     * @param rotation rotation for the rectangle
     * @throws IllegalArgumentException when height or width is less than zero
     */
    public RotatedRectangle(float x, float y, 
            float width, float height, float rotation)
	throws IllegalArgumentException {
        if (height >= 0.0f && width >= 0.0f) {
            this.x = x;
            this.y = y;
            this.height = height;
            this.width = width;
            this.rotation = rotation;
        } else {
            throw NEGEXCEPTION ;
        }
    }

    /**
     * A four argument constructor of a rectangle.
     *
     * @param x x coordinate for the center of the rectangle
     * @param y y coordinate for the center of the rectangle
     * @param width width for the rectangle
     * @param height height for the rectangle
     * @throws IllegalArgumentException when height or width is less than zero
     */
    public RotatedRectangle(float x, float y, float width, float height)
	throws IllegalArgumentException {
        this(x, y, width, height, 0.0f);
    }

    /**
     * A two argument constructor of a rectangle.
     *
     * @param x x coordinate for the center of the rectangle
     * @param y y coordinate for the center of the rectangle
     */
    public RotatedRectangle(float x, float y) {
        this(x, y, 0.0f, 0.0f, 0.0f);
    }

    /**
     * The no argument constructor that sets all values associated with the
     * rectangle to 0.
     */
    public RotatedRectangle() {
        this(0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
    }
    
    /**
     * Constructor that copies RotatedRectangle
     *
     * @param object RotatedRectangle object to be duplicated
     */
    public RotatedRectangle(RotatedRectangle object) {
        this(object.getX(), object.getY(), object.getWidth(), object.getHeight(), object.getRotation());
    }

    /**
     *
     * @return X coordinate of the center of the rectangle
     */
    public float getX() {
        return x;
    }

    /**
     *
     * @param x New X coordinate for the center of the rectangle
     */
    public void setX(float x) {
        this.x = x;
    }

    /**
     *
     * @return Y coordinate of the center of the rectangle
     */
    public float getY() {
        return y;
    }

    /**
     *
     * @param y New Y coordinate for the center of the rectangle
     */
    public void setY(float y) {
        this.y = y;
    }

    /**
     *
     * @return Width of the rectangle (when rotation is 0)
     */
    public float getWidth() {
        return width;
    }

    /**
     * Sets the width of the rectangle
     *
     * @param width the new width for the rectangle
     * @throws IllegalArgumentException when the value is less than zero
     */
    public void setWidth(float width) throws IllegalArgumentException {
        if (width >= 0) {
            this.width = width;
        } else {
            throw NEGEXCEPTION ;
        }
    }
    
    /**
     *
     * @return Height of the rectangle (when rotation is 0)
     */
    public float getHeight() {
        return height;
    }

    /**
     *
     * @param height New height for the rectangle (when rotation is 0)
     * @throws IllegalArgumentException when the value is less than zero
     */
    public void setHeight(float height) throws IllegalArgumentException {
        if (height >= 0) {
            this.height = height;
        } else {
            throw NEGEXCEPTION;
        }
    }

    /**
     *
     * @return Rotation for the rectangle
     */
    public float getRotation() {
        return rotation;
    }

    /**
     * Sets the rotation for the rectangle in radians.
     *
     * @param rotation new rotation for the rectangle in radians
     */
    public void setRotation(float rotation) {
        this.rotation = rotation;
    }

    /**
     * Sets the new rotation for the rectangle by converting the degrees to radians.
     *
     * @param degrees The rotation in the rectangle in degrees.
     */
    public void setRotation(int degrees) {
        rotation = (float)((Math.PI / 180.0f) * degrees);
    }
    
    
    /**
     * Determines whether or not two RotatedRectangle objects have the
     * same values for each instance variable.
     *
     * @param otherObject the object to be compared
     * @return true when the passed object equals this object in the eyes of Java
     */
    @Override
    public boolean equals(Object otherObject) {
        if (otherObject == null) {
            return false;
        }
        if (getClass() == otherObject.getClass()) {
            RotatedRectangle rect = (RotatedRectangle) otherObject;
            if (rect.getX() == x && rect.getY() == y && rect.getWidth() == width
                    && rect.getHeight() == height && rect.getRotation() == rotation) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
    
    /*
     * 
     * @return Silly hashCode for the rectangle
     */
    @Override
    public int hashCode() {
        Object[] whocares = new Object[]{x, y, height, width, rotation} ;
        return java.util.Arrays.deepHashCode(whocares) ;
    }
    
    /**
     *
     * @return A string giving the values of the RotatedRectangle
     */
    @Override
    public String toString() {
        return "RotatedRectangle[x=" + x + ",y=" + y + ",width=" + width + ",height="
                + height + ",rotation=" + rotation + "]";
    }
    
    /**
     * 
     * @return An iterator that yields the points of the rectangle as rotated
     */
    @Override
    public java.util.Iterator<Point2D> iterator() {
	class Innerrator implements java.util.Iterator<Point2D> {
            private int nextPoint ;
            private Point2D points[] ;
            Innerrator() {
                float xOffset ;
                float yOffset ;
                float xRot ;
                float yRot ;
                float cosRot = (float)Math.cos(rotation) ;
                float sinRot = (float)Math.sin(rotation) ;
                points = new Point2D.Float[4] ;
                for (int i=0; i<4; ++i) {
                    points[i] = new Point2D.Float() ;
                    xOffset = (i<2) ? +width/2 : -width/2 ;
                    yOffset = (i==1||i==2) ? +height/2 : -height/2 ;
                    xRot = xOffset*cosRot - yOffset*sinRot ;
                    yRot = xOffset*sinRot + yOffset*cosRot ;
                    points[i].setLocation(x + xRot, y + yRot) ;
                }
                nextPoint = 0 ;
            }

            @Override
            public boolean hasNext() {
                return nextPoint < 4 ;
            }
            
            @Override
            public Point2D next()
                    throws java.util.NoSuchElementException {
                if (nextPoint==4) {
                    throw new java.util.NoSuchElementException() ;
                }
                return points[nextPoint++] ;
            }

            @Override
            public void remove()
                    throws UnsupportedOperationException {
                throw new UnsupportedOperationException() ;
            }

        }

        return new Innerrator() ;
    }
}
