use glium::texture::{RawImage2d,Texture2dDataSource};
use therm_util::reader::ByteReader;

#[derive(Debug,Clone)]
pub struct FFImage {
    pixels: Vec<Vec<(u16,u16,u16,u16)>>
}

fn parse_pixel<Rd>(r: &mut ByteReader<Rd>) -> Result<(u16,u16,u16,u16), String>
    where Rd: Iterator<Item=u8>
{
    Ok((r.read_u16be()?,
        r.read_u16be()?,
        r.read_u16be()?,
        r.read_u16be()?))
}

impl FFImage {
    pub fn from_bz2_file(path: &str) -> Result<FFImage, String> {
        let mut r = match ByteReader::from_compressed_file(path) {
            Ok(x) => x,
            Err(_) => return Err("Unable to open file".to_string()),
        };
        FFImage::from_reader(&mut r)
    }

    pub fn from_file(path: &str) -> Result<FFImage, String> {
        let mut r = match ByteReader::from_file(path) {
            Ok(x) => x,
            Err(_) => return Err("Unable to open file".to_string()),
        };
        FFImage::from_reader(&mut r)
    }


    pub fn from_reader<Rd>(r: &mut ByteReader<Rd>) -> Result<FFImage, String>
        where Rd: Iterator<Item=u8>
    {
        assert!(r.next()? == 'f' as u8);
        assert!(r.next()? == 'a' as u8);
        assert!(r.next()? == 'r' as u8);
        assert!(r.next()? == 'b' as u8);
        assert!(r.next()? == 'f' as u8);
        assert!(r.next()? == 'e' as u8);
        assert!(r.next()? == 'l' as u8);
        assert!(r.next()? == 'd' as u8);

        let w = try!(r.read_u32be());
        let h = try!(r.read_u32be());

        let mut pixels = vec![];
        for _ in 0..h {
            let mut row = vec![];
            for _ in 0..w {
                row.push(try!(parse_pixel(r)));
            }
            pixels.push(row)
        }
        pixels.reverse();

        Ok(FFImage { pixels: pixels })
    }

    pub fn get_raw_data(self) -> Vec<Vec<(u16,u16,u16,u16)>> {
        self.pixels
    }
}

impl <'a> Texture2dDataSource<'a> for FFImage {
    type Data = (u16, u16, u16, u16);

    fn into_raw(self) -> RawImage2d<'a, (u16, u16, u16, u16)> {
        self.pixels.into_raw()
    }
}
