use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use rusttype::{Font, PositionedGlyph, Scale, Rect, point};
use rusttype::gpu_cache::Cache;
use vulkano::buffer::{BufferAccess, BufferUsage, ImmutableBuffer, CpuAccessibleBuffer};
use vulkano::device::{Device, Queue};
use std::sync::Arc;
use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState};
use vulkano::image::{ImmutableImage, ImageUsage, ImageLayout, Dimensions};
use vulkano::format::ClearValue;
use vulkano::format::Format::R8Unorm;


/*

So I think this thing is going to build text vertex buffers to send to the GPU.
I assume I will just lay them out in ASCII for now along with a list of
transformation matrices

Glpyh:
    index: 0-255,
    scale: 0.0 - 99.99
    transform: (0.0, 0.0) - (1.0, 1.0)

I'm not sure if I want to send a new transformation matrix for each frame. But I suppose
that can come when I look at caching the sprites





*/

pub struct Glyph {

}

/// Typed wrapper for a u32 shader handle (index id)
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct CanvasFontHandle {
    pub handle: u32
}

/// So currently, I'm using these as container classes which vkprocessor owns
/// I then use a CanvasFrame which accumulates lists of handles and vertices.
pub struct CanvasText {
    device:             Arc<Device>,
    queue:              Arc<Queue>,
    font:               Font<'static>,
}

impl CanvasText {

    /// Load the font
    pub fn new(device: Arc<Device>, queue: Arc<Queue>) -> CanvasText {

        let font_data = include_bytes!("../../resources/fonts/sansation.ttf");
        let font = Font::from_bytes(font_data as &[u8]).unwrap();

        CanvasText {
            device: device.clone(),
            queue: queue.clone(),
            font: font,
        }
    }

    /// Generate a vertex buffer from the font
    /*
        So... These fonts are going to have unequal amounts of vertices.

    */
    pub fn get_vertex_buffer(&self) {
        unimplemented!()
    }

    /// postpone this until caching
    pub fn queue_text(&mut self,
                      x: f32, y: f32,
                      size: f32, color: [f32; 4],
                      text: &str) {
        let glyphs: Vec<PositionedGlyph> = self.font.layout(text, Scale::uniform(size), point(x, y)).map(|x| x.standalone()).collect();
        for glyph in &glyphs {
            self.cache.queue_glyph(0, glyph.clone());
        }
//        self.texts.push(TextData {
//            glyphs: glyphs.clone(),
//            color:  color,
//        });
    }

    pub fn draw_text(&mut self,
                     command_buffer: AutoCommandBufferBuilder,
                     image_num: usize
    ) -> AutoCommandBufferBuilder {

//        let screen_width = 0;
//        let screen_height = 0;
//
//        let cache_pixel_buffer = &mut self.cache_pixel_buffer;
//        let cache = &mut self.cache;
//
//        // update texture cache
//        cache.cache_queued(
//            |rect, src_data| {
//                let width = (rect.max.x - rect.min.x) as usize;
//                let height = (rect.max.y - rect.min.y) as usize;
//                let mut dst_index = rect.min.y as usize * CACHE_WIDTH + rect.min.x as usize;
//                let mut src_index = 0;
//
//                for _ in 0..height {
//                    let dst_slice = &mut cache_pixel_buffer[dst_index..dst_index+width];
//                    let src_slice = &src_data[src_index..src_index+width];
//                    dst_slice.copy_from_slice(src_slice);
//
//                    dst_index += CACHE_WIDTH;
//                    src_index += width;
//                }
//            }
//        ).unwrap();
//
//        // need to get a hold of the cache buffer handle after I create it
//        // will then get swapped into this texture buffer
//        // Hmmm so this uninit call returns the texture and then a handle for whatever fills it up
//        let (cache_texture, cache_texture_write) = ImmutableImage::uninitialized(
//            self.device.clone(),
//            Dimensions::Dim2d { width: CACHE_WIDTH as u32, height: CACHE_HEIGHT as u32 },
//            R8Unorm,
//            1,
//            ImageUsage {
//                sampled: true,
//                transfer_destination: true,
//                .. ImageUsage::none()
//            },
//            ImageLayout::General,
//            Some(self.queue.family())
//        ).unwrap();
//
//
//
//        let set = Arc::new(
//            PersistentDescriptorSet::start(self.pipeline.clone(), 0)
//                .add_sampled_image(cache_texture.clone(), sampler).unwrap()
//                .build().unwrap()
//        );
//
//        let mut command_buffer = command_buffer
//            .copy_buffer_to_image(
//                buffer.clone(),
//                cache_texture_write,
//            ).unwrap()
//            .begin_render_pass(self.framebuffers[image_num].clone(), false, vec!(ClearValue::None)).unwrap();
//
//        // draw
//        for text in &mut self.texts.drain(..) {
//            let vertices: Vec<Vertex2D> = text.glyphs.iter().flat_map(|g| {
//                if let Ok(Some((uv_rect, screen_rect))) = cache.rect_for(0, g) {
//                    let gl_rect = Rect {
//                        min: point(
//                            (screen_rect.min.x as f32 / screen_width  as f32 - 0.5) * 2.0,
//                            (screen_rect.min.y as f32 / screen_height as f32 - 0.5) * 2.0
//                        ),
//                        max: point(
//                            (screen_rect.max.x as f32 / screen_width  as f32 - 0.5) * 2.0,
//                            (screen_rect.max.y as f32 / screen_height as f32 - 0.5) * 2.0
//                        )
//                    };
//                    vec!(
////                        Vertex {
////                            position:     [gl_rect.min.x, gl_rect.max.y],
////                            tex_position: [uv_rect.min.x, uv_rect.max.y],
////                            color:        text.color,
////                        },
////                        Vertex {
////                            position:     [gl_rect.min.x, gl_rect.min.y],
////                            tex_position: [uv_rect.min.x, uv_rect.min.y],
////                            color:        text.color,
////                        },
////                        Vertex {
////                            position:     [gl_rect.max.x, gl_rect.min.y],
////                            tex_position: [uv_rect.max.x, uv_rect.min.y],
////                            color:        text.color,
////                        },
////
////                        Vertex {
////                            position:     [gl_rect.max.x, gl_rect.min.y],
////                            tex_position: [uv_rect.max.x, uv_rect.min.y],
////                            color:        text.color,
////                        },
////                        Vertex {
////                            position:     [gl_rect.max.x, gl_rect.max.y],
////                            tex_position: [uv_rect.max.x, uv_rect.max.y],
////                            color:        text.color,
////                        },
////                        Vertex {
////                            position:     [gl_rect.min.x, gl_rect.max.y],
////                            tex_position: [uv_rect.min.x, uv_rect.max.y],
////                            color:        text.color,
////                        },
//                    ).into_iter()
//                }
//                else {
//                    vec!().into_iter()
//                }
//            }).collect();
//
//            let vertex_buffer = CpuAccessibleBuffer::from_iter(self.device.clone(), BufferUsage::all(), vertices.into_iter()).unwrap();
//            command_buffer = command_buffer.draw(self.pipeline.clone(), &DynamicState::none(), vertex_buffer.clone(), set.clone(), ()).unwrap();
//        }

        command_buffer//.end_render_pass().unwrap()
    }

}