package math.linear;

import math.utils.Tuple2d;

public class Vector2 {
    private double x, y;

    public Vector2() {
        this(0.0, 0.0);
    }

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

    public Vector2(double[] array) throws VectorException {
        if (array.length == 2) {
            x = array[0];
            y = array[1];
        } else {
            throw new VectorException("Niewłaściwa długość tablicy");
        }
    }

    public Vector2(Vector2 vector) {
        x = vector.x;
        y = vector.y;
    }

    public Vector2(Polar polar) {
        x = polar.getRadius() * Math.cos(polar.getAngle());
        y = polar.getRadius() * Math.sin(polar.getAngle());
    }

    public void normalize() {
        x /= getLength();
        y /= getLength();
    }

    public double dot(Vector2 vector) {
        return (x * vector.x + y * vector.y);
    }

    public double lengthSquared() {
        return (x * x + y * y);
    }

    public double getLength() {
        return Math.sqrt(x * x + y * y);
    }

    public void setLength(double length) {
        double r = this.getLength();
        if (r != 0.0) {
            scale(length / r);
        } else {
            this.x = length;
        }
    }

    public double getAngle() {
        return Math.atan2(y, x);
    }

    public void setAngle(double angle) {
        double r = getLength();
        this.x = r * Math.cos(angle);
        this.y = r * Math.sin(angle);
    }

    public double angleBetween(Vector2 vector) {
        double val = dot(vector) / (getLength() * vector.getLength());
        return ((Math.acos(val)));
    }

    public double getX() {
        return x;
    }

    public void setX(double x) {
        this.x = x;
    }

    public double getY() {
        return y;
    }

    public void setY(double y) {
        this.y = y;
    }

    public Polar toPolar() {
        double radius = Math.sqrt(Math.pow(y, 2) + Math.pow(x, 2));
        double angle = Math.atan2(y, x);
        return new Polar(radius, angle);
    }

    public void add(Vector2 vector) {
        this.x += vector.x;
        this.y += vector.y;
    }

    public void sub(Vector2 vector) {
        this.x -= vector.x;
        this.y -= vector.y;
    }

    public void scale(double s) {
        this.x *= s;
        this.y *= s;
    }

    public Vector2 normal(String direction) {
        double x1;
        double y1;
        if (direction.equals("left")) {
            x1 = -y;
            y1 = x;
            return new Vector2(x1, y1);
        } else if (direction.equals("right")) {
            x1 = y;
            y1 = -x;
            return new Vector2(x1, y1);
        } else {
            return null;
        }
    }

    public boolean isNormalTo(Vector2 vector) {
        return dot(vector) == 0.0;
    }

    @Override
    public String toString() {
        return "[" + x + ", " + y + "]";
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        if (!(obj instanceof Vector2)) {
            return false;
        }
        Vector2 t2 = (Vector2) obj;
        return (x == t2.getX()) && (y == t2.getY());
    }

    @Override
    public int hashCode() {
        return 17 * Double.valueOf(x).hashCode() + 19 * Double.valueOf(y).hashCode();
    }

    public Tuple2d toTuple2d() {
        return new Tuple2d(x, y);
    }

    public Vector2 cross(Vector2 vector) {
        double z = this.x * vector.getY() - this.y * vector.getX();
        return (new Vector2(0, z));
    }
}
