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


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

use std::sync::Arc;

use vulkano::instance::debug::DebugCallback;
use vulkano::instance::Instance;
use vulkano::sync;
use vulkano::sync::GpuFuture;
use vulkano_win::VkSurfaceBuild;
use winit::dpi::LogicalSize;
use winit::event::{DeviceEvent, ElementState, Event, VirtualKeyCode, WindowEvent};
use winit::event_loop::{EventLoop, ControlFlow};
use winit::platform::unix::WindowBuilderExtUnix;
use winit::window::WindowBuilder;

use crate::canvas::canvas_frame::{CanvasFrame, Drawable};
use crate::canvas::managed::handles::{CanvasFontHandle, CanvasTextureHandle, Handle};
use crate::compute::compu_frame::CompuFrame;
use crate::compute::managed::handles::{CompuBufferHandle, CompuKernelHandle};
use crate::drawables::compu_sprite::CompuSprite;
use crate::drawables::rect::Rect;
use crate::drawables::sprite::Sprite;
use crate::drawables::text::Text;
use crate::util::load_raw;
use crate::util::timer::Timer;
use crate::util::vertex::{TextureVertex3D, VertexTypes};
use crate::vkprocessor::VkProcessor;
use std::path::Path;

pub mod util;
pub mod vkprocessor;
pub mod drawables;
pub mod canvas;
pub mod compute;

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 = EventLoop::new();

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

    let mut processor = VkProcessor::new(instance.clone(), surface.clone());

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

        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<dyn GpuFuture> =
        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: (f32, f32) = ((image_data.1).clone().0 as f32, (image_data.1).clone().1 as f32);
    let image_dimensions_u: (u32, u32) = image_data.1;
    let compu_sprite1: CompuSprite =
        CompuSprite::new((0.0, -0.5), (1.0, 1.0), 0, image_dimensions_f,
                         // Swap image to render the result to. Must match dimensions
                         processor.new_swap_image(image_dimensions_u));


    // Demo gpu toolpath generation

    // Need to
    let compute_buffer: Arc<CompuBufferHandle> =
        processor.new_compute_buffer(image_data.0.clone(), image_data.1, 4);

    let first_output_buffer: Arc<CompuBufferHandle> =
        processor.new_compute_buffer(image_data.0.clone(), image_data.1.clone(), 4);

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

    // Get the handles for the assets
    let funky_handle: Arc<CanvasTextureHandle> =
        processor.get_texture_handle(String::from("funky-bird.jpg")).unwrap();
    let sfml_handle: Arc<CanvasTextureHandle> =
        processor.get_texture_handle(String::from("sfml.png")).unwrap();
    //let font_handle : Arc<CanvasFontHandle> =
    //    processor.get_font_handle(String::from("sansation.ttf")).unwrap();

    let funky_sprite = Sprite::new((0.0, 0.5), (0.5, 0.5), 0, funky_handle.clone());
    let sfml_sprite = Sprite::new((0.0, -0.5), (0.5, 0.5), 1, sfml_handle.clone());
    let rect = Rect::new((-0.5, -0.5), (0.5, 0.5), 1);


    //let sfml_sprite  = Sprite::new((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), 1);
    //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");

    // 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.run(move |event, _, control_flow| {
        match event {
            Event::WindowEvent { event: WindowEvent::CloseRequested, .. } =>
                {
                    *control_flow = ControlFlow::Exit
                }
            Event::WindowEvent { event: WindowEvent::Resized(_), .. } => {
                processor.swapchain_recreate_needed = true;
            }
            Event::MainEventsCleared => {
                let mut canvas_frame = CanvasFrame::default();
                canvas_frame.draw(&funky_sprite);
                canvas_frame.draw(&text_sprite);
//        canvas_frame.draw(&rect);

                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);
                compu_frame.add(compute_buffer.clone(), compute_kernel.clone());

                canvas_frame.draw(&compu_sprite1);

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

            }
            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();
                        }
                    },
                    VirtualKeyCode::P => {
                        if keyboard_input.state == ElementState::Pressed {
                            let data = processor.read_compute_buffer(compute_buffer.clone());
                            image::save_buffer(&Path::new("image.png"), data.as_slice(), (image_data.1).0, (image_data.1).1, image::RGBA(8));
                        }
                    }
                    _ => ()
                }
            }
//                Event::DeviceEvent { event: DeviceEvent::Button(mouse_input), .. } => {
//                    mouse_xy.x
//                },
            _ => ()
        }
    });

    drop(l);

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

































