/* automatically generated by rust-bindgen 0.59.2 */
use std::convert::TryInto;
use std::ffi::CString;

pub type SizeT = ::std::os::raw::c_ulong;
pub type WcharT = ::std::os::raw::c_uint;
#[repr(C)]
#[repr(align(16))]
#[derive(Debug, Copy, Clone)]
pub struct max_align_t {
    pub __clang_max_align_nonce1: ::std::os::raw::c_longlong,
    pub __bindgen_padding_0: u64,
    pub __clang_max_align_nonce2: u128,
}
#[test]
fn bindgen_test_layout_max_align_t() {
    assert_eq!(
        ::std::mem::size_of::<max_align_t>(),
        32usize,
        concat!("Size of: ", stringify!(max_align_t))
    );
    assert_eq!(
        ::std::mem::align_of::<max_align_t>(),
        16usize,
        concat!("Alignment of ", stringify!(max_align_t))
    );
    assert_eq!(
        unsafe {
            &(*(::std::ptr::null::<max_align_t>())).__clang_max_align_nonce1 as *const _ as usize
        },
        0usize,
        concat!(
            "Offset of field: ",
            stringify!(max_align_t),
            "::",
            stringify!(__clang_max_align_nonce1)
        )
    );
    assert_eq!(
        unsafe {
            &(*(::std::ptr::null::<max_align_t>())).__clang_max_align_nonce2 as *const _ as usize
        },
        16usize,
        concat!(
            "Offset of field: ",
            stringify!(max_align_t),
            "::",
            stringify!(__clang_max_align_nonce2)
        )
    );
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct uws_app_s {
    _unused: [u8; 0],
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct uws_req_s {
    _unused: [u8; 0],
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct uws_res_s {
    _unused: [u8; 0],
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct uws_app_listen_config_s {
    port: ::std::os::raw::c_int,
    host: *const ::std::os::raw::c_char,
    options: ::std::os::raw::c_int,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct us_socket_context_options_s {
    key_file_name: *const ::std::os::raw::c_char,
    cert_file_name: *const ::std::os::raw::c_char,
    passphrase: *const ::std::os::raw::c_char,
    dh_params_file_name: *const ::std::os::raw::c_char,
    ca_file_name: *const ::std::os::raw::c_char,
    ssl_prefer_low_memory_usage: ::std::os::raw::c_int,
}

pub type UwsAppListenConfigT = uws_app_listen_config_s;
pub type UsSocketContextOptionsT = us_socket_context_options_s;
pub struct UsSocketContextOptions<'a> {
    key_file_name: &'a str,
    cert_file_name: &'a str,
    passphrase: &'a str,
    dh_params_file_name: &'a str,
    ca_file_name: &'a str,
    ssl_prefer_low_memory_usage: i32,
}
pub type UwsAppT = uws_app_s;
pub type UwsReqT = uws_req_s;
pub type UwsResT = uws_res_s;
extern "C" {
    pub fn uws_create_app(
        ssl: ::std::os::raw::c_int,
        options: UsSocketContextOptionsT,
    ) -> *mut UwsAppT;
    pub fn uws_app_get(
        ssl: ::std::os::raw::c_int,
        app: *mut UwsAppT,
        pattern: *const ::std::os::raw::c_char,
        handler: ::std::option::Option<
            unsafe extern "C" fn(
                res: *mut UwsResT,
                req: *mut UwsReqT,
                user_data: *mut ::std::os::raw::c_void,
            ),
        >,
        user_data: *mut ::std::os::raw::c_void,
    );
    pub fn uws_app_run(ssl: ::std::os::raw::c_int, app: *mut UwsAppT);

    pub fn uws_app_listen(
        ssl: ::std::os::raw::c_int,
        app: *mut UwsAppT,
        port: ::std::os::raw::c_int,
        handler: ::std::option::Option<
            unsafe extern "C" fn(
                listen_socket: *mut ::std::os::raw::c_void,
                config: UwsAppListenConfigT,
                user_data: *mut ::std::os::raw::c_void,
            ),
        >,
        user_data: *mut ::std::os::raw::c_void,
    );
    pub fn uws_res_end(
        ssl: ::std::os::raw::c_int,
        res: *mut UwsResT,
        data: *const ::std::os::raw::c_char,
        length: SizeT,
        close_connection: bool,
    );
}

pub struct AppResponse<const SSL: i32> {
    native: *mut UwsResT,
}
pub struct AppRequest {
    native: *mut UwsReqT,
}
impl AppRequest {
    pub fn new(native: *mut UwsReqT) -> AppRequest {
        AppRequest { native: native }
    }
}
impl<const SSL: i32> AppResponse<SSL> {
    pub fn new(native: *mut UwsResT) -> AppResponse<SSL> {
        AppResponse::<SSL> { native: native }
    }
    fn end(self, message: &str) -> AppResponse<SSL> {
        unsafe {
            let c_message =
                ::std::ffi::CString::new(message).expect("Failed to create message CString");
            //This will now const fold :/ performance impact needs refactor
            uws_res_end(
                SSL,
                self.native,
                c_message.as_ptr(),
                message.len().try_into().unwrap(),
                false,
            );
        }
        self
    }
}

pub type UwsMethodHandler<const SSL: i32> = fn(res: AppResponse<SSL>, req: AppRequest);
pub type UwsListenHandler =
    fn(listen_socket: *mut ::std::os::raw::c_void, config: UwsAppListenConfigT);

pub struct TemplateApp<const SSL: i32> {
    native: *mut UwsAppT,
}

extern "C" fn uws_generic_listen_handler(
    listen_socket: *mut ::std::os::raw::c_void,
    config: UwsAppListenConfigT,
    user_data: *mut ::std::os::raw::c_void,
) {
    unsafe {
        let callback = &mut *(user_data as *mut UwsListenHandler);
        callback(listen_socket, config);
    }
}

extern "C" fn uws_generic_method_handler(
    res: *mut UwsResT,
    req: *mut UwsReqT,
    user_data: *mut ::std::os::raw::c_void,
) {
    unsafe {
        let response = AppResponse::<0>::new(res);
        let request = AppRequest::new(req);
        let callback = &mut *(user_data as *mut UwsMethodHandler<0>);
        callback(response, request);
    }
}
extern "C" fn uws_ssl_generic_method_handler(
    res: *mut UwsResT,
    req: *mut UwsReqT,
    user_data: *mut ::std::os::raw::c_void,
) {
    unsafe {
        let response = AppResponse::<1>::new(res);
        let request = AppRequest::new(req);
        let callback = &mut *(user_data as *mut UwsMethodHandler<1>);
        callback(response, request);
    }
}

impl<const SSL: i32> TemplateApp<SSL> {
    pub fn new(config: UsSocketContextOptions) -> TemplateApp<SSL> {
        unsafe {
            let key_file_name_s =
                CString::new(config.key_file_name).expect("Failed to create key_file_name CString");
            let cert_file_name_s = CString::new(config.cert_file_name)
                .expect("Failed to create cert_file_name CString");
            let passphrase_s =
                CString::new(config.passphrase).expect("Failed to create passphrase CString");
            let dh_params_file_name_s = CString::new(config.dh_params_file_name)
                .expect("Failed to create dh_params_file_name CString");
            let ca_file_name_s =
                CString::new(config.ca_file_name).expect("Failed to create ca_file_name CString");

            let native_options = UsSocketContextOptionsT {
                key_file_name: key_file_name_s.as_ptr(),
                cert_file_name: cert_file_name_s.as_ptr(),
                passphrase: passphrase_s.as_ptr(),
                dh_params_file_name: dh_params_file_name_s.as_ptr(),
                ca_file_name: ca_file_name_s.as_ptr(),
                ssl_prefer_low_memory_usage: config.ssl_prefer_low_memory_usage,
            };
            TemplateApp::<SSL> {
                native: uws_create_app(SSL, native_options),
            }
        }
    }
    pub fn get(self, route: &str, mut handler: UwsMethodHandler<SSL>) -> TemplateApp<SSL> {
        unsafe {
            let c_route = ::std::ffi::CString::new(route).expect("Failed to create route CString");
            if SSL == 1 {
                uws_app_get(
                    SSL,
                    self.native,
                    c_route.as_ptr(),
                    std::option::Option::Some(uws_ssl_generic_method_handler),
                    &mut handler as *mut _ as *mut ::std::os::raw::c_void,
                );
            } else {
                uws_app_get(
                    SSL,
                    self.native,
                    c_route.as_ptr(),
                    std::option::Option::Some(uws_generic_method_handler),
                    &mut handler as *mut _ as *mut ::std::os::raw::c_void,
                );
            }
        }
        self
    }

    pub fn listen(self, port: i32, mut handler: UwsListenHandler) -> TemplateApp<SSL> {
        unsafe {
            uws_app_listen(
                SSL,
                self.native,
                port,
                ::std::option::Option::Some(uws_generic_listen_handler),
                &mut handler as *mut _ as *mut ::std::os::raw::c_void,
            );
        }
        self
    }

    pub fn run(self) -> TemplateApp<SSL> {
        unsafe {
            uws_app_run(SSL, self.native);
        }
        self
    }
}
pub type App = TemplateApp<0>;
pub type SSLApp = TemplateApp<1>;

fn main() {
    let config = UsSocketContextOptions {
        key_file_name: "../misc/key.pem",
        cert_file_name: "../misc/cert.pem",
        passphrase: "1234",
        ca_file_name: "",
        dh_params_file_name: "",
        ssl_prefer_low_memory_usage: 0,
    };

    SSLApp::new(config)
        .get("/", |res, _req| {
            res.end("Hello Rust!");
        })
        .listen(3000, |_listen_socket, config| {
            println!("Listening on port https://127.0.0.1:{}", config.port);
        })
        .run();
}
