#![allow(non_snake_case)]

use std::ops::{Add, Sub, Mul, Div};

#[derive(Debug)]
pub struct Vector3D {
    pub X: f64,
    pub Y: f64,
    pub Z: f64,
}

impl Vector3D {
    pub fn New(&self, nx: f64, ny: f64, nz: f64) -> Vector3D {
        Vector3D { X: nx, Y: ny, Z: nz}
    }

    pub fn Magnitude(&self) -> f64 {
        (((self.X * self.X) + (self.Y * self.Y) + (self.Z * self.Z))).sqrt()
    }

    pub fn Normalize(&mut self) {
        let temp_mag = self.Magnitude();
        self.X = self.X / temp_mag;
        self.Y = self.Y / temp_mag;
        self.Z = self.Z / temp_mag;
    }
}

impl Add for Vector3D {
    type Output = Vector3D;

    fn add(self, rhs: Vector3D) -> Vector3D {
        Vector3D {
            X: self.X + rhs.X,
            Y: self.Y + rhs.Y,
            Z: self.Z + rhs.Z,
        }
    }
}

impl Sub for Vector3D {
    type Output = Vector3D;

    fn sub(self, rhs: Vector3D) -> Vector3D {
        Vector3D {
            X: self.X - rhs.X,
            Y: self.Y - rhs.Y,
            Z: self.Z - rhs.Z,
        }
    }
}

impl Mul for Vector3D {
    type Output = Vector3D;

    fn mul(self, rhs: Vector3D) -> Vector3D {
        Vector3D {
            X: self.X * rhs.X,
            Y: self.Y * rhs.Y,
            Z: self.Z * rhs.Z,
        }
    }
}

impl Div for Vector3D {
    type Output = Vector3D;

    fn div(self, rhs: Vector3D) -> Vector3D {
        Vector3D {
            X: self.X / rhs.X,
            Y: self.Y / rhs.Y,
            Z: self.Z / rhs.Z,
        }
    }
}
