A rust port of vgm2mid by Paul Jensen and Valley Bell
pub mod ay8910;
pub mod config;
pub mod gameboy;
pub mod gd3;
pub mod gym;
pub mod midi_shim;
pub mod nesapu;
pub mod pcm;
pub mod sn76489;
pub mod utils;
pub mod vgm;
pub mod vgm2mid;
pub mod ym2151;
pub mod ym2413;
pub mod ym2612;
pub mod ym3812;
pub mod ymf278;

use crate::gym::convert_gym_to_mid;
use crate::vgm::convert_vgm_to_mid;
use crate::config::Config;
use anyhow::{Context, Result};
use flate2::bufread::GzDecoder;
use std::io::Read;
use std::path::Path;
use once_cell::sync::OnceCell;

pub(crate) static STRICT: OnceCell<bool> = OnceCell::new();
pub(crate) static VERBOSE: OnceCell<bool> = OnceCell::new();

#[macro_export]
macro_rules! strict {
	() => {
		if $crate::STRICT.get().map(|r| *r).unwrap_or(false) {
			anyhow::bail!("Strict violation.");
		}
	};
	($($arg:tt)*)  => {
	{
		$crate::verbose!($($arg)*);
		if $crate::STRICT.get().map(|r| *r).unwrap_or(false) {
			anyhow::bail!("Strict violation.");
		}
	}
	};
}

#[macro_export]
macro_rules! verbose {
	($($arg:tt)*) => {
		if $crate::VERBOSE.get().map(|r| *r).unwrap_or(false) {
			std::println!($($arg)*);
		}
	}
}

pub enum FileType {
	Gym,
	Vgm,
	Vgz,
}

pub fn convert_to_mid(
	in_path: &Path,
	file_type: FileType,
	out_path: &Path,
	config: &Config,
) -> Result<()> {
	let _metadata = std::fs::metadata(in_path)
		.with_context(|| format!("Failed to load file metadata: {}", in_path.display()))?;

	let data = std::fs::read(in_path)
		.with_context(|| format!("Failed to load data from file: {}", in_path.display()))?;

	let mut midi = midi_shim::MIDIShim::new(config)?;

	match file_type {
		FileType::Gym => convert_gym_to_mid(data.as_slice(), config, &mut midi),
		FileType::Vgm => convert_vgm_to_mid(data.as_slice(), config, &mut midi),
		FileType::Vgz => {
			let mut buf = Vec::<u8>::new();
			GzDecoder::new(data.as_slice()).read_to_end(&mut buf)?;
			convert_vgm_to_mid(buf.as_slice(), config, &mut midi)
		},
	}?;

	midi.write_smf(out_path)?;

	Ok(())
}