pub mod bsp;
pub mod mesh;
mod brush;

const VALVE_SCALE:f32=1.0/16.0;
pub(crate) fn valve_transform_dist(d:f32)->strafesnet_common::integer::Planar64{
	(d*VALVE_SCALE).try_into().unwrap()
}
pub(crate) fn valve_transform_normal([x,y,z]:[f32;3])->strafesnet_common::integer::Planar64Vec3{
	strafesnet_common::integer::vec3::try_from_f32_array([x,z,-y]).unwrap()
}
pub(crate) fn valve_transform([x,y,z]:[f32;3])->strafesnet_common::integer::Planar64Vec3{
	strafesnet_common::integer::vec3::try_from_f32_array([x*VALVE_SCALE,z*VALVE_SCALE,-y*VALVE_SCALE]).unwrap()
}

#[derive(Debug)]
pub enum ReadError{
	Bsp(vbsp::BspError),
	Io(std::io::Error),
}
impl std::fmt::Display for ReadError{
	fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
		write!(f,"{self:?}")
	}
}
impl std::error::Error for ReadError{}

pub struct Bsp{
	bsp:vbsp::Bsp,
	case_folded_file_names:std::collections::HashMap<String,String>,
}
impl AsRef<vbsp::Bsp> for Bsp{
	fn as_ref(&self)->&vbsp::Bsp{
		&self.bsp
	}
}

pub fn read<R:std::io::Read>(mut input:R)->Result<Bsp,ReadError>{
	let mut s=Vec::new();

	//TODO: mmap
	input.read_to_end(&mut s).map_err(ReadError::Io)?;

	vbsp::Bsp::read(s.as_slice()).map(Bsp::new).map_err(ReadError::Bsp)
}
impl Bsp{
	pub fn new(bsp:vbsp::Bsp)->Self{
		let case_folded_file_names=bsp.pack.clone().into_zip().lock().unwrap().file_names().map(|s|{
			(s.to_lowercase(),s.to_owned())
		}).collect();
		Self{
			bsp,
			case_folded_file_names,
		}
	}
	pub fn pack_get(&self,name_lowercase:&str)->Result<Option<Vec<u8>>,vbsp::BspError>{
		match self.case_folded_file_names.get(name_lowercase){
			Some(name_folded)=>self.bsp.pack.get(name_folded),
			None=>Ok(None),
		}
	}
}
pub struct Vpk{
	vpk:vpk::VPK,
	case_folded_file_names:std::collections::HashMap<String,String>,
}
impl AsRef<vpk::VPK> for Vpk{
	fn as_ref(&self)->&vpk::VPK{
		&self.vpk
	}
}
impl Vpk{
	pub fn new(vpk:vpk::VPK)->Vpk{
		let case_folded_file_names=vpk.tree.keys().map(|s|{
			(s.to_lowercase(),s.to_owned())
		}).collect();
		Vpk{
			vpk,
			case_folded_file_names,
		}
	}
	pub fn tree_get(&self,name_lowercase:&str)->Option<&vpk::entry::VPKEntry>{
		let name_folded=self.case_folded_file_names.get(name_lowercase)?;
		self.vpk.tree.get(name_folded)
	}
}
