use std::ops::RangeInclusive;
use std::fmt::{ Debug, Formatter, Result as FmtResult };
use std::marker::PhantomData;
use num_enum::{ FromPrimitive, IntoPrimitive };
use enumset::{ EnumSet, EnumSetType };
use bytemuck::{ Zeroable, Pod };
use mchr::Std as StdEncoding;
use super::ReadError;
use super::core::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(FromPrimitive, IntoPrimitive)]
#[repr(u16)]
pub enum Platform {
	Unicode = 0,
	Macintosh = 1,
	Windows = 3,
	#[num_enum(catch_all)]
	Unknown(u16),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[derive(FromPrimitive, IntoPrimitive)]
#[repr(u16)]
pub enum UnicodeVersion {
	Version1_0 = 0,
	Version1_1 = 1,
	Iso10646 = 2,
	Unicode2BmpOnly = 3,
	Unicode2 = 4,
	#[num_enum(catch_all)]
	Unknown(u16),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[derive(FromPrimitive, IntoPrimitive)]
#[repr(u16)]
pub enum UnicodeLanguage {
	None = 0,
	#[num_enum(catch_all)]
	Unknown(u16),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[derive(FromPrimitive, IntoPrimitive)]
#[repr(u16)]
pub enum ScriptManagerCode {
	Roman = 0,
	Japanese = 1,
	TraditionalChinese = 2,
	Korean = 3,
	Arabic = 4,
	Hebrew = 5,
	Greek = 6,
	Russian = 7,
	RSymbol = 8,
	Devanagari = 9,
	Gurmukhi = 10,
	Gujarati = 11,
	Oriya = 12,
	Bengali = 13,
	Tamil = 14,
	Telugu = 15,
	Kannada = 16,
	Malayalam = 17,
	Sinhalese = 18,
	Burmese = 19,
	Khmer = 20,
	Thai = 21,
	Laotian = 22,
	Georgian = 23,
	Armenian = 24,
	SimplifiedChinese = 25,
	Tibetan = 26,
	Mongolian = 27,
	Geez = 28,
	Slavic = 29,
	Vietnamese = 30,
	Sindhi = 31,
	#[num_enum(catch_all)]
	Unknown(u16),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[derive(FromPrimitive, IntoPrimitive)]
#[repr(u16)]
pub enum MacintoshLanguage {
	English = 0,
	French = 1,
	German = 2,
	Italian = 3,
	Dutch = 4,
	Swedish = 5,
	Spanish = 6,
	Danish = 7,
	Portuguese = 8,
	Norwegian = 9,
	Hebrew = 10,
	Japanese = 11,
	Arabic = 12,
	Finnish = 13,
	Greek = 14,
	Icelandic = 15,
	Maltese = 16,
	Turkish = 17,
	Croatian = 18,
	TraditionalChinese = 19,
	Urdu = 20,
	Hindi = 21,
	Thai = 22,
	Korean = 23,
	Lithuanian = 24,
	Polish = 25,
	Hungarian = 26,
	Estonian = 27,
	Latvian = 28,
	Sami = 29,
	Faroese = 30,
	FarsiPersian = 31,
	Russian = 32,
	SimplifiedChinese = 33,
	Flemish = 34,
	IrishGaelic = 35,
	Albanian = 36,
	Romanian = 37,
	Czech = 38,
	Slovak = 39,
	Slovenian = 40,
	Yiddish = 41,
	Serbian = 42,
	Macedonian = 43,
	Bulgarian = 44,
	Ukrainian = 45,
	Byelorussian = 46,
	Uzbek = 47,
	Kazakh = 48,
	AzerbaijaniCyrillic = 49,
	AzerbaijaniArabic = 50,
	Armenian = 51,
	Georgian = 52,
	Moldavian = 53,
	Kirghiz = 54,
	Tajiki = 55,
	Turkmen = 56,
	Mongolian = 57,
	MongolianCyrillic = 58,
	Pashto = 59,
	Kurdish = 60,
	Kashmiri = 61,
	Sindhi = 62,
	Tibetan = 63,
	Nepali = 64,
	Sanskrit = 65,
	Marathi = 66,
	Bengali = 67,
	Assamese = 68,
	Gujarati = 69,
	Punjabi = 70,
	Oriya = 71,
	Malayalam = 72,
	Kannada = 73,
	Tamil = 74,
	Telugu = 75,
	Sinhalese = 76,
	Burmese = 77,
	Khmer = 78,
	Lao = 79,
	Vietnamese = 80,
	Indonesian = 81,
	Tagalog = 82,
	MalayRoman = 83,
	MalayArabic = 84,
	Amharic = 85,
	Tigrinya = 86,
	Galla = 87,
	Somalia = 88,
	Swahili = 89,
	KinyarwandaRuanda = 90,
	Rundi = 91,
	NyanjaChewa = 92,
	Malagasy = 93,
	Esperanto = 94,
	Welsh = 128,
	Basque = 129,
	Catalan = 130,
	Latin = 131,
	Quechua = 132,
	Guarani = 133,
	Aymara = 134,
	Tatar = 135,
	Uighur = 136,
	Dzongkha = 137,
	JavaneseRoman = 138,
	SundaneseRoman = 139,
	Galician = 140,
	Afrikaans = 141,
	Breton = 142,
	Inuktitut = 143,
	ScottishGaelic = 144,
	ManxGaelic = 145,
	IrishGaelicWithDotAbove = 146,
	Tongan = 147,
	GreekPolytonic = 148,
	Greenlandic = 149,
	AzerbaijaniRoman = 150,
	#[num_enum(catch_all)]
	Unknown(u16),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[derive(FromPrimitive, IntoPrimitive)]
#[repr(u16)]
pub enum WindowsEncoding {
	Symbol = 0,
	UnicodeBmp = 1,
	ShiftJis = 2,
	Prc = 3,
	Big5 = 4,
	Wansung = 5,
	Johab = 6,
	UnicodeFullRepertoire = 10,
	#[num_enum(catch_all)]
	Unknown(u16),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[derive(FromPrimitive, IntoPrimitive)]
#[repr(u16)]
pub enum WindowsLanguage {
	EnUs = 0x409,
	#[num_enum(catch_all)]
	Unknown(u16),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PlatformEncoding {
	Unicode(UnicodeVersion),
	Macintosh(ScriptManagerCode),
	Windows(WindowsEncoding),
	Unknown(u16, u16),
}
impl PlatformEncoding {
	pub fn platform(&self) -> Platform {
		match self {
			Self::Unicode(_) => Platform::Unicode,
			Self::Macintosh(_) => Platform::Macintosh,
			Self::Windows(_) => Platform::Windows,
			Self::Unknown(x, _) => Platform::Unknown(*x),
		}
	}
}
impl From<(Platform, u16)> for PlatformEncoding {
	fn from(value: (Platform, u16)) -> Self {
		match value.0 {
			Platform::Unicode    => Self::Unicode(value.1.into()),
			Platform::Macintosh  => Self::Macintosh(value.1.into()),
			Platform::Windows    => Self::Windows(value.1.into()),
			Platform::Unknown(x) => Self::Unknown(x, value.1),
		}
	}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PlatformLanguage {
	Unicode(UnicodeLanguage),
	Macintosh(MacintoshLanguage),
	Windows(WindowsLanguage),
	Unknown(u16, u16),
}
impl PlatformLanguage {
	pub fn platform(&self) -> Platform {
		match self {
			Self::Unicode(_) => Platform::Unicode,
			Self::Macintosh(_) => Platform::Macintosh,
			Self::Windows(_) => Platform::Windows,
			Self::Unknown(x, _) => Platform::Unknown(*x),
		}
	}
}
impl From<(Platform, u16)> for PlatformLanguage {
	fn from(value: (Platform, u16)) -> Self {
		match value.0 {
			Platform::Unicode    => Self::Unicode(value.1.into()),
			Platform::Macintosh  => Self::Macintosh(value.1.into()),
			Platform::Windows    => Self::Windows(value.1.into()),
			Platform::Unknown(x) => Self::Unknown(x, value.1),
		}
	}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PlatformEncodingAndLanguage {
	Unicode(UnicodeVersion, UnicodeLanguage),
	Macintosh(ScriptManagerCode, MacintoshLanguage),
	Windows(WindowsEncoding, WindowsLanguage),
	Unknown(u16, u16, u16),
}
impl PlatformEncodingAndLanguage {
	pub fn platform(&self) -> Platform {
		match self {
			Self::Unicode(_, _) => Platform::Unicode,
			Self::Macintosh(_, _) => Platform::Macintosh,
			Self::Windows(_, _) => Platform::Windows,
			Self::Unknown(x, _, _) => Platform::Unknown(*x),
		}
	}
	pub fn encoding(&self) -> PlatformEncoding {
		match self {
			Self::Unicode(x, _) => PlatformEncoding::Unicode(*x),
			Self::Macintosh(x, _) => PlatformEncoding::Macintosh(*x),
			Self::Windows(x, _) => PlatformEncoding::Windows(*x),
			Self::Unknown(x, y, _) => PlatformEncoding::Unknown(*x, *y),
		}
	}
	pub fn language(&self) -> PlatformLanguage {
		match self {
			Self::Unicode(_, x) => PlatformLanguage::Unicode(*x),
			Self::Macintosh(_, x) => PlatformLanguage::Macintosh(*x),
			Self::Windows(_, x) => PlatformLanguage::Windows(*x),
			Self::Unknown(x, _, y) => PlatformLanguage::Unknown(*x, *y),
		}
	}
}
impl From<(Platform, u16, u16)> for PlatformEncodingAndLanguage {
	fn from(value: (Platform, u16, u16)) -> Self {
		match value.0 {
			Platform::Unicode    => Self::Unicode(value.1.into(), value.2.into()),
			Platform::Macintosh  => Self::Macintosh(value.1.into(), value.2.into()),
			Platform::Windows    => Self::Windows(value.1.into(), value.2.into()),
			Platform::Unknown(x) => Self::Unknown(x, value.1, value.2),
		}
	}
}
impl From<(u16, u16, u16)> for PlatformEncodingAndLanguage {
	fn from(value: (u16, u16, u16)) -> Self {
		(Platform::from(value.0), value.1, value.2).into()
	}
}
impl From<(PlatformEncoding, u16)> for PlatformEncodingAndLanguage {
	fn from(value: (PlatformEncoding, u16)) -> Self {
		match value.0 {
			PlatformEncoding::Unicode(x)    => Self::Unicode(x, value.1.into()),
			PlatformEncoding::Macintosh(x)  => Self::Macintosh(x, value.1.into()),
			PlatformEncoding::Windows(x)    => Self::Windows(x, value.1.into()),
			PlatformEncoding::Unknown(x, y) => Self::Unknown(x, y, value.1),
		}
	}
}
impl PlatformEncodingAndLanguage {
	pub fn character_encoding(&self) -> Option<StdEncoding> {
		match self {
			Self::Unicode(_, _) => Some(StdEncoding::Utf16BE),
			Self::Macintosh(ScriptManagerCode::Roman, _) => Some(StdEncoding::MacRoman),
			Self::Windows(WindowsEncoding::UnicodeBmp, _) => Some(StdEncoding::Utf16BE),
			Self::Windows(WindowsEncoding::UnicodeFullRepertoire, _) => Some(StdEncoding::Utf16BE),
	
			_ => None,
		}
	}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[derive(FromPrimitive, IntoPrimitive)]
#[repr(u16)]
pub enum CoverageTableFormat {
	Flat = 1,
	Ranges = 2,
	#[num_enum(catch_all)]
	Unknown(u16),
}
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct FlatCoverageTable<'a>(&'a [u8]);
impl<'a> RandomAccess<'a> for FlatCoverageTable<'a> {
	fn bytes(&self) -> &'a [u8] { self.0 }
}
impl<'a> FlatCoverageTable<'a> {
	pub fn format(&self) -> CoverageTableFormat { self.uint16(0).into() }
	pub fn glyphs(&self) -> U16Array<'a> { self.uint16_array(4, self.uint16(2) as usize) }
	pub fn contains(&self, glyph: u16) -> bool { self.map(glyph).is_some() }
	pub fn map(&self, glyph: u16) -> Option<u16> {
		for (i, g) in self.glyphs().iter().enumerate() {
			if g == glyph {
				return Some(i as u16);
			}
		}
		None
	}
}
impl Debug for FlatCoverageTable<'_> {
	fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
		f.debug_struct("FlatCoverageTable")
			.field("glyphs", &self.glyphs())
			.finish()
	}
}
#[derive(Clone, Copy, Zeroable, Pod)]
#[repr(transparent)]
pub struct RangeRecord([u8; 6]);
impl<'a> RandomAccess<'a> for &'a RangeRecord {
	fn bytes(&self) -> &'a [u8] { &self.0 }
}
impl RangeRecord {
	pub fn start_glyph(&self) -> u16 { self.uint16(0) }
	pub fn end_glyph(&self) -> u16 { self.uint16(2) }
	pub fn start_coverage(&self) -> u16 { self.uint16(4) }
	pub fn glyphs(&self) -> RangeInclusive<u16> { self.start_glyph()..=self.end_glyph() }
	pub fn coverage(&self) -> RangeInclusive<u16> {
		let glyphs = self.glyphs();
		let start = self.start_coverage();
		let stop = start + glyphs.end() - glyphs.start();
		start..=stop
	}
	pub fn contains(&self, glyph: u16) -> bool {
		let glyphs = self.glyphs();
		glyph >= *glyphs.start() && glyph <= *glyphs.end()
	}
	pub fn map(&self, glyph: u16) -> Option<u16> {
		let glyphs = self.glyphs();
		if glyph >= *glyphs.start() && glyph <= *glyphs.end() {
			Some(self.start_coverage() + glyph - *glyphs.start())
		} else { None }
	}
}
impl Debug for RangeRecord {
	fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
		f.debug_struct("RangeRecord")
			.field("glyphs", &self.glyphs())
			.field("coverage", &self.coverage())
			.finish()
	}
}
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct RangesCoverageTable<'a>(&'a [u8]);
impl<'a> RandomAccess<'a> for RangesCoverageTable<'a> {
	fn bytes(&self) -> &'a [u8] { self.0 }
}
impl<'a> RangesCoverageTable<'a> {
	pub fn format(&self) -> CoverageTableFormat { self.uint16(0).into() }
	pub fn ranges(&self) -> &'a [RangeRecord] { self.array(4, self.uint16(2) as usize) }
	pub fn contains(&self, glyph: u16) -> bool { self.map(glyph).is_some() }
	pub fn map(&self, glyph: u16) -> Option<u16> {
		for range in self.ranges() {
			if let Some(i) = range.map(glyph) {
				return Some(i);
			}
		}
		None
	}
}
impl Debug for RangesCoverageTable<'_> {
	fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
		f.debug_struct("RangesCoverageTable")
			.field("ranges", &self.ranges())
			.finish()
	}
}
#[derive(Clone, Copy)]
pub enum CoverageTable<'a> {
	Flat(FlatCoverageTable<'a>),
	Ranges(RangesCoverageTable<'a>),
}
impl<'a> RandomAccess<'a> for CoverageTable<'a> {
	fn bytes(&self) -> &'a [u8] {
		match self {
			Self::Flat(x) => x.bytes(),
			Self::Ranges(x) => x.bytes(),
		}
	}
}
impl<'a> CoverageTable<'a> {
	pub fn format(&self) -> CoverageTableFormat { self.uint16(0).into() }
	pub fn contains(&self, glyph: u16) -> bool {
		match self {
			Self::Flat(x) => x.contains(glyph),
			Self::Ranges(x) => x.contains(glyph),
		}
	}
	pub fn map(&self, glyph: u16) -> Option<u16> {
		match self {
			Self::Flat(x) => x.map(glyph),
			Self::Ranges(x) => x.map(glyph),
		}
	}
}
impl<'a> Debug for CoverageTable<'a> {
	fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
		match self {
			Self::Flat(x) => x.fmt(f),
			Self::Ranges(x) => x.fmt(f),
		}
	}
}
impl<'a> TryFrom<&'a [u8]> for CoverageTable<'a> {
	type Error = ReadError;
	fn try_from(data: &'a [u8]) -> Result<Self, Self::Error> {
		if data.len() < 4 { return Err(ReadError::UnexpectedEof); }
		let format: CoverageTableFormat = data.uint16(0).into();
		match format {
			CoverageTableFormat::Flat => {
				let length = 4 + data.uint16(2) as usize * 2;
				if data.len() < length { return Err(ReadError::UnexpectedEof); }
				let data = &data[0..length];
				Ok(Self::Flat(FlatCoverageTable(data)))
			},
			CoverageTableFormat::Ranges => {
				let length = 4 + data.uint16(2) as usize * 6;
				if data.len() < length { return Err(ReadError::UnexpectedEof); }
				let data = &data[0..length];
				Ok(Self::Ranges(RangesCoverageTable(data)))
			},
			CoverageTableFormat::Unknown(x) => Err(ReadError::UnknownCoverageTableFormat(x)),
		}
	}
}
#[derive(Clone, Copy)]
pub struct LanguageSystem<'a>(Option<&'a Tag>, &'a [u8]);
impl<'a> RandomAccess<'a> for LanguageSystem<'a> {
	fn bytes(&self) -> &'a [u8] { self.1 }
}
impl<'a> LanguageSystem<'a> {
	pub fn tag(&self) -> Option<&'a Tag> {
		self.0
	}
	pub fn required_feature(&self) -> Option<u16> {
		match self.uint16(2) {
			x @ 0..=0xFFFE => Some(x),
			0xFFFF => None,
		}
	}
	pub fn optional_features(&self) -> U16Array<'a> {
		self.uint16_array(6, self.uint16(4) as usize)
	}
}
impl Debug for LanguageSystem<'_> {
	fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
		f.debug_struct("LanguageSystem")
			.field("tag", &self.tag())
			.field("required_feature", &self.required_feature())
			.field("optional_features", &self.optional_features())
			.finish()
	}
}
impl<'a> LanguageSystem<'a> {
	pub fn try_from(tag: Option<&'a Tag>, data: &'a [u8]) -> Result<Self, ReadError> {
		if data.len() < 6 { return Err(ReadError::UnexpectedEof); }
		let count = data.uint16(4);
		let size = count as usize * 2 + 6;
		if data.len() < size { return Err(ReadError::UnexpectedEof); }
		Ok(Self(tag, &data[0..size]))
	}
}
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct LanguageSystemList<'a>(&'a [u8]);
impl<'a> RandomAccess<'a> for LanguageSystemList<'a> {
	fn bytes(&self) -> &'a [u8] { self.0 }
}
impl<'a> LanguageSystemList<'a> {
	pub fn len(&self) -> u16 { self.uint16(0) }
	pub fn is_empty(&self) -> bool { self.len() == 0 }
	pub fn get(&self, index: u16) -> Result<LanguageSystem<'a>, ReadError> {
		let offset = index as usize * 6 + 2;
		let tag = self.item(offset);
		let offset = self.uint16(offset + 4) as usize;
		if offset >= self.0.len() {
			return Err(ReadError::UnexpectedEof);
		}
		let data = &self.0[offset..];
		LanguageSystem::try_from(Some(tag), data)
	}
	pub fn find(&self, find_tag: &[u8; 4]) -> Result<Option<LanguageSystem<'a>>, ReadError> {
		let find_tag = Tag::new(find_tag);
		let count = self.uint16(0);
		for index in 0..count {
			let offset = index as usize * 6 + 2;
			let tag = self.item(offset);
			if *tag == find_tag {
				let offset = self.uint16(offset + 4) as usize;
				if offset >= self.0.len() {
					return Err(ReadError::UnexpectedEof);
				}
				let data = &self.0[offset..];
				return Ok(Some(LanguageSystem::try_from(Some(tag), data)?));
			}
		}
		Ok(None)
	}
	pub fn iter(&self) -> impl ExactSizeIterator<Item = Result<LanguageSystem<'a>, ReadError>> + '_ {
		(0..self.len()).map(|x| self.get(x))
	}
}
impl Debug for LanguageSystemList<'_> {
	fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
		f.debug_list()
			.entries(self.iter())
			.finish()
	}
}
impl<'a> TryFrom<&'a [u8]> for LanguageSystemList<'a> {
	type Error = ReadError;
	fn try_from(data: &'a [u8]) -> Result<Self, Self::Error> {
		if data.len() < 2 { return Err(ReadError::UnexpectedEof); }
		let count = data.uint16(0);
		let min_size = count as usize * 6 + 2;
		if data.len() < min_size { return Err(ReadError::UnexpectedEof); }
		Ok(Self(data))
	}
}
#[derive(Clone, Copy)]
pub struct ScriptTable<'a>(&'a Tag, &'a [u8]);
impl<'a> RandomAccess<'a> for ScriptTable<'a> {
	fn bytes(&self) -> &'a [u8] { self.1 }
}
impl<'a> ScriptTable<'a> {
	pub fn tag(&self) -> &'a Tag { self.0 }
	pub fn default_system(&self) -> Result<LanguageSystem<'a>, ReadError> {
		let offset = self.uint16(0) as usize;
		if offset >= self.1.len() {
			return Err(ReadError::UnexpectedEof);
		}
		let data = &self.1[offset..];
		LanguageSystem::try_from(None, data)
	}
	pub fn additional_systems(&self) -> LanguageSystemList<'a> {
		LanguageSystemList(&self.1[2..])
	}
}
impl Debug for ScriptTable<'_> {
	fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
		f.debug_struct("ScriptTable")
			.field("tag", &self.tag())
			.field("default_system", &self.default_system())
			.field("additional_systems", &self.additional_systems())
			.finish()
	}
}
impl<'a> ScriptTable<'a> {
	pub fn try_from(tag: &'a Tag, data: &'a [u8]) -> Result<Self, ReadError> {
		if data.len() < 4 { return Err(ReadError::UnexpectedEof); }
		let count = data.uint16(2);
		let min_size = count as usize * 6 + 4;
		if data.len() < min_size { return Err(ReadError::UnexpectedEof); }
		Ok(Self(tag, data))
	}
}
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct ScriptList<'a>(&'a [u8]);
impl<'a> RandomAccess<'a> for ScriptList<'a> {
	fn bytes(&self) -> &'a [u8] { self.0 }
}
impl<'a> ScriptList<'a> {
	pub fn len(&self) -> u16 { self.uint16(0) }
	pub fn is_empty(&self) -> bool { self.len() == 0 }
	pub fn get(&self, index: u16) -> Result<ScriptTable<'a>, ReadError> {
		let offset = index as usize * 6 + 2;
		let tag = self.item(offset);
		let offset = self.uint16(offset + 4) as usize;
		if offset >= self.0.len() {
			return Err(ReadError::UnexpectedEof);
		}
		let data = &self.0[offset..];
		ScriptTable::try_from(tag, data)
	}
	pub fn find(&self, find_tag: &[u8; 4]) -> Result<Option<ScriptTable<'a>>, ReadError> {
		let find_tag = Tag::new(find_tag);
		let count = self.uint16(0);
		for index in 0..count {
			let offset = index as usize * 6 + 2;
			let tag = self.item(offset);
			if *tag == find_tag {
				let offset = self.uint16(offset + 4) as usize;
				if offset >= self.0.len() {
					return Err(ReadError::UnexpectedEof);
				}
				let data = &self.0[offset..];
				return Ok(Some(ScriptTable::try_from(tag, data)?));
			}
		}
		Ok(None)
	}
	pub fn iter(&self) -> impl ExactSizeIterator<Item = Result<ScriptTable<'a>, ReadError>> + '_ {
		(0..self.len()).map(|x| self.get(x))
	}
}
impl Debug for ScriptList<'_> {
	fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
		f.debug_list()
			.entries(self.iter())
			.finish()
	}
}
impl<'a> TryFrom<&'a [u8]> for ScriptList<'a> {
	type Error = ReadError;
	fn try_from(data: &'a [u8]) -> Result<Self, Self::Error> {
		if data.len() < 2 { return Err(ReadError::UnexpectedEof); }
		let count = data.uint16(0);
		let min_size = count as usize * 6 + 2;
		if data.len() < min_size { return Err(ReadError::UnexpectedEof); }
		Ok(Self(data))
	}
}
#[derive(Clone, Copy)]
pub struct Feature<'a>(&'a Tag, &'a [u8]);
impl<'a> RandomAccess<'a> for Feature<'a> {
	fn bytes(&self) -> &'a [u8] { self.1 }
}
impl<'a> Feature<'a> {
	pub fn tag(&self) -> &'a Tag {
		self.0
	}
	pub fn params_offset(&self) -> Option<u16> {
		match self.uint16(0) {
			0 => None,
			x @ 1..=0xFFFF => Some(x),
		}
	}
	pub fn lookup_tables(&self) -> U16Array<'a> {
		self.uint16_array(4, self.uint16(2) as usize)
	}
}
impl Debug for Feature<'_> {
	fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
		f.debug_struct("Feature")
			.field("tag", &self.tag())
			.field("params_offset", &self.params_offset())
			.field("lookup_tables", &self.lookup_tables())
			.finish()
	}
}
impl<'a> Feature<'a> {
	pub fn try_from(tag: &'a Tag, data: &'a [u8]) -> Result<Self, ReadError> {
		if data.len() < 6 { return Err(ReadError::UnexpectedEof); }
		let count = data.uint16(2);
		let min_size = count as usize * 2 + 4;
		if data.len() < min_size { return Err(ReadError::UnexpectedEof); }
		Ok(Self(tag, data))
	}
}
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct FeatureList<'a>(&'a [u8]);
impl<'a> RandomAccess<'a> for FeatureList<'a> {
	fn bytes(&self) -> &'a [u8] { self.0 }
}
impl<'a> FeatureList<'a> {
	pub fn len(&self) -> u16 { self.uint16(0) }
	pub fn is_empty(&self) -> bool { self.len() == 0 }
	pub fn get(&self, index: u16) -> Result<Feature<'a>, ReadError> {
		let offset = index as usize * 6 + 2;
		let tag = self.item(offset);
		let offset = self.uint16(offset + 4) as usize;
		if offset >= self.0.len() {
			return Err(ReadError::UnexpectedEof);
		}
		let data = &self.0[offset..];
		Feature::try_from(tag, data)
	}
	pub fn find(&self, find_tag: &[u8; 4]) -> Result<Option<Feature<'a>>, ReadError> {
		let find_tag = Tag::new(find_tag);
		let count = self.uint16(0);
		for index in 0..count {
			let offset = index as usize * 6 + 2;
			let tag = self.item(offset);
			if *tag == find_tag {
				let offset = self.uint16(offset + 4) as usize;
				if offset >= self.0.len() {
					return Err(ReadError::UnexpectedEof);
				}
				let data = &self.0[offset..];
				return Ok(Some(Feature::try_from(tag, data)?));
			}
		}
		Ok(None)
	}
	pub fn iter(&self) -> impl ExactSizeIterator<Item = Result<Feature<'a>, ReadError>> + '_ {
		(0..self.len()).map(|x| self.get(x))
	}
}
impl Debug for FeatureList<'_> {
	fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
		f.debug_list()
			.entries(self.iter())
			.finish()
	}
}
impl<'a> TryFrom<&'a [u8]> for FeatureList<'a> {
	type Error = ReadError;
	fn try_from(data: &'a [u8]) -> Result<Self, Self::Error> {
		if data.len() < 2 { return Err(ReadError::UnexpectedEof); }
		let count = data.uint16(0);
		let min_size = count as usize * 6 + 2;
		if data.len() < min_size { return Err(ReadError::UnexpectedEof); }
		Ok(Self(data))
	}
}
#[derive(EnumSetType, Debug)]
#[repr(u8)]
pub enum LookupFlag {
	RightToLeft = 0,
	IgnoreBaseGlyphs = 1,
	IgnoreLigatures = 2,
	IgnoreMarks = 3,
	UseMarkFilteringSet = 4,
}
pub struct LookupTable<'a, T, S> {
	data: &'a [u8],
	phantom: PhantomData<(T, S)>,
}
impl<'a, T, S> Clone for LookupTable<'a, T, S> {
	fn clone(&self) -> Self { *self }
}
impl<'a, T, S> Copy for LookupTable<'a, T, S> {}
impl<'a, T, S> RandomAccess<'a> for LookupTable<'a, T, S> {
	fn bytes(&self) -> &'a [u8] { self.data }
}
impl<'a, T, S> LookupTable<'a, T, S> where T: FromPrimitive<Primitive = u16> {
	pub fn r#type(&self) -> T { T::from_primitive(self.uint16(0)) }
}
impl<'a, T, S> LookupTable<'a, T, S> {
	pub fn mark_attachment_class(&self) -> u8 { self.uint8(2) }
	pub fn flags(&self) -> EnumSet<LookupFlag> { EnumSet::from_u8(self.uint8(3)) }
}
impl<'a, T, S> LookupTable<'a, T, S> where S: TryFrom<&'a [u8]> {
	pub fn subtable_count(&self) -> u16 { self.uint16(4) }
	pub fn subtable(&self, index: u16) -> Result<S, S::Error> {
		let offset = self.uint16(6 + index as usize) as usize;
		self.data[offset..].try_into()
	}
	pub fn subtables(&self) -> impl ExactSizeIterator<Item = Result<S, S::Error>> + '_ {
		(0..self.subtable_count()).map(|x| self.subtable(x))
	}
}
impl<'a, T, S> LookupTable<'a, T, S> {
	pub fn mark_filtering_set(&self) -> Option<u16> {
		if self.flags().contains(LookupFlag::UseMarkFilteringSet) {
			Some(self.uint16(6 + self.uint16(4) as usize * 2))
		} else {
			None
		}
	}
}
impl<'a, T, S> Debug for LookupTable<'a, T, S> where T: Debug + FromPrimitive<Primitive = u16>, S: Debug + TryFrom<&'a [u8]>, S::Error: Debug {
	fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
		struct Subtables<'a, T, S>(LookupTable<'a, T, S>);
		
		impl<'a, T, S> Debug for Subtables<'a, T, S> where S: Debug + TryFrom<&'a [u8]>, S::Error: Debug {
			fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
				f.debug_list()
					.entries(self.0.subtables())
					.finish()
			}
		}
		f.debug_struct("LookupTable")
			.field("type", &self.r#type())
			.field("flags", &self.flags())
			.field("mark_attachment_class", &self.mark_attachment_class())
			.field("mark_filtering_set", &self.mark_filtering_set())
			.field("subtables", &Subtables(*self))
			.finish()
	}
}
impl<'a, E, T> TryFrom<&'a [u8]> for LookupTable<'a, E, T> {
	type Error = ReadError;
	fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
		Ok(Self { data: value, phantom: PhantomData })
	}
}