use async_once_cell::OnceCell;
use infer::{Infer, Type};
use simple_error::SimpleResult;
use std::path::Path;
pub const BPS_EXTENSION: &str = "bps";
pub const CHD_EXTENSION: &str = "chd";
pub const CSO_EXTENSION: &str = "cso";
pub const GZ_EXTENSION: &str = "gz";
pub const IPS_EXTENSION: &str = "ips";
pub const IRD_EXTENSION: &str = "ird";
pub const ISO_EXTENSION: &str = "iso";
pub const RDSK_EXTENSION: &str = "rdsk";
pub const RIFF_EXTENSION: &str = "riff";
pub const RVZ_EXTENSION: &str = "rvz";
pub const XDELTA_EXTENSION: &str = "xdelta";
pub const ZSO_EXTENSION: &str = "zso";
static MATCHER: OnceCell<Infer> = OnceCell::new();
fn bps_matcher(buf: &[u8]) -> bool {
buf.len() >= 4 && buf[0] == 0x42 && buf[1] == 0x50 && buf[2] == 0x53 && buf[3] == 0x31
}
fn chd_matcher(buf: &[u8]) -> bool {
buf.len() >= 8
&& buf[0] == 0x4D
&& buf[1] == 0x43
&& buf[2] == 0x6F
&& buf[3] == 0x6D
&& buf[4] == 0x70
&& buf[5] == 0x72
&& buf[6] == 0x48
&& buf[7] == 0x44
}
fn cso_matcher(buf: &[u8]) -> bool {
buf.len() >= 4 && buf[0] == 0x43 && buf[1] == 0x49 && buf[2] == 0x53 && buf[3] == 0x4F
}
fn ips_matcher(buf: &[u8]) -> bool {
buf.len() >= 5
&& buf[0] == 0x50
&& buf[1] == 0x41
&& buf[2] == 0x54
&& buf[3] == 0x43
&& buf[4] == 0x48
}
fn ird_matcher(buf: &[u8]) -> bool {
buf.len() >= 4 && buf[0] == 0x33 && buf[1] == 0x49 && buf[2] == 0x52 && buf[3] == 0x44
}
fn rdsk_matcher(buf: &[u8]) -> bool {
buf.len() >= 4 && buf[0] == 0x52 && buf[1] == 0x44 && buf[2] == 0x53 && buf[3] == 0x4B
}
fn riff_matcher(buf: &[u8]) -> bool {
buf.len() >= 4 && buf[0] == 0x52 && buf[1] == 0x49 && buf[2] == 0x46 && buf[3] == 0x46
}
fn rvz_matcher(buf: &[u8]) -> bool {
buf.len() >= 4 && buf[0] == 0x52 && buf[1] == 0x56 && buf[2] == 0x5A && buf[3] == 0x01
}
fn xdelta_matcher(buf: &[u8]) -> bool {
buf.len() >= 3 && buf[0] == 0xD6 && buf[1] == 0xC3 && buf[2] == 0xC4
}
fn zso_matcher(buf: &[u8]) -> bool {
buf.len() >= 4 && buf[0] == 0x5A && buf[1] == 0x49 && buf[2] == 0x53 && buf[3] == 0x4F
}
async fn init_matcher() -> Infer {
let mut matcher = Infer::new();
matcher.add("application/x-bps", BPS_EXTENSION, bps_matcher);
matcher.add("application/x-chd", CHD_EXTENSION, chd_matcher);
matcher.add("application/x-cso", CSO_EXTENSION, cso_matcher);
matcher.add("application/x-ips", IPS_EXTENSION, ips_matcher);
matcher.add("application/x-ird", IRD_EXTENSION, ird_matcher);
matcher.add("application/x-rdsk", RDSK_EXTENSION, rdsk_matcher);
matcher.add("application/x-riff", RIFF_EXTENSION, riff_matcher);
matcher.add("application/x-rvz", RVZ_EXTENSION, rvz_matcher);
matcher.add("application/x-xdelta", XDELTA_EXTENSION, xdelta_matcher);
matcher.add("application/x-zso", ZSO_EXTENSION, zso_matcher);
matcher
}
pub async fn get_mimetype<P: AsRef<Path>>(path: &P) -> SimpleResult<Option<Type>> {
let matcher = MATCHER.get_or_init(init_matcher()).await;
Ok(try_with!(
matcher.get_from_path(path),
"Failed to infer MIME type"
))
}