use super::*;

/// The main way to represent a reference in ADN.
pub struct Point<'a, Ctx: Context<'a>, A: MentionableBase<'a, Ctx>> {
    /// Hash of the referred content.
    /// Derived both from the serialised value ([`Serializable::serialize`])
    /// and its topology ([`MentionableTop::topology`]).
    pub point: Hash,
    /// [Origin] used in [`Point::resolve`].
    pub origin: Rc<dyn Origin<'a, Ctx, Mtbl = A>>,
}

impl<'a, Ctx: Context<'a>, A: MentionableBase<'a, Ctx>> PartialEq for Point<'a, Ctx, A> {
    /// Note: this doesn't check for [Factory] equality.
    fn eq(&self, other: &Self) -> bool {
        self.point == other.point
    }
}

impl<'a, Ctx: Context<'a>, A: MentionableBase<'a, Ctx>> Clone for Point<'a, Ctx, A> {
    fn clone(&self) -> Self {
        Self {
            point: self.point,
            origin: self.origin.clone(),
        }
    }
}

impl<'a, Ctx: Context<'a>, A: MentionableBase<'a, Ctx>> Point<'a, Ctx, A>
where
    A::Fctr: FactoryParse<'a, Ctx>,
{
    /// See [`Origin::resolve`].
    pub fn resolve(&self) -> Resolution<'a, Ctx, A> {
        self.origin.clone().resolve()
    }

    /// Resolve the object, then map the [ResolutionResult].
    pub fn resolve_map<B: 'a>(
        &self,
        f: impl 'a + FnOnce(ResolutionResult<'a, Ctx, A>) -> B,
    ) -> Wrapped<'a, Ctx, B> {
        Ctx::fmap(self.resolve(), f)
    }
}