use crate::Node;
use crate::NodeLocation;
use crate::NodeStr;
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 ComponentStr {
    pub origin: ComponentOrigin,
    pub node: NodeStr,
}
impl ComponentStr {
    #[inline]
    pub fn new(value: &str) -> Self {
        Self {
            origin: ComponentOrigin::Definition,
            node: NodeStr::new(value),
        }
    }
}
impl hash::Hash for ComponentStr {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.node.hash(state); }
}
impl Eq for ComponentStr {}
impl PartialEq for ComponentStr {
    fn eq(&self, other: &Self) -> bool {
        self.node == other.node }
}
impl PartialEq<str> for ComponentStr {
    fn eq(&self, other: &str) -> bool {
        self.as_str() == other
    }
}
impl Deref for ComponentStr {
    type Target = NodeStr;
    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.node
    }
}
impl std::borrow::Borrow<NodeStr> for ComponentStr {
    fn borrow(&self) -> &NodeStr {
        self
    }
}
impl std::borrow::Borrow<str> for ComponentStr {
    fn borrow(&self) -> &str {
        self
    }
}
impl AsRef<str> for ComponentStr {
    fn as_ref(&self) -> &str {
        self
    }
}
impl From<&'_ str> for ComponentStr {
    fn from(value: &'_ str) -> Self {
        Self::new(value)
    }
}
impl From<&'_ String> for ComponentStr {
    fn from(value: &'_ String) -> Self {
        Self::new(value)
    }
}
impl From<String> for ComponentStr {
    fn from(value: String) -> Self {
        Self::new(&value)
    }
}