use cairo::XCBSurface;
use cairo::prelude::SurfaceExt;
use pango::LayoutExt;
use std::mem;
use xcb::ffi::*;

// this should in no way be hard-coded, but hey guess what it is
// right now deal with it
const WIDTH: i32 = 1920;
const HEIGHT: i32 = 38;

fn find_visual(conn: *mut xcb_connection_t, visual: xcb_visualid_t) -> *mut xcb_visualtype_t {
    unsafe {
        let screen_iter = xcb_setup_roots_iterator(xcb_get_setup(conn));
        while screen_iter.rem > 0 {
            let depth_iter = xcb_screen_allowed_depths_iterator(screen_iter.data);
            while depth_iter.rem > 0 {
                let visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
                while visual_iter.rem > 0 {
                    if visual == (*visual_iter.data).visual_id {
                        return visual_iter.data;
                    }
                    xcb_visualtype_next(&visual_iter as *const xcb_visualtype_iterator_t as *mut xcb_visualtype_iterator_t);
                }
                xcb_depth_next(&depth_iter as *const xcb_depth_iterator_t as *mut xcb_depth_iterator_t);
            }
            xcb_screen_next(&screen_iter as *const xcb_screen_iterator_t as *mut xcb_screen_iterator_t);
        }
        std::ptr::null_mut()
    }
}

fn mk_connection() -> *mut xcb_connection_t {
    unsafe {
        xcb_connect(std::ptr::null_mut(), std::ptr::null_mut())
    }
}


fn mk_window(conn: *mut xcb_connection_t) -> (*mut xcb_screen_t, xcb_window_t) {
    unsafe {
        let screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
        let window = xcb_generate_id(conn);
        let mask = [1, XCB_EVENT_MASK_EXPOSURE];
        xcb_create_window(conn, XCB_COPY_FROM_PARENT as u8, window, (*screen).root,
                          0, 0, WIDTH as u16, HEIGHT as u16, 0,
                          XCB_WINDOW_CLASS_INPUT_OUTPUT as u16,
                          (*screen).root_visual,
                          XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK,
                          mask.as_ptr());
        xcb_map_window(conn, window);
        (screen, window)
    }
}

fn main () {
    let conn = mk_connection();

    let (screen, window) = mk_window(conn);
    let visual = find_visual(conn, unsafe { (*screen).root_visual });

    let s = unsafe {
        <cairo::Surface as XCBSurface>::create(
            &cairo::XCBConnection::from_raw_none(mem::transmute::<*mut xcb_connection_t, *mut cairo_sys::xcb_connection_t>(conn)),
            &cairo::XCBDrawable(window),
            &cairo::XCBVisualType::from_raw_none(mem::transmute::<*mut xcb_visualtype_t, *mut cairo_sys::xcb_visualtype_t>(visual)),
            WIDTH,
            HEIGHT,
        )
    };
    let ctx = cairo::Context::new(&s);
    unsafe { xcb_flush(conn); }

    loop {
        let event = unsafe { xcb_wait_for_event(conn) };
        if let Some(e) = unsafe { event.as_ref() } {
            if (e.response_type & !0x80) == XCB_EXPOSE {
                ctx.set_source_rgb(0.2, 0.2, 0.2);
                ctx.paint();

                ctx.set_source_rgb(1.0, 1.0, 1.0);
                let layout = pangocairo::functions::create_layout(&ctx).unwrap();
                layout.set_width(1920 * 1024);
                let font = pango::FontDescription::from_string("Fira Mono 18");
                layout.set_font_description(&font);
                ctx.move_to(6.0, 4.0);
                layout.set_text("The quick brown fox jumps over the lazy dog.");
                pangocairo::functions::show_layout(&ctx, &layout);
                <&cairo::Surface as SurfaceExt>::flush(&&s);
            }
        } else {
            break;
        }
        unsafe { xcb_flush(conn); }
    }

    unsafe { xcb_disconnect(conn); }

}
