use super::{
    application::{frame::Frame, render::RenderError},
    maths::geometry::Vec2,
};
use crate::arch::x86_64::drivers::framebuffer::colour::Colour;
use crate::resources::font::Font;

pub struct Writer<'a> {
    font: &'a Font,
}

impl<'a> Writer<'a> {
    pub const fn new(font: &'a Font) -> Self {
        Self { font }
    }

    pub const fn set_font(&mut self, font: &'a Font) {
        self.font = font;
    }

    pub const fn font_size(&self) -> Vec2<usize> {
        Vec2::new(self.font.width(), self.font.height())
    }

    pub fn render_glyph(
        &self,
        frame: &mut Frame,
        pos: Vec2<usize>,
        c: u8,
        scale: usize,
    ) -> Result<(), RenderError> {
        // get a reference to the character glyph from the font.
        let data: &[u8] = self.font.glyph_for(c as u16);

        if pos.x() + self.font.width() * scale > frame.dimensions().x()
            || pos.y() + self.font.height() * scale > frame.dimensions().y()
        {
            return Err(RenderError::Generic);
        }

        for (row, line) in data.iter().enumerate().take(self.font.height()) {
            for col in 0..self.font.width() {
                let pixel_x: usize = pos.x() + col * scale;
                let pixel_y: usize = pos.y() + row * scale;

                if line & (0x80 >> col) != 0 {
                    for i in 0..scale {
                        for j in 0..scale {
                            frame.write_pixel(
                                pixel_x + i,
                                pixel_y + j,
                                Colour::White,
                            )?;
                        }
                    }
                }
            }
        }
        Ok(())
    }
}
