use std::env;
use std::fs;
use std::path::{Path, PathBuf};


#[cfg(all(target_env = "msvc", not(feature = "vendored")))]
fn try_vcpkg() -> Option<Vec<PathBuf>> {
    let lib = vcpkg::Config::new()
        .emit_includes(true)
        .find_package("nettle");

    match lib {
        Ok(lib) => Some(lib.include_paths),
        Err(e) => {
            println!("note: vcpkg did not find openssl: {}", e);
            None
        }
    }
}

#[cfg(any(not(target_env = "msvc"), feature = "vendored"))]
fn try_vcpkg() -> Option<Vec<PathBuf>> { None }

fn print_library(lib: &pkg_config::Library, mode: &str) {
	for p in &lib.include_paths {
		println!("cargo:include={}", p.display());
	}

	for p in &lib.frameworks {
		println!("cargo:rustc-link-lib=framework={}", p);
	}

	for p in &lib.framework_paths {
		println!("cargo:rustc-link-search=framework={}", p.display());
	}

    for p in &lib.libs {
        println!("cargo:rustc-link-lib={}={}", mode, p);
    }

    for p in &lib.link_paths {
        println!("cargo:rustc-link-search=native={}", p.display());
    }
}

fn try_pkg_config() -> Option<Vec<PathBuf>> {
    let nettle = pkg_config::probe_library("nettle hogweed").unwrap();

    let mode = match env::var_os("NETTLE_STATIC") {
        Some(_) => "static",
        None => "dylib",
    };

    print_library(&nettle, mode);
    println!("cargo:rustc-link-lib={}=gmp", mode);
    Some(nettle.include_paths)
}

const NETTLE_PREGENERATED_BINDINGS: &str = "NETTLE_PREGENERATED_BINDINGS";

fn main() {
    println!("cargo:rerun-if-env-changed=NETTLE_STATIC");
    println!("cargo:rerun-if-env-changed={}", NETTLE_PREGENERATED_BINDINGS);

    #[cfg(feature = "vendored")]
    {
        let artifacts = nettle_src::Build::new().build();
        println!("cargo:vendored=1");
        env::set_var("PKG_CONFIG_PATH", artifacts.lib_dir().join("pkgconfig"));
    }

    let include_paths = try_vcpkg().or_else(try_pkg_config).unwrap();

    let out_path = Path::new(&env::var("OUT_DIR").unwrap()).join("bindings.rs");

    // Check if we have a bundled bindings.rs.
    if let Ok(bundled) = env::var(NETTLE_PREGENERATED_BINDINGS)
    {
        let p = Path::new(&bundled);
        if p.exists() {
            fs::copy(&p, &out_path).expect("Could not copy bundled bindings");
            println!("cargo:rerun-if-changed={:?}", p);

            // We're done.
            return;
        }
    }

    let mut builder = bindgen::Builder::default()
        // Includes all nettle headers except mini-gmp.h
        .header("bindgen-wrapper.h")
        // Workaround for https://github.com/rust-lang-nursery/rust-bindgen/issues/550
        .blacklist_type("max_align_t")
        .blacklist_function("strtold")
        .blacklist_function("qecvt")
        .blacklist_function("qfcvt")
        .blacklist_function("qgcvt")
        .blacklist_function("qecvt_r")
        .blacklist_function("qfcvt_r")
        .size_t_is_usize(true);

    for p in include_paths {
        builder = builder.clang_arg(format!("-I{}", p.display()));
    }

    let bindings = builder.generate().unwrap();
    bindings.write_to_file(out_path).expect("Couldn't write bindings!");
}
