#![allow(non_snake_case)]

extern crate rand;
extern crate MBrane;

use rand::Rng;
use MBrane::Vector::Vector4D::*;

#[test]
fn vector4d_initialization() {
    let mut rng = rand::thread_rng();

    let rx = rng.gen::<f64>();
    let ry = rng.gen::<f64>();
    let rz = rng.gen::<f64>();
    let rt = rng.gen::<f64>();

    let vector = Vector4D {
        X: rx,
        Y: ry,
        Z: rz,
        T: rt,
    };

    assert_eq!(rx, vector.X);
    assert_eq!(ry, vector.Y);
    assert_eq!(rz, vector.Z);
    assert_eq!(rt, vector.T);
}

#[test]
fn vector4d_new_initialization() {
    let mut rng = rand::thread_rng();

    let rx = rng.gen::<f64>();
    let ry = rng.gen::<f64>();
    let rz = rng.gen::<f64>();
    let rt = rng.gen::<f64>();

    let vector = Vector4D {
        X: rx,
        Y: ry,
        Z: rz,
        T: rt,
    };

    let new_vector = vector.New(rx, ry, rz, rt);

    assert_eq!(rx, new_vector.X);
    assert_eq!(ry, new_vector.Y);
    assert_eq!(rz, new_vector.Z);
    assert_eq!(rt, new_vector.T);
}

#[test]
fn vector4d_magnitude() {
    let mut rng = rand::thread_rng();

    let rx = rng.gen::<f64>();
    let ry = rng.gen::<f64>();
    let rz = rng.gen::<f64>();
    let rt = rng.gen::<f64>();

    let rresult = ((rx * rx) + (ry * ry) + (rz * rz) + (rt * rt)).sqrt();

    let vector = Vector4D {
        X: rx,
        Y: ry,
        Z: rz,
        T: rt,
    };

    assert_eq!(rresult, vector.Magnitude());
}

#[test]
fn vector4d_normalization() {
    let mut rng = rand::thread_rng();

    let rx = rng.gen::<f64>();
    let ry = rng.gen::<f64>();
    let rz = rng.gen::<f64>();
    let rt = rng.gen::<f64>();

    let rxres = rx / ((rx * rx) + (ry * ry) + (rz * rz) + (rt * rt)).sqrt();
    let ryres = ry / ((rx * rx) + (ry * ry) + (rz * rz) + (rt * rt)).sqrt();
    let rzres = rz / ((rx * rx) + (ry * ry) + (rz * rz) + (rt * rt)).sqrt();
    let rtres = rt / ((rx * rx) + (ry * ry) + (rz * rz) + (rt * rt)).sqrt();

    let mut vector = Vector4D {
        X: rx,
        Y: ry,
        Z: rz,
        T: rt,
    };

    vector.Normalize();

    assert_eq!(rxres, vector.X);
    assert_eq!(ryres, vector.Y);
    assert_eq!(rzres, vector.Z);
    assert_eq!(rtres, vector.T);
}

#[test]
fn vector4d_addition() {
    let mut rng = rand::thread_rng();

    let rx_lhs = rng.gen::<f64>();
    let ry_lhs = rng.gen::<f64>();
    let rz_lhs = rng.gen::<f64>();
    let rt_lhs = rng.gen::<f64>();

    let rx_rhs = rng.gen::<f64>();
    let ry_rhs = rng.gen::<f64>();
    let rz_rhs = rng.gen::<f64>();
    let rt_rhs = rng.gen::<f64>();

    let rx_result = rx_lhs + rx_rhs;
    let ry_result = ry_lhs + ry_rhs;
    let rz_result = rz_lhs + rz_rhs;
    let rt_result = rt_lhs + rt_rhs;

    let lhs = Vector4D {
        X: rx_lhs,
        Y: ry_lhs,
        Z: rz_lhs,
        T: rt_lhs,
    };
    let rhs = Vector4D {
        X: rx_rhs,
        Y: ry_rhs,
        Z: rz_rhs,
        T: rt_rhs,
    };

    let result = lhs + rhs;

    assert_eq!(rx_result, result.X);
    assert_eq!(ry_result, result.Y);
    assert_eq!(rz_result, result.Z);
    assert_eq!(rt_result, result.T);
}

#[test]
fn vector4d_substraction() {
    let mut rng = rand::thread_rng();

    let rx_lhs = rng.gen::<f64>();
    let ry_lhs = rng.gen::<f64>();
    let rz_lhs = rng.gen::<f64>();
    let rt_lhs = rng.gen::<f64>();

    let rx_rhs = rng.gen::<f64>();
    let ry_rhs = rng.gen::<f64>();
    let rz_rhs = rng.gen::<f64>();
    let rt_rhs = rng.gen::<f64>();

    let rx_result = rx_lhs - rx_rhs;
    let ry_result = ry_lhs - ry_rhs;
    let rz_result = rz_lhs - rz_rhs;
    let rt_result = rt_lhs - rt_rhs;

    let lhs = Vector4D {
        X: rx_lhs,
        Y: ry_lhs,
        Z: rz_lhs,
        T: rt_lhs,
    };
    let rhs = Vector4D {
        X: rx_rhs,
        Y: ry_rhs,
        Z: rz_rhs,
        T: rt_rhs,
    };

    let result = lhs - rhs;

    assert_eq!(rx_result, result.X);
    assert_eq!(ry_result, result.Y);
    assert_eq!(rz_result, result.Z);
    assert_eq!(rt_result, result.T);
}

#[test]
fn vector4d_multiplication() {
    let mut rng = rand::thread_rng();

    let rx_lhs = rng.gen::<f64>();
    let ry_lhs = rng.gen::<f64>();
    let rz_lhs = rng.gen::<f64>();
    let rt_lhs = rng.gen::<f64>();

    let rx_rhs = rng.gen::<f64>();
    let ry_rhs = rng.gen::<f64>();
    let rz_rhs = rng.gen::<f64>();
    let rt_rhs = rng.gen::<f64>();

    let rx_result = rx_lhs * rx_rhs;
    let ry_result = ry_lhs * ry_rhs;
    let rz_result = rz_lhs * rz_rhs;
    let rt_result = rt_lhs * rt_rhs;

    let lhs = Vector4D {
        X: rx_lhs,
        Y: ry_lhs,
        Z: rz_lhs,
        T: rt_lhs,
    };
    let rhs = Vector4D {
        X: rx_rhs,
        Y: ry_rhs,
        Z: rz_rhs,
        T: rt_rhs,
    };

    let result = lhs * rhs;

    assert_eq!(rx_result, result.X);
    assert_eq!(ry_result, result.Y);
    assert_eq!(rz_result, result.Z);
    assert_eq!(rt_result, result.T);
}

#[test]
fn vector4d_division() {
    let mut rng = rand::thread_rng();

    let rx_lhs = rng.gen::<f64>();
    let ry_lhs = rng.gen::<f64>();
    let rz_lhs = rng.gen::<f64>();
    let rt_lhs = rng.gen::<f64>();

    let rx_rhs = rng.gen::<f64>();
    let ry_rhs = rng.gen::<f64>();
    let rz_rhs = rng.gen::<f64>();
    let rt_rhs = rng.gen::<f64>();

    let rx_result = rx_lhs / rx_rhs;
    let ry_result = ry_lhs / ry_rhs;
    let rz_result = rz_lhs / rz_rhs;
    let rt_result = rt_lhs / rt_rhs;

    let lhs = Vector4D {
        X: rx_lhs,
        Y: ry_lhs,
        Z: rz_lhs,
        T: rt_lhs,
    };
    let rhs = Vector4D {
        X: rx_rhs,
        Y: ry_rhs,
        Z: rz_rhs,
        T: rt_rhs,
    };

    let result = lhs / rhs;

    assert_eq!(rx_result, result.X);
    assert_eq!(ry_result, result.Y);
    assert_eq!(rz_result, result.Z);
    assert_eq!(rt_result, result.T);
}
