use crate::prelude_internal::*;

pub struct ParseState<'a> {
	input: &'a str,
	at: usize,
}
impl<'a> ParseState<'a> {
	pub fn new(input: &'a str) -> Self {
		Self { input, at: 0 }
	}

	pub fn is_empty(&self) -> bool {
		self.head().is_empty()
	}

	pub fn head(&self) -> &str {
		&self.input[self.at..]
	}

	pub fn goto(&mut self, at: usize) {
		self.at = at;
	}

	pub fn skip(&mut self, amt: usize) {
		self.at += amt;
	}

	pub fn back(&mut self, amt: usize) {
		self.at -= amt;
	}

	pub fn parse_root(&mut self, out: &mut Vec<Command>) {
		while !self.is_empty() {
			let head = self.head();
			if let Some(bo) = head.find('{') {
				if bo != 0 {
					out.push(Command::Print(head[0..bo].to_string()));
				}

				self.goto(bo);
				self.parse_directive(out);
			} else {
				out.push(Command::Print(head.to_string()));
				return;
			}
		}
	}

	pub fn parse_directive(&mut self, out: &mut Vec<Command>) {
		assert!(self.head().starts_with('{'));

		let mut ok = Err(self.at);

		'inner: {
			self.skip(1);
			let head = self.head();
			if let Some(bo) = head.find('}') {
				let inner = &head[..bo];
				let bo = bo + 1;

				let mut inner = inner.split(' ').collect::<Vec<_>>();
				match inner.as_slice() {
					&[name] => {
						out.push(Command::LookupPrint(name.to_string()));
						ok = Ok(bo);
					},
					_ => (),
				}
			} else {
			}
		};

		match ok {
			Err(checkpoint) => self.goto(checkpoint),
			Ok(skip) => self.skip(skip),
		}
	}
}
