extern crate cc;

use std::fs::File;
use std::path::Path;
use std::io::{Result, Write};

fn main() {
	println!("cargo:rerun-if-env-changed=LOG");

	let arch: String = std::env::var("ARCH").unwrap();
	match arch.as_str() {
		"x86_64" => {
			// cc::Build::new()
			// 	.file("src/arch/x86_64/driver/apic/lapic.c")
			// 	.file("src/arch/x86_64/driver/keyboard/keyboard.c")
			// 	.flag("-mcmodel=large")
			// 	.compile("cobj");
			gen_vector_asm().unwrap();
		}
		"riscv32" => {
			cc::Build::new()
				.file("src/arch/riscv32/compiler_rt.c")
				.flag("-march=rv32ia")
				.flag("-mabi=ilp32")
				.compile("atomic_rt");
			if let Ok(file_path) = gen_sfsimg_asm() {
				cc::Build::new()
					.file(&file_path)
					.flag("-march=rv32ia")
					.flag("-mabi=ilp32")
					.compile("sfsimg");
			}
		}
		"aarch64" => {
			if let Ok(file_path) = gen_sfsimg_asm() {
				cc::Build::new().file(&file_path).compile("sfsimg");
			}
		}
		_ => panic!("Unknown arch {}", arch),
	}
}

fn gen_vector_asm() -> Result<()> {
	let mut f = File::create("src/arch/x86_64/interrupt/vector.asm").unwrap();

	writeln!(f, "# generated by build.rs - do not edit")?;
	writeln!(f, ".section .text")?;
	writeln!(f, ".intel_syntax noprefix")?;
	for i in 0..256 {
		writeln!(f, "vector{}:", i)?;
		if !(i == 8 || (i >= 10 && i <= 14) || i == 17) {
			writeln!(f, "\tpush 0")?;
		}
		writeln!(f, "\tpush {}", i)?;
		writeln!(f, "\tjmp __alltraps")?;
	}

	writeln!(f, "\n.section .rodata")?;
	writeln!(f, ".global __vectors")?;
	writeln!(f, "__vectors:")?;
	for i in 0..256 {
		writeln!(f, "\t.quad vector{}", i)?;
	}
	Ok(())
}

fn gen_sfsimg_asm() -> Result<std::path::PathBuf> {
	let out_dir = std::env::var("OUT_DIR").unwrap();
	let sfsimg = std::env::var("SFSIMG").unwrap();

	let file_path = Path::new(&out_dir).join("sfsimg.S");
	let mut f = File::create(&file_path).unwrap();

	write!(f, "# generated by build.rs - do not edit")?;
	write!(f, r#"
	.section .rodata
	.align 12
	.global _user_img_start
	.global _user_img_end
_user_img_start:
    .incbin "{}"
_user_img_end:
"#, sfsimg)?;

	println!("cargo:rerun-if-changed={}", sfsimg);
	println!("cargo:rerun-if-env-changed=SFSIMG");

	Ok(file_path)
}
