use std::io::Read;

use crate::{decode_tile, image::Image, protocol::{self, ProtocolReaderResult}};

pub fn decode_image<R: Read>(
    reader: &mut protocol::ProtocolReader<R>
) -> ProtocolReaderResult<Image> {
    let width = reader.read_u16()? as usize;
    let height = reader.read_u16()? as usize;

    let mut layer_quality = [0_u8; 4];
    for i in 0..4 {
        layer_quality[i] = reader.read_u8()?;
    }

    let mut n_layers = 0;
    for i in (0..4).rev() {
        if layer_quality[i] != 0 {
            n_layers = i + 1;
            break;
        }
    }

    let mut layer_pixels = vec![];
    for _ in 0..n_layers {
        layer_pixels.push(vec![0_u8; width as usize * height as usize])
    }

    for y0 in (0..height).step_by(16) {
        for x0 in (0..width).step_by(16) {
            for layer in 0..n_layers {
                let mut data = [0; 256];

                decode_tile::decode_tile(&mut data, layer_quality[layer], reader)?;

                for y in 0..16 {
                    for x in 0..16 {
                        let src_x = x0 + x;
                        let src_y = y0 + y;
                        if src_x < width && src_y < height {
                            layer_pixels[layer][src_y * width + src_x] = 
                                data[y * 16 + x];
                        }
                    }
                }
            }
        }
    }

    let mut image = Image::new(width, height);
    for (layer, pixels) in layer_pixels.into_iter().enumerate() {
        image.add(layer_quality[layer], pixels)
            .expect("should be correct by construction");
    }
    Ok(image)
}