use crate::ast::Name;
use crate::Node;
use crate::NodeLocation;
use std::hash;
use std::ops::Deref;
use std::ops::DerefMut;
use triomphe::Arc;
#[derive(Debug, Clone)]
pub struct Component<T> {
    pub origin: ComponentOrigin,
    pub node: Node<T>,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum ComponentOrigin {
    Definition,
    Extension(ExtensionId),
}
#[derive(Debug, Clone, Eq)]
pub struct ExtensionId {
    arc: Arc<Option<NodeLocation>>,
}
impl ExtensionId {
    pub fn new<T>(extension: &Node<T>) -> Self {
        Self {
            arc: Arc::new(extension.location()),
        }
    }
    pub fn location(&self) -> Option<NodeLocation> {
        *self.arc
    }
    pub fn same_location<T>(&self, node: T) -> Node<T> {
        Node::new_opt_location(node, self.location())
    }
}
impl PartialEq for ExtensionId {
    fn eq(&self, other: &Self) -> bool {
        Arc::ptr_eq(&self.arc, &other.arc)
    }
}
impl hash::Hash for ExtensionId {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        Arc::as_ptr(&self.arc).hash(state);
    }
}
impl ComponentOrigin {
    pub fn extension_id(&self) -> Option<&ExtensionId> {
        match self {
            ComponentOrigin::Definition => None,
            ComponentOrigin::Extension(id) => Some(id),
        }
    }
}
impl<T> Component<T> {
    pub fn new(node: T) -> Self {
        Self {
            origin: ComponentOrigin::Definition,
            node: Node::new(node),
        }
    }
}
impl<T: hash::Hash> hash::Hash for Component<T> {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.node.hash(state); }
}
impl<T: Eq> Eq for Component<T> {}
impl<T: PartialEq> PartialEq for Component<T> {
    fn eq(&self, other: &Self) -> bool {
        self.node == other.node }
}
impl<T> Deref for Component<T> {
    type Target = Node<T>;
    fn deref(&self) -> &Self::Target {
        &self.node
    }
}
impl<T> DerefMut for Component<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.node
    }
}
impl<T> AsRef<T> for Component<T> {
    fn as_ref(&self) -> &T {
        &self.node
    }
}
impl<T> From<T> for Component<T> {
    fn from(node: T) -> Self {
        Component::new(node)
    }
}
#[derive(Debug, Clone)]
pub struct ComponentName {
    pub origin: ComponentOrigin,
    pub name: Name,
}
impl From<&Name> for ComponentName {
    fn from(value: &Name) -> Self {
        value.to_component(ComponentOrigin::Definition)
    }
}
impl From<Name> for ComponentName {
    fn from(value: Name) -> Self {
        value.to_component(ComponentOrigin::Definition)
    }
}
impl hash::Hash for ComponentName {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.name.hash(state); }
}
impl Eq for ComponentName {}
impl PartialEq for ComponentName {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name }
}
impl PartialEq<str> for ComponentName {
    fn eq(&self, other: &str) -> bool {
        self.as_str() == other
    }
}
impl Deref for ComponentName {
    type Target = Name;
    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.name
    }
}
impl std::borrow::Borrow<Name> for ComponentName {
    fn borrow(&self) -> &Name {
        self
    }
}
impl std::borrow::Borrow<str> for ComponentName {
    fn borrow(&self) -> &str {
        self
    }
}
impl AsRef<str> for ComponentName {
    fn as_ref(&self) -> &str {
        self
    }
}