use crate::lumps::{LinedefLump, Lump, SidedefLump, ThingLump, VertexLump};
use crate::types::{Linedef, Sidedef, Thing, Vertex};
use crate::utils::read_ascii;
use crate::wad::WADFile;
use crate::wad::wadfile::read_i16_le;

impl WADFile {
    pub fn get_vertex_lump(&self, lump: &Lump) -> VertexLump {
        let lump_offset = lump.offset as usize;
        let lump_size = lump.size as usize;
        let lump_data = &self.data[lump_offset..lump_offset + lump_size];
        let lump_entries: usize = lump_size / 4;
        let mut vertexes: Vec<Vertex> = Vec::with_capacity(lump_entries);

        for entry in 0..lump_entries {
            let startpos = entry * 4;
            let vertex_x = read_i16_le(&lump_data[startpos..startpos + 2]);
            let vertex_y = read_i16_le(&lump_data[startpos + 2..startpos + 4]);

            vertexes.push(Vertex {
                x: vertex_x,
                y: vertex_y,
            });
        }

        VertexLump { vertexes }
    }

    pub fn get_linedef_lump(&self, lump: &Lump) -> LinedefLump {
        let lump_offset = lump.offset as usize;
        let lump_size = lump.size as usize;
        let lump_data = &self.data[lump_offset..lump_offset + lump_size];
        let lump_entries = lump_size / 14;
        let mut linedefs: Vec<Linedef> = Vec::with_capacity(lump_entries);

        for entry in 0..lump_entries {
            let startpos = entry * 14;
            let vertex1 = read_i16_le(&lump_data[startpos..startpos + 2]);
            let vertex2 = read_i16_le(&lump_data[startpos + 2..startpos + 4]);
            let flags = read_i16_le(&lump_data[startpos + 4..startpos + 6]);
            let special = read_i16_le(&lump_data[startpos + 6..startpos + 8]);
            let tag = read_i16_le(&lump_data[startpos + 8..startpos + 10]);
            let front_sidedef = read_i16_le(&lump_data[startpos + 10..startpos + 12]);
            let back_sidedef = read_i16_le(&lump_data[startpos + 12..startpos + 14]);

            linedefs.push(Linedef {
                vertex1,
                vertex2,
                flags,
                special,
                tag,
                front_sidedef,
                back_sidedef,
            });
        }

        LinedefLump { linedefs }
    }

    pub fn get_sidedef_lump(&self, lump: &Lump) -> SidedefLump {
        let lump_offset = lump.offset as usize;
        let lump_size = lump.size as usize;
        let lump_data = &self.data[lump_offset..lump_offset + lump_size];
        let lump_entires = lump_size / 30;
        let mut sidedefs: Vec<Sidedef> = Vec::with_capacity(lump_entires);

        for entry in 0..lump_entires {
            let startpos = entry * 30;
            let x_offset = read_i16_le(&lump_data[startpos..startpos + 2]);
            let y_offset = read_i16_le(&lump_data[startpos + 2..startpos + 4]);
            let upper_texture = read_ascii(&lump_data[startpos + 4..startpos + 12]);
            let lower_texture = read_ascii(&lump_data[startpos + 12..startpos + 20]);
            let middle_texture = read_ascii(&lump_data[startpos + 20..startpos + 28]);
            let sector = read_i16_le(&lump_data[startpos + 28..startpos + 30]);

            sidedefs.push(Sidedef {
                x_offset,
                y_offset,
                upper_texture,
                lower_texture,
                middle_texture,
                sector,
            });
        }

        SidedefLump { sidedefs }
    }

    pub fn get_thing_lump(&self, lump: &Lump) -> ThingLump {
        let lump_offset = lump.offset as usize;
        let lump_size = lump.size as usize;
        let lump_data = &self.data[lump_offset..lump_offset + lump_size];
        let lump_entries = lump_size / 10;
        let mut things: Vec<Thing> = Vec::with_capacity(lump_entries);

        for entry in 0..lump_entries {
            let startpos = entry * 10;
            let x_position = read_i16_le(&lump_data[startpos..startpos + 2]);
            let y_position = read_i16_le(&lump_data[startpos + 2..startpos + 4]);
            let angle = read_i16_le(&lump_data[startpos + 4..startpos + 6]);
            let thing_type = read_i16_le(&lump_data[startpos + 6..startpos + 8]);
            let flags = read_i16_le(&lump_data[startpos + 8..startpos + 10]);

            things.push(Thing {
                x_position,
                y_position,
                angle,
                thing_type,
                flags,
            });
        }

        ThingLump { things }
    }
}
