use std::io::Read;

use crate::protocol::{ProtocolReader, ProtocolReaderResult};

pub fn decode_tile<R: Read>(
    data: &mut [u8; 256], 
    quality: u8, 
    reader: &mut ProtocolReader<R>
) -> ProtocolReaderResult<()> {
    let mut coefs = [0_i32; 256];

    for _ in 0..quality {
        let ix = reader.read_u8()?;
        coefs[ix as usize] = reader.read_u16()? as i16 as i32 * 256;
    }

    let mut transform = |zero: usize, stride: usize| {
        let mut ixs = [0; 16];
        ixs[0] = zero;
        for i in 1..16 { ixs[i] = ixs[i - 1] + stride; }

        for bit in [8, 4, 2, 1] {
            for i in 0..16 {
                if i & bit == 0 {
                    let j = i | bit;

                    let ival = coefs[ixs[i]];
                    let jval = coefs[ixs[j]];

                    coefs[ixs[i]] = ival.wrapping_add(jval);
                    coefs[ixs[j]] = ival.wrapping_sub(jval);
                }
            }
        }
    };

    for row in 0..16 { transform(row * 16, 1); }
    for col in 0..16 { transform(col, 16); }

    for i in 0..256 {
        data[i] = (coefs[i] / 256).max(0).min(255) as u8;
    }
    Ok(())
}