use proto::{Vector, VectorBin};

#[derive(Default, PartialEq, Clone, Debug)]
pub struct Vector3 {
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

#[derive(Default, PartialEq, Clone, Debug)]
pub struct Vector2 {
    pub x: f32,
    pub y: f32,
}

#[derive(Default, PartialEq, Eq, Clone, Debug)]
pub struct Coordinate {
    pub x: i32,
    pub y: i32,
}

pub static VECTOR3_ZERO: Vector3 = Vector3 {
    x: 0.0,
    y: 0.0,
    z: 0.0,
};

impl Vector3 {
    pub fn from_bin(bin: VectorBin) -> Self {
        Self {
            x: bin.x,
            y: bin.y,
            z: bin.z,
        }
    }

    pub fn to_bin(&self) -> VectorBin {
        VectorBin {
            x: self.x,
            y: self.y,
            z: self.z,
        }
    }

    pub fn to_client(&self) -> Vector {
        Vector {
            x: self.x,
            y: self.y,
            z: self.z,
        }
    }

    pub fn reset(&mut self) {
        self.x = 0.0;
        self.y = 0.0;
        self.z = 0.0;
    }

    pub fn is_zero(&self) -> bool {
        if self.x.abs() >= 0.00000011920929 {
            return false;
        }

        if self.y.abs() >= 0.00000011920929 {
            return false;
        }

        self.z.abs() < 0.00000011920929
    }

    pub fn is_valid(&self) -> bool {
        self.x.is_finite() && self.y.is_finite() && self.z.is_finite()
    }

    pub fn is_valid_rot(&self) -> bool {
        let range = 0.0..361.0;
        self.is_valid()
            && range.contains(&self.x)
            && range.contains(&self.y)
            && range.contains(&self.z)
    }
}

impl ToString for Vector3 {
    fn to_string(&self) -> String {
        format!("{{{},{},{}}}", self.x, self.y, self.z)
    }
}
