#[derive(Debug, Clone, Copy)]
pub struct BLOCK(pub(crate) [[u8; 4]; 4]);

impl BLOCK {
    /* it configures the data in the form:
    ------------------------------------------------------------
    |   unnaceptable block =   |  socialy respectable block =  |          this is essential to the shift_row part of aes. you will notice that each of the rows in then
    |   [0,1,2,3,              |  [0,4,8,12                    |          respectable block are made up of one componant from each row in the *ahem* dumbass block. this means
    |    4,5,6,7,              |   1,5,9,13                    |          that when they are shifted they are thourughl mixed. the end text will not just be the original first
    |    8,9,10,11,            |   2,6,10,14                   |          row but in a different order.
    |    12,13,14,15];         |   3,7,11,15];                 |
    ------------------------------------------------------------
    */
    pub fn new(input: [u8; 16]) -> Self {
        Self(unsafe { core::mem::transmute(input) })
    }
    pub fn flipyx(&mut self) -> Self {
        let buff = self.0;
        for x in 0..4 {
            for y in 0..4 {
                self.0[x][y] = buff[y][x];
            }
        }
        *self
    }
    /*pub fn encrypt(message:&[u8], key:BLOCK)->String{
        let blocks = Vec::new();
        for index in 0..1+message.len()%16{
            blocks.push(
                BLOCK::new(message[index*16..(index+1)*16])
            );


        }


        message
    }*/
}

impl std::fmt::UpperHex for BLOCK {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        for i in 0..4 {
            for j in 0..4 {
                write!(f, " {:x} ", self.0[i][j]).unwrap();
            }
        }

        Ok(())
    }
}

impl std::ops::BitXor for BLOCK {
    type Output = Self;
    fn bitxor(mut self, rhs: Self) -> Self::Output {
        for row in self.0.iter_mut().zip(rhs.0.iter()) {
            for item in row.0.iter_mut().zip(row.1) {
                *item.0 ^= *item.1
            }
        }
        self
    }
}

// this only works for encryption as it is a seperate method to reverse this proscess as it involves fractions (differnte type also)
impl std::ops::Mul for BLOCK {
    type Output = Self;

    //this is just a dot product method, but where in dot product you would add you xor
    fn mul(self, rhs: Self) -> Self::Output {
        let mut result = [0_u8; 16];
        for row in 0..4 {
            for column in 0..4 {
                result[row * 4 + column] = self.0[row][0] ^ rhs.0[0][column];
                for i in 1..4 {
                    result[row * 4 + column] ^= self.0[row][i] ^ rhs.0[i][column];
                }
            }
        }
        BLOCK::new(result)
    }
}
