mod builder;
pub mod syntax_error;
mod syntax_text;

use self::syntax_text::SyntaxText;
use crate::{SmolStr, SyntaxKind, TextRange};
use rowan::Types;
use std::{
    fmt,
    hash::{Hash, Hasher},
};

pub(crate) use self::builder::GreenBuilder;
pub use self::syntax_error::{SyntaxError, SyntaxErrorKind, Location};
pub use rowan::{TreeRoot, WalkEvent};

#[derive(Debug, Clone, Copy)]
pub enum RaTypes {}
impl Types for RaTypes {
    type Kind = SyntaxKind;
    type RootData = Vec<SyntaxError>;
}

pub type OwnedRoot = ::rowan::OwnedRoot<RaTypes>;
pub type RefRoot<'a> = ::rowan::RefRoot<'a, RaTypes>;

pub type GreenNode = ::rowan::GreenNode<RaTypes>;

#[derive(Clone, Copy)]
pub struct SyntaxNode<R: TreeRoot<RaTypes> = OwnedRoot>(pub(crate) ::rowan::SyntaxNode<RaTypes, R>);
pub type SyntaxNodeRef<'a> = SyntaxNode<RefRoot<'a>>;

impl<R1, R2> PartialEq<SyntaxNode<R1>> for SyntaxNode<R2>
where
    R1: TreeRoot<RaTypes>,
    R2: TreeRoot<RaTypes>,
{
    fn eq(&self, other: &SyntaxNode<R1>) -> bool {
        self.0 == other.0
    }
}

impl<R: TreeRoot<RaTypes>> Eq for SyntaxNode<R> {}
impl<R: TreeRoot<RaTypes>> Hash for SyntaxNode<R> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.hash(state)
    }
}

impl SyntaxNode {
    pub(crate) fn new(green: GreenNode, errors: Vec<SyntaxError>) -> SyntaxNode {
        SyntaxNode(::rowan::SyntaxNode::new(green, errors))
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Direction {
    Next,
    Prev,
}

impl<'a> SyntaxNodeRef<'a> {
    pub fn leaf_text(self) -> Option<&'a SmolStr> {
        self.0.leaf_text()
    }
    pub fn ancestors(self) -> impl Iterator<Item = SyntaxNodeRef<'a>> {
        crate::algo::generate(Some(self), |&node| node.parent())
    }
    pub fn descendants(self) -> impl Iterator<Item = SyntaxNodeRef<'a>> {
        self.preorder().filter_map(|event| match event {
            WalkEvent::Enter(node) => Some(node),
            WalkEvent::Leave(_) => None,
        })
    }
    pub fn siblings(self, direction: Direction) -> impl Iterator<Item = SyntaxNodeRef<'a>> {
        crate::algo::generate(Some(self), move |&node| match direction {
            Direction::Next => node.next_sibling(),
            Direction::Prev => node.prev_sibling(),
        })
    }
    pub fn preorder(self) -> impl Iterator<Item = WalkEvent<SyntaxNodeRef<'a>>> {
        self.0.preorder().map(|event| match event {
            WalkEvent::Enter(n) => WalkEvent::Enter(SyntaxNode(n)),
            WalkEvent::Leave(n) => WalkEvent::Leave(SyntaxNode(n)),
        })
    }
}

impl<R: TreeRoot<RaTypes>> SyntaxNode<R> {
    pub(crate) fn root_data(&self) -> &Vec<SyntaxError> {
        self.0.root_data()
    }
    pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode {
        self.0.replace_with(replacement)
    }
    pub fn borrowed<'a>(&'a self) -> SyntaxNode<RefRoot<'a>> {
        SyntaxNode(self.0.borrowed())
    }
    pub fn owned(&self) -> SyntaxNode<OwnedRoot> {
        SyntaxNode(self.0.owned())
    }
    pub fn kind(&self) -> SyntaxKind {
        self.0.kind()
    }
    pub fn range(&self) -> TextRange {
        self.0.range()
    }
    pub fn text(&self) -> SyntaxText {
        SyntaxText::new(self.borrowed())
    }
    pub fn is_leaf(&self) -> bool {
        self.0.is_leaf()
    }
    pub fn parent(&self) -> Option<SyntaxNode<R>> {
        self.0.parent().map(SyntaxNode)
    }
    pub fn first_child(&self) -> Option<SyntaxNode<R>> {
        self.0.first_child().map(SyntaxNode)
    }
    pub fn last_child(&self) -> Option<SyntaxNode<R>> {
        self.0.last_child().map(SyntaxNode)
    }
    pub fn next_sibling(&self) -> Option<SyntaxNode<R>> {
        self.0.next_sibling().map(SyntaxNode)
    }
    pub fn prev_sibling(&self) -> Option<SyntaxNode<R>> {
        self.0.prev_sibling().map(SyntaxNode)
    }
    pub fn children(&self) -> SyntaxNodeChildren<R> {
        SyntaxNodeChildren(self.0.children())
    }
}

impl<R: TreeRoot<RaTypes>> fmt::Debug for SyntaxNode<R> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{:?}@{:?}", self.kind(), self.range())?;
        if has_short_text(self.kind()) {
            write!(fmt, " \"{}\"", self.text())?;
        }
        Ok(())
    }
}

#[derive(Debug)]
pub struct SyntaxNodeChildren<R: TreeRoot<RaTypes>>(::rowan::SyntaxNodeChildren<RaTypes, R>);

impl<R: TreeRoot<RaTypes>> Iterator for SyntaxNodeChildren<R> {
    type Item = SyntaxNode<R>;

    fn next(&mut self) -> Option<SyntaxNode<R>> {
        self.0.next().map(SyntaxNode)
    }
}

fn has_short_text(kind: SyntaxKind) -> bool {
    use crate::SyntaxKind::*;
    match kind {
        IDENT | LIFETIME | INT_NUMBER | FLOAT_NUMBER => true,
        _ => false,
    }
}