#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(unused_mut)]



extern crate cgmath;
extern crate image;
extern crate nalgebra as na;
extern crate rand;
extern crate time;
extern crate hprof;

use vulkano::sync;
use crate::util::timer::Timer;
use vulkano::instance::Instance;
use vulkano::sync::GpuFuture;
use winit::{EventsLoop, WindowBuilder, WindowEvent, Event, DeviceEvent, VirtualKeyCode, ElementState};
use winit::dpi::LogicalSize;
use vulkano_win::VkSurfaceBuild;
use sprite::Sprite;

use crate::util::load_raw;

use crate::sprite::{Poly, Text, TextHandle, TextVertex, TextInstance};
use vulkano::instance::debug::DebugCallback;
use crate::compute::compu_sprite::CompuSprite;
use crate::compute::compu_frame::CompuFrame;
use crate::canvas::canvas_frame::{CanvasFrame, GenericCanvasFrame};


pub mod util;
pub mod vkprocessor;
pub mod sprite;

pub mod canvas;
pub mod compute;

/*

    Trac3r : A program to convert images to 2D toolpaths

    TODO:
        + Text rendering is half implemented.
        + Need generalized interface for render (image, texture, text)
        + Currently using local copies of a few libraries:
            shade_runner
            vulkano/vulkano-win
            vulkano/vulkano-shaders
            vulkano/vulkano
        + Need to generate runtime vertex definitions if I want to have on the fly shaders



*/

pub fn main() {
    hprof::start_frame();

    let q1 = hprof::enter("setup");

    let instance = {
        let extensions = vulkano_win::required_extensions();
        Instance::new(None, &extensions, None).unwrap()
    };

    let _callback = DebugCallback::errors_and_warnings(&instance, |msg| {
        println!("Debug callback: {:?}", msg.description);
    }).ok();

    let mut events_loop = EventsLoop::new();
    let mut surface = WindowBuilder::new()
        .with_dimensions(LogicalSize::from((800, 800)))
        .build_vk_surface(&events_loop, instance.clone()).unwrap();
    let mut window = surface.window();

    let mut processor = vkprocessor::VkProcessor::new(&instance, &surface);

    {
        let g = hprof::enter("vulkan preload");
        processor.create_swapchain(&surface);

        processor.preload_kernels();
        processor.preload_shaders();
        processor.preload_textures();
        processor.preload_fonts();
    }

    let q2 = hprof::enter("Game Objects");

    let mut timer = Timer::new();
    let mut frame_future = Box::new(sync::now(processor.device.clone())) as Box<dyn GpuFuture>;

    let step_size: f32 = 0.005;
    let mut elapsed_time: f32;
    let mut delta_time: f32;
    let mut accumulator_time: f32 = 0.0;
    let mut current_time: f32 = timer.elap_time();

    let image_data = load_raw(String::from("funky-bird.jpg"));
    let image_dimensions_f = ((image_data.1).0 as f32, (image_data.1).1 as f32);
    let image_dimensions_u = image_data.1;
    let compu_sprite1 = CompuSprite::new((0.0, -0.5), (0.4, 0.4), 0, image_dimensions_f,
                                         // This swap image needs to match the size of the compute
                                         processor.new_swap_image(image_dimensions_u));

    let compute_buffer = processor.new_compute_buffer(image_data.0, image_data.1, 4);

    let compute_kernel = processor.get_kernel_handle(String::from("simple-edge.compute"))
        .expect("Can't find that kernel");

    let funky_handle = processor.get_texture_handle(String::from("funky-bird.jpg")).unwrap();
    let sfml_handle = processor.get_texture_handle(String::from("sfml.png")).unwrap();
    let font_handle = processor.get_font_handle(String::from("sansation.ttf")).unwrap();

    let funky_sprite = Sprite::new_with_texture((0.0, -0.5), (0.5, 0.5), 0, funky_handle.clone());
    let sfml_sprite  = Sprite::new_with_texture((0.0, -0.5), (0.5, 0.5), 1, sfml_handle.clone());
    let text_sprite = Text::new((-0.1,-0.1), (10.0, 10.0), font_handle.clone());


    let test_polygon = Poly::new_with_color((-0.5, -0.5), (0.5, 0.5), 1, (1.0,0.0,0.0,0.0));

    drop(q2);
    drop(q1);

    let l = hprof::enter("Loop");

    let mut exit = false;

    let mut count = 0;

    while let true = processor.is_open() {

        // Take care of our timing
        {
            elapsed_time = timer.elap_time();
            delta_time = elapsed_time - current_time;
            current_time = elapsed_time;
            if delta_time > 0.02 {
                delta_time = 0.02;
            }
            accumulator_time += delta_time;
        }

        while (accumulator_time - step_size) >= step_size {
            accumulator_time -= step_size;
        }

        // Events loop is borrowed from the surface
        events_loop.poll_events(|event| {
            match event {
                Event::WindowEvent { event: WindowEvent::CloseRequested, .. } =>
                    {
                        exit = true;
                    }
                Event::WindowEvent { event: WindowEvent::Resized(_), .. } => {
                    processor.recreate_swapchain(&surface);
                }
                Event::DeviceEvent { event: DeviceEvent::Key(keyboard_input), .. } => {
                    match keyboard_input.virtual_keycode.unwrap() {
                        VirtualKeyCode::A => {
                            if keyboard_input.state == ElementState::Pressed {
                                // processor.save_edges_image();
                            }
                        }
                        _ => ()
                    }
                }
//                Event::DeviceEvent { event: DeviceEvent::Button(mouse_input), .. } => {
//                    mouse_xy.x
//                },
                _ => ()
            }
        });

        if exit {
            break;
        }

        let mut compu_frame = CompuFrame::new();
//        compu_frame.add(compute_buffer.clone(), compute_kernel.clone());
//        compu_frame.add_with_image_swap(compute_buffer.clone(), compute_kernel.clone(), &compu_sprite1);
//
        let mut canvas = CanvasFrame::new();
        canvas.draw(&funky_sprite);
        canvas.draw(&test_polygon);

        {
            let g = hprof::enter("Run");
            processor.run(&surface,
                          canvas,
                          compu_frame);
        }
    }

    drop(l);


return;
    hprof::end_frame();
    hprof::profiler().print_timing();
}

































