mod device;
mod model;

#[macro_use]
extern crate glium;
extern crate nalgebra_glm as glm;

use model::Model;

#[derive(Copy, Clone)]
struct Vertex {
    position: [f32; 3],
    color: [f32; 3],
}

implement_vertex!(Vertex, position, color);

fn main() {
    use glium::{glutin, Surface};
    
    let events_loop = glutin::event_loop::EventLoop::new();
    let wb = glutin::window::WindowBuilder::new()
        .with_title("Couch Game Engine");
    let cb = glutin::ContextBuilder::new();

    let display = glium::Display::new(wb, cb, &events_loop).unwrap();

    let vertex1 = Vertex { position: [-0.5, -0.5 , 0.0], color: [1.0, 0.0, 0.0] };
    let vertex2 = Vertex { position: [ 0.0,  0.5 , 0.0], color: [0.0, 1.0, 0.0] };
    let vertex3 = Vertex { position: [ 0.5, -0.25, 0.0], color: [0.0, 0.0, 1.0] };
    let shape = vec![vertex1, vertex2, vertex3];

    let vertex_buffer = glium::VertexBuffer::new(&display, &shape).unwrap();
    let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

    let vertex_shader_src = include_str!("flat.vert");
    let fragment_shader_src = include_str!("flat.frag");
    let flat_program = glium::Program::from_source(&display, vertex_shader_src, fragment_shader_src, None).unwrap();

    let vertex_shader_src = include_str!("cube.vert");
    let fragment_shader_src = include_str!("cube.frag");
    let cube_program = glium::Program::from_source(&display, vertex_shader_src, fragment_shader_src, None).unwrap();

    let mut device_manager = crate::device::DeviceManager::new();

    let mut offset = 0.0;
    let mut rotate = 0.0;

    let model = Model::new(&display, "Lantern.glb");

    events_loop.run(move |ev, _, control_flow| {
	if device_manager.is_pressed(&device::Key::W) {
	    offset += 0.001;
	} else if device_manager.is_pressed(&device::Key::S) {
	    offset -= 0.001;
	}
	if device_manager.is_pressed(&device::Key::A) {
	    rotate += 0.01;
	} else if device_manager.is_pressed(&device::Key::D) {
	    rotate -= 0.01;
	}
	    
        let mvp = glm::perspective::<f32>(4.0/3.0, 45.0_f32.to_radians(), 0.2, 100.0);
        let mvp = glm::translate::<f32>(&mvp, &glm::vec3(0.0, 0.0, -10.0 + offset));
	let mvp = glm::rotate::<f32>(&mvp, 15.0_f32.to_radians() + rotate, &glm::vec3(1.0, 0.0, 0.0));
        let uniforms = uniform! {
            MVP: *mvp.as_ref(),
        };

        let mut target = display.draw();
	let params = glium::DrawParameters {
	    depth: glium::Depth {
		test: glium::DepthTest::IfLess,
		write: true,
		.. Default::default()
	    },
	    backface_culling: glium::draw_parameters::BackfaceCullingMode::CullClockwise,
	    .. Default::default()
	};
        target.clear_color(0.0, 0.0, 0.0, 1.0);
        target.draw(&vertex_buffer, &indices, &flat_program, &uniforms, &params).unwrap();
	model.draw(&mut target, &cube_program, &uniforms);
        target.finish().unwrap();
        
        
        let next_frame_time = std::time::Instant::now() +
            std::time::Duration::from_nanos(16_666_667);
        *control_flow = glutin::event_loop::ControlFlow::WaitUntil(next_frame_time);
	match ev {
	    glutin::event::Event::WindowEvent { event, .. } => {
		if event == glutin::event::WindowEvent::CloseRequested {
                    *control_flow = glutin::event_loop::ControlFlow::Exit;
		}
	    },
	    glutin::event::Event::DeviceEvent { event, .. } => {
		device_manager.handle(event);
	    },
	    _ => (),
        };
    });
}
