/* Implemnetation of *m_fixed.c/h

This provides fixed-point arithmetic as 32-bit 16.16
*/
use std::ops::ShrAssign;

use crate::doomtype::{
    MININT,
    MAXINT
};

pub const FRACBITS: i32 = 16;
pub const FRACUNIT: i32 = 1 << FRACBITS;


/// Struct representing a fixed point 32-bit value
#[derive(Copy, Clone, PartialEq, Debug)]
#[allow(non_camel_case_types)]
pub struct fixed_t {
    pub value: i32,
}

impl fixed_t {

    pub const fn new(val: i32) -> Self {
        fixed_t { value: val }
    }
    
    #[allow(non_snake_case)]
    pub fn FixedMul(a: fixed_t, b: fixed_t) -> fixed_t {
        let value = ((a.value as u64) * (b.value as u64) >> FRACBITS) as i32;
        fixed_t{value}
    }

    #[allow(non_snake_case)]
    pub fn FixedDiv(a: fixed_t, b: fixed_t) -> fixed_t {
        if (i32::abs(a.value) >> 14) >= i32::abs(b.value) {
            if a.value^b.value == 0 {
                fixed_t{value: MININT};
            }
            else {
               fixed_t{value: MAXINT};
            }
        }
        fixed_t::FixedDiv2(a,b)
    }

    #[allow(non_snake_case)]
    pub fn FixedDiv2(a: fixed_t, b: fixed_t) -> fixed_t {
        let c: f64 = ((a.value as f64) / (b.value as f64)) * FRACUNIT as f64;
        if c >= 2147483648.0 || c < -2147483648.0 {
            panic!("FixedDiv: divide by zero");
        }
        fixed_t { value: c as i32 }
    }

} 

impl ShrAssign<i32> for fixed_t {
    fn shr_assign(&mut self, rhs: i32) {
        // Shift the underlying wrapped i32 value directly
        self.value >>= rhs;
    }
}
