use form::create_directory_structure;
use svd2rust::generate;
use svd2rust::util::{Config, Target, SourceType};
use std::env;
use std::fs::File;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use regex::Regex;

mod inner {
    use super::*;
    /// This is modified stuff originally generated by `svd2rust`
    /// Hack our way out keeping it here.
    pub fn main(device_rs: &str) {
        if env::var_os("CARGO_FEATURE_RT").is_some() {
            let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
            File::create(out.join("device.x"))
                .unwrap()
                // .write_all(include_bytes!("device.x"))
                .write_all(device_rs.as_bytes())
                .unwrap();
            println!("cargo:rustc-link-search={}", out.display());
            println!("cargo:rerun-if-changed=device.x");
        }
        println!("cargo:rerun-if-changed=build.rs");
    }
}

fn write_lib_rs(path: &Path, content: &str) {
    //let mut file = File::create(path.join("lib.rs")).expect("Couldn't create output file");

    //let data = items.to_string().replace("] ", "]\n");
    // file.write_all(content.as_bytes()/*data.as_ref()*/)
        // .expect("Could not write code to lib.rs");

    create_directory_structure(path, content)
        .expect("Directory structure creation failed!");

    println!("cargo:rerun-if-changed=lib.rs");
}

const SVDFILE: &str = "svd/chip.svd";

fn main() {
    let config = Config {
        target: Target::CortexM,
        atomics: false,
        atomics_feature: None,
        generic_mod: false,
        make_mod: true,
        const_generic: true,
        ignore_groups: false,
        keep_list: false,
        strict: true,
        pascal_enum_values: false,
        feature_group: false,
        feature_peripheral: false,
        max_cluster_size: false,
        impl_debug: false, // TODO: consider this behind feature flag
        impl_debug_feature: None,
        output_dir: Path::new(&env::var_os("OUT_DIR").unwrap()).into(),
        input: None,
        source_type: SourceType::from_path(Path::new(SVDFILE)),
        log_level: None,
        interrupt_link_section: None,
    };

    let input = &mut String::new();
    File::open(SVDFILE)
                .expect("Cannot open the SVD file")
                .read_to_string(input)
                .expect("Cannot read the SVD file");
    let generation = generate(input, &config).unwrap();

    let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());

    // Patch content
    let re = Regex::new(r#"#\s*!\s*\[\s*doc\s*=\s*"[^"]+"\s*]"#).unwrap();
    let modified = re.replace(&generation.lib_rs, "");
    // Dump generation.lib_rs content
    write_lib_rs(out.as_path(), &modified);

    // Dump generation.device_specific.device_x content
    if let Some(device_specific) = &generation.device_specific {
        inner::main(&device_specific.device_x);
    }
    // TODO: generation.device_specific.build_rs = content? huston, we have a problem!

    println!("cargo:rustc-link-search={}", out.display());
}
