import codedraw.CodeDraw;

/**
 * This class represents vectors in a 3D vector space.
 */
public class Vector3 {
    private double x;
    private double y;
    private double z;

    public Vector3() {
        this(0);
    }

    public Vector3(double v) {
        this(v, v, v);
    }

    public Vector3(double x, double y, double z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    public Vector3(Vector3 other) {
        this(other.x, other.y, other.z);
    }

    public void set(double v) {
        set(v, v, v);
    }

    public void set(double x, double y, double z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    /**
     * Returns the sum of this vector and vector 'v'.
     */
    public Vector3 plus(Vector3 v) {
        return new Vector3(x + v.x, y + v.y, z + v.z);
    }

    public void add(Vector3 v) {
        this.x += v.x;
        this.y += v.y;
        this.z += v.z;
    }

    /**
     * Returns the product of this vector and 'd'.
     */
    public Vector3 times(double d) {
        return new Vector3(x * d, y * d, z * d);
    }

    /**
     * Returns the sum of this vector and -1*v.
     */
    public Vector3 minus(Vector3 v) {
        return new Vector3(x - v.x, y - v.y, z - v.z);
    }

    public void sub(Vector3 v) {
        this.x -= v.x;
        this.y -= v.y;
        this.z -= v.z;
    }

    /**
     * Returns the Euclidean distance of this vector
     * to the specified vector 'v'.
     */
    public double distanceTo(Vector3 v) {
        double dX = x - v.x;
        double dY = y - v.y;
        double dZ = z - v.z;
        return Math.sqrt(dX * dX + dY * dY + dZ * dZ);
    }

    /**
     * Returns the length (norm) of this vector.
     */
    public double length() {
        return distanceTo(new Vector3());
    }

    /**
     * Normalizes this vector: changes the length of this vector such that it becomes 1.
     * The direction and orientation of the vector is not affected.
     */
    public void normalize() {
        double length = length();
        x /= length;
        y /= length;
        z /= length;
    }

    public double getScreenX(CodeDraw cd) {
        return cd.getWidth() * (this.x + Simulation4.SECTION_SIZE / 2) / Simulation4.SECTION_SIZE;
    }

    public double getScreenY(CodeDraw cd) {
        return cd.getWidth() * (this.y + Simulation4.SECTION_SIZE / 2) / Simulation4.SECTION_SIZE;
    }

    /**
     * Draws a filled circle with a specified radius centered at the (x,y) coordinates of this vector
     * in the canvas associated with 'cd'. The z-coordinate is not used.
     */
    public void drawAsFilledCircle(CodeDraw cd, double radius) {
        radius = cd.getWidth() * radius / Simulation4.SECTION_SIZE;
        cd.fillCircle(getScreenX(cd), getScreenY(cd), Math.max(radius, 1.5));
    }

    /**
     * Returns the coordinates of this vector in brackets as a string
     * in the form "[x,y,z]", e.g., "[1.48E11,0.0,0.0]".
     */
    @Override
    public String toString() {
        return String.format("[%g,%g,%g]", x, y, z);
    }

    @Override
    public boolean equals(Object other) {
        if (other.getClass() != Vector3.class) {
            return false;
        }
        Vector3 v = (Vector3) other;
        return this.x == v.x && this.y == v.y && this.z == v.z;
    }
}
