use std::fmt;
use iref::IriRefBuf;
use locspan::Meta;
pub use rdf_types::{BlankId, BlankIdBuf};
pub use xsd_types::lexical::{DecimalBuf, DoubleBuf, IntegerBuf};
pub type RdfLiteral<M> = rdf_types::meta::Literal<M, String, Iri<M>>;
#[derive(Clone, Debug)]
pub enum Iri<M> {
	IriRef(IriRefBuf),
	Compact(Meta<String, M>, Meta<String, M>),
}
#[derive(Clone, Debug)]
pub struct Document<M> {
	pub statements: Vec<Meta<Statement<M>, M>>,
}
impl<M> Default for Document<M> {
	fn default() -> Self {
		Self {
			statements: Vec::new(),
		}
	}
}
impl<M> Document<M> {
	pub fn new() -> Document<M> {
		Self::default()
	}
	pub fn insert(&mut self, statement: Meta<Statement<M>, M>) {
		self.statements.push(statement)
	}
}
#[derive(Clone, Debug)]
pub enum Statement<M> {
	Directive(Directive<M>),
	Triples(Triples<M>),
}
#[derive(Clone, Debug)]
pub struct Triples<M> {
	pub subject: Meta<Subject<M>, M>,
	pub predicate_objects_list: Meta<PredicateObjectsList<M>, M>,
}
pub type PredicateObjectsList<M> = Vec<Meta<PredicateObjects<M>, M>>;
#[derive(Clone, Debug)]
pub enum Directive<M> {
	Prefix(Meta<String, M>, Meta<IriRefBuf, M>),
	Base(Meta<IriRefBuf, M>),
	SparqlPrefix(Meta<String, M>, Meta<IriRefBuf, M>),
	SparqlBase(Meta<IriRefBuf, M>),
}
#[derive(Clone, Debug)]
pub enum Verb<M> {
	A,
	Predicate(Iri<M>),
}
#[derive(Clone, Debug)]
pub enum Subject<M> {
	Iri(Iri<M>),
	BlankNode(BlankNode<M>),
	Collection(Collection<M>),
}
#[derive(Clone, Debug)]
pub struct Collection<M>(pub Vec<Meta<Object<M>, M>>);
#[derive(Clone, Debug)]
pub enum BlankNode<M> {
	Label(BlankIdBuf),
	Anonymous(Meta<BlankNodePropertyList<M>, M>),
}
pub type BlankNodePropertyList<M> = PredicateObjectsList<M>;
#[derive(Clone, Debug)]
pub enum Object<M> {
	Iri(Iri<M>),
	BlankNode(BlankNode<M>),
	Collection(Collection<M>),
	Literal(Literal<M>),
}
#[derive(Clone, Debug)]
pub struct PredicateObjects<M> {
	pub verb: Meta<Verb<M>, M>,
	pub objects: Meta<Objects<M>, M>,
}
#[derive(Clone, Debug)]
pub struct Objects<M>(pub Vec<Meta<Object<M>, M>>);
#[derive(Clone, Debug)]
pub enum Literal<M> {
	Rdf(RdfLiteral<M>),
	Numeric(NumericLiteral),
	Boolean(bool),
}
#[derive(Clone, Debug)]
pub enum NumericLiteral {
	Integer(IntegerBuf),
	Decimal(DecimalBuf),
	Double(DoubleBuf),
}
impl fmt::Display for NumericLiteral {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match self {
			Self::Integer(i) => i.fmt(f),
			Self::Decimal(d) => d.fmt(f),
			Self::Double(d) => d.fmt(f),
		}
	}
}