use static_regular_grammar::RegularGrammar;
mod segment;
pub use segment::*;
use crate::common::path::{NormalizedSegmentsImpl, PathBufImpl, PathImpl, SegmentsImpl};
use super::PathMut;
#[derive(RegularGrammar)]
#[grammar(
	file = "src/iri/grammar.abnf",
	entry_point = "ipath",
	name = "IRI path",
	cache = "automata/iri/path.aut.cbor"
)]
#[grammar(sized(PathBuf, derive(Debug, Display)))]
#[cfg_attr(feature = "serde", grammar(serde))]
#[cfg_attr(feature = "ignore-grammars", grammar(disable))]
pub struct Path(str);
impl PathImpl for Path {
	const EMPTY: &'static Self = Self::EMPTY;
	const EMPTY_ABSOLUTE: &'static Self = Self::EMPTY_ABSOLUTE;
	type Segment = Segment;
	type Owned = PathBuf;
	unsafe fn new_unchecked(bytes: &[u8]) -> &Self {
		Self::new_unchecked(std::str::from_utf8_unchecked(bytes))
	}
	#[inline(always)]
	fn as_bytes(&self) -> &[u8] {
		self.as_bytes()
	}
	fn to_path_buf(&self) -> Self::Owned {
		unsafe { PathBuf::new_unchecked(self.to_string()) }
	}
}
impl PathBufImpl for PathBuf {
	type Borrowed = Path;
	unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> {
		self.0.as_mut_vec()
	}
	fn as_bytes(&self) -> &[u8] {
		self.0.as_bytes()
	}
}
impl Path {
	pub const EMPTY_ABSOLUTE: &'static Self = unsafe { Self::new_unchecked("/") };
	#[inline]
	pub fn segment_count(&self) -> usize {
		self.segments().count()
	}
	#[inline]
	pub fn is_empty(&self) -> bool {
		PathImpl::is_empty(self)
	}
	#[inline]
	pub fn is_absolute(&self) -> bool {
		PathImpl::is_absolute(self)
	}
	#[inline]
	pub fn is_relative(&self) -> bool {
		PathImpl::is_relative(self)
	}
	pub fn first(&self) -> Option<&Segment> {
		PathImpl::first(self)
	}
	pub fn last(&self) -> Option<&Segment> {
		PathImpl::last(self)
	}
	#[inline]
	pub fn segments(&self) -> Segments {
		Segments(PathImpl::segments(self))
	}
	#[inline]
	pub fn normalized_segments(&self) -> NormalizedSegments {
		NormalizedSegments(PathImpl::normalized_segments(self))
	}
	#[inline]
	pub fn normalized(&self) -> PathBuf {
		PathImpl::normalized(self)
	}
	#[inline]
	pub fn file_name(&self) -> Option<&Segment> {
		PathImpl::file_name(self)
	}
	pub fn directory(&self) -> &Self {
		PathImpl::directory(self)
	}
	#[inline]
	pub fn parent(&self) -> Option<&Self> {
		PathImpl::parent(self)
	}
	#[inline]
	pub fn parent_or_empty(&self) -> &Self {
		PathImpl::parent_or_empty(self)
	}
	#[inline]
	pub fn suffix(&self, prefix: &Self) -> Option<PathBuf> {
		PathImpl::suffix(self, prefix)
	}
}
impl<'a> IntoIterator for &'a Path {
	type Item = &'a Segment;
	type IntoIter = Segments<'a>;
	#[inline]
	fn into_iter(self) -> Segments<'a> {
		self.segments()
	}
}
impl PartialEq for Path {
	#[inline]
	fn eq(&self, other: &Path) -> bool {
		if self.is_absolute() == other.is_absolute() {
			let self_segments = self.normalized_segments();
			let other_segments = other.normalized_segments();
			self_segments.len() == other_segments.len()
				&& self_segments.zip(other_segments).all(|(a, b)| a == b)
		} else {
			false
		}
	}
}
impl PartialEq<str> for Path {
	fn eq(&self, other: &str) -> bool {
		self.as_str() == other
	}
}
impl<'a> PartialEq<&'a str> for Path {
	fn eq(&self, other: &&'a str) -> bool {
		self.as_str() == *other
	}
}
impl PartialEq<String> for Path {
	fn eq(&self, other: &String) -> bool {
		self.as_str() == other.as_str()
	}
}
impl Eq for Path {}
impl PartialOrd for Path {
	#[inline]
	fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
		Some(self.cmp(other))
	}
}
impl Ord for Path {
	#[inline]
	fn cmp(&self, other: &Self) -> std::cmp::Ordering {
		use std::cmp::Ordering;
		if self.is_absolute() == other.is_absolute() {
			let mut self_segments = self.normalized_segments();
			let mut other_segments = other.normalized_segments();
			loop {
				match (self_segments.next(), other_segments.next()) {
					(None, None) => return Ordering::Equal,
					(Some(_), None) => return Ordering::Greater,
					(None, Some(_)) => return Ordering::Less,
					(Some(a), Some(b)) => match a.cmp(b) {
						Ordering::Greater => return Ordering::Greater,
						Ordering::Less => return Ordering::Less,
						Ordering::Equal => (),
					},
				}
			}
		} else if self.is_absolute() {
			Ordering::Greater
		} else {
			Ordering::Less
		}
	}
}
impl std::hash::Hash for Path {
	#[inline]
	fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
		self.is_absolute().hash(hasher);
		self.normalized_segments().for_each(move |s| s.hash(hasher))
	}
}
pub struct Segments<'a>(SegmentsImpl<'a, Path>);
impl<'a> Iterator for Segments<'a> {
	type Item = &'a Segment;
	fn next(&mut self) -> Option<Self::Item> {
		self.0.next()
	}
}
impl<'a> DoubleEndedIterator for Segments<'a> {
	fn next_back(&mut self) -> Option<Self::Item> {
		self.0.next_back()
	}
}
pub struct NormalizedSegments<'a>(NormalizedSegmentsImpl<'a, Path>);
impl<'a> Iterator for NormalizedSegments<'a> {
	type Item = &'a Segment;
	fn size_hint(&self) -> (usize, Option<usize>) {
		self.0.size_hint()
	}
	#[inline]
	fn next(&mut self) -> Option<&'a Segment> {
		self.0.next()
	}
}
impl<'a> DoubleEndedIterator for NormalizedSegments<'a> {
	#[inline]
	fn next_back(&mut self) -> Option<Self::Item> {
		self.0.next_back()
	}
}
impl<'a> ExactSizeIterator for NormalizedSegments<'a> {}
impl PathBuf {
	pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> {
		self.0.as_mut_vec()
	}
	pub fn as_path_mut(&mut self) -> PathMut {
		PathMut::from_path(self)
	}
	pub fn push(&mut self, segment: &Segment) {
		self.as_path_mut().push(segment)
	}
	pub fn pop(&mut self) {
		self.as_path_mut().pop()
	}
	pub fn clear(&mut self) {
		self.as_path_mut().clear()
	}
	#[inline]
	pub fn symbolic_push(&mut self, segment: &Segment) {
		self.as_path_mut().symbolic_push(segment)
	}
	#[inline]
	pub fn symbolic_append<'s, P: IntoIterator<Item = &'s Segment>>(&mut self, path: P) {
		self.as_path_mut().symbolic_append(path)
	}
	#[inline]
	pub fn normalize(&mut self) {
		self.as_path_mut().normalize()
	}
}
impl PartialEq<str> for PathBuf {
	fn eq(&self, other: &str) -> bool {
		self.as_str() == other
	}
}
impl<'a> PartialEq<&'a str> for PathBuf {
	fn eq(&self, other: &&'a str) -> bool {
		self.as_str() == *other
	}
}
impl PartialEq<String> for PathBuf {
	fn eq(&self, other: &String) -> bool {
		self.as_str() == other.as_str()
	}
}
#[cfg(test)]
mod tests {
	use super::*;
	#[test]
	fn empty() {
		let path = Path::EMPTY;
		assert!(path.is_empty());
		assert!(!path.is_absolute());
		assert!(path.segments().next().is_none());
	}
	#[test]
	fn empty_absolute() {
		let path = Path::EMPTY_ABSOLUTE;
		assert!(path.is_empty());
		assert!(path.is_absolute());
		assert!(path.segments().next().is_none());
	}
	#[test]
	fn non_empty() {
		let path = Path::new("a/b").unwrap();
		assert!(!path.is_empty());
		assert!(!path.is_absolute());
		let mut segments = path.segments();
		assert!(segments.next().unwrap().as_str() == "a");
		assert!(segments.next().unwrap().as_str() == "b");
		assert!(segments.next().is_none());
	}
	#[test]
	fn non_empty_absolute() {
		let path = Path::new("/foo/bar").unwrap();
		assert!(!path.is_empty());
		assert!(path.is_absolute());
		let mut segments = path.segments();
		assert!(segments.next().unwrap().as_str() == "foo");
		assert!(segments.next().unwrap().as_str() == "bar");
		assert!(segments.next().is_none());
	}
	#[test]
	fn next_segment() {
		let vectors = [
			("foo/bar", 0, Some(("foo", 4))),
			("foo/bar", 4, Some(("bar", 8))),
			("foo/bar", 8, None),
			("foo/bar/", 8, Some(("", 9))),
			("foo/bar/", 9, None),
			("//foo", 1, Some(("", 2))),
		];
		for (input, offset, expected) in vectors {
			unsafe {
				assert_eq!(
					Path::new(input).unwrap().next_segment_from(offset),
					expected.map(|(e, i)| (Segment::new(e).unwrap(), i))
				)
			}
		}
	}
	#[test]
	fn previous_segment() {
		let vectors = [
			("/foo/bar", 1, None),
			("foo/bar", 0, None),
			("foo/bar", 4, Some(("foo", 0))),
			("foo/bar", 8, Some(("bar", 4))),
			("foo/bar/", 8, Some(("bar", 4))),
			("foo/bar/", 9, Some(("", 8))),
			("//a/b", 4, Some(("a", 2))),
		];
		for (input, offset, expected) in vectors {
			unsafe {
				assert_eq!(
					Path::new(input).unwrap().previous_segment_from(offset),
					expected.map(|(e, i)| (Segment::new(e).unwrap(), i))
				)
			}
		}
	}
	#[test]
	fn first_segment() {
		let vectors = [
			("", None),
			("/", None),
			("//", Some("")),
			("/foo/bar", Some("foo")),
		];
		for (input, expected) in vectors {
			assert_eq!(
				Path::new(input).unwrap().first(),
				expected.map(|e| Segment::new(e).unwrap())
			)
		}
	}
	#[test]
	fn segments() {
		let vectors: [(&str, &[&str]); 8] = [
			("", &[]),
			("foo", &["foo"]),
			("/foo", &["foo"]),
			("foo/", &["foo", ""]),
			("/foo/", &["foo", ""]),
			("a/b/c/d", &["a", "b", "c", "d"]),
			("a/b//c/d", &["a", "b", "", "c", "d"]),
			("//a/b/foo//bar/", &["", "a", "b", "foo", "", "bar", ""]),
		];
		for (input, expected) in vectors {
			let path = Path::new(input).unwrap();
			let segments: Vec<_> = path.segments().collect();
			assert_eq!(segments.len(), expected.len());
			assert!(segments
				.into_iter()
				.zip(expected)
				.all(|(a, b)| a.as_str() == *b))
		}
	}
	#[test]
	fn segments_rev() {
		let vectors: [(&str, &[&str]); 8] = [
			("", &[]),
			("foo", &["foo"]),
			("/foo", &["foo"]),
			("foo/", &["foo", ""]),
			("/foo/", &["foo", ""]),
			("a/b/c/d", &["a", "b", "c", "d"]),
			("a/b//c/d", &["a", "b", "", "c", "d"]),
			("//a/b/foo//bar/", &["", "a", "b", "foo", "", "bar", ""]),
		];
		for (input, expected) in vectors {
			let path = Path::new(input).unwrap();
			let segments: Vec<_> = path.segments().rev().collect();
			assert_eq!(segments.len(), expected.len());
			assert!(segments
				.into_iter()
				.zip(expected.into_iter().rev())
				.all(|(a, b)| a.as_str() == *b))
		}
	}
	#[test]
	fn normalized() {
		let vectors = [
			("", ""),
			("a/b/c", "a/b/c"),
			("a/..", ""),
			("a/b/..", "a/"),
			("a/b/../", "a/"),
			("a/b/c/..", "a/b/"),
			("a/b/c/.", "a/b/c/"),
			("a/../..", "../"),
			("/a/../..", "/"), ];
		for (input, expected) in vectors {
			let path = Path::new(input).unwrap();
			let output = path.normalized();
			assert_eq!(output.as_str(), expected);
		}
	}
	#[test]
	fn eq() {
		let vectors = [
			("a/b/c", "a/b/c"),
			("a/b/c", "a/b/c/."),
			("a/b/c/", "a/b/c/./"),
			("a/b/c", "a/b/../b/c"),
			("a/b/c/..", "a/b"),
			("a/..", ""),
			("/a/..", "/"),
			("a/../..", ".."),
			("/a/../..", "/.."),
			("a/b/c/./", "a/b/c/"),
			("a/b/c/../", "a/b/"),
		];
		for (a, b) in vectors {
			let a = Path::new(a).unwrap();
			let b = Path::new(b).unwrap();
			assert_eq!(a, b)
		}
	}
	#[test]
	fn ne() {
		let vectors = [
			("a/b/c", "a/b/c/"),
			("a/b/c/", "a/b/c/."),
			("a/b/c/../", "a/b"),
		];
		for (a, b) in vectors {
			let a = Path::new(a).unwrap();
			let b = Path::new(b).unwrap();
			assert_ne!(a, b)
		}
	}
	#[test]
	fn file_name() {
		let vectors = [("//a/b/foo//bar/", None), ("//a/b/foo//bar", Some("bar"))];
		for (input, expected) in vectors {
			let input = Path::new(input).unwrap();
			assert_eq!(input.file_name().map(Segment::as_str), expected)
		}
	}
	#[test]
	fn parent() {
		let vectors = [
			("", None),
			("/", None),
			(".", None),
			("//a/b/foo//bar", Some("//a/b/foo/")),
			("//a/b/foo//", Some("//a/b/foo/")),
			("//a/b/foo/", Some("//a/b/foo")),
			("//a/b/foo", Some("//a/b")),
			("//a/b", Some("//a")),
			("//a", Some("/./")),
			("/./", Some("/.")),
			("/.", Some("/")),
		];
		for (input, expected) in vectors {
			let input = Path::new(input).unwrap();
			assert_eq!(input.parent().map(Path::as_str), expected)
		}
	}
	#[test]
	fn suffix() {
		let vectors = [
			("/foo/bar/baz", "/foo/bar", Some("baz")),
			("//foo", "/", Some(".//foo")),
			("/a/b/baz", "/foo/bar", None),
		];
		for (path, prefix, expected_suffix) in vectors {
			let path = Path::new(path).unwrap();
			let suffix = path.suffix(Path::new(prefix).unwrap());
			assert_eq!(suffix.as_deref().map(Path::as_str), expected_suffix)
		}
	}
}