{-# Language TemplateHaskell #-}
-- | Defines a type used to hold referencing information.
module Language.Drasil.Reference (
  -- * Type
  Reference(Reference),
  -- * Class
  HasReference(..),
  -- * Constructors
  ref, refS, namedRef, complexRef, namedComplexRef
) where

import Language.Drasil.Label.Type (LblType, HasRefAddress(..))
import Language.Drasil.ShortName (HasShortName(..), ShortName)
import Language.Drasil.Sentence (Sentence(Ref, EmptyS), RefInfo(..))
import Language.Drasil.UID (UID, HasUID(..))

import Control.Lens ((^.), makeLenses, Lens')

-- | A Reference contains the identifier ('UID'), a reference address ('LblType'),
-- a human-readable shortname ('ShortName'), and any extra information about the reference ('RefInfo').
data Reference = Reference
  { Reference -> UID
_ui :: UID
  ,  Reference -> LblType
ra :: LblType
  ,  Reference -> ShortName
sn :: ShortName}
makeLenses ''Reference

-- | A class that contains a list of 'Reference's.
class HasReference c where
  -- | Provides a 'Lens' to the 'Reference's.
  getReferences :: Lens' c [Reference]

-- | Equal if 'UID's are equal.
instance Eq            Reference where Reference
a == :: Reference -> Reference -> Bool
== Reference
b = (Reference
a Reference -> Getting UID Reference UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID Reference UID
forall c. HasUID c => Getter c UID
Getter Reference UID
uid) UID -> UID -> Bool
forall a. Eq a => a -> a -> Bool
== (Reference
b Reference -> Getting UID Reference UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID Reference UID
forall c. HasUID c => Getter c UID
Getter Reference UID
uid)
-- | Finds the 'UID' of a 'Reference'.
instance HasUID        Reference where uid :: Getter Reference UID
uid = (UID -> f UID) -> Reference -> f Reference
Lens' Reference UID
ui
-- | Finds the reference address contained in a 'Reference' (through a 'LblType').
instance HasRefAddress Reference where getRefAdd :: Reference -> LblType
getRefAdd = Reference -> LblType
ra
-- | Finds the shortname of the reference address used for the 'Reference'.
instance HasShortName  Reference where shortname :: Reference -> ShortName
shortname = Reference -> ShortName
sn
{--- Finds the reference information of a 'Reference'.
instance Referable Reference where
  refAdd r = r ^. ui
  renderRef = ra-}

-------------------------------

-- | Projector function that creates a 'Reference' from something 'Referable'.
ref :: (HasUID r, HasRefAddress r, HasShortName r) => r -> Reference
ref :: forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Reference
ref r
r = UID -> LblType -> ShortName -> Reference
Reference (r
r r -> Getting UID r UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID r UID
forall c. HasUID c => Getter c UID
Getter r UID
uid) (r -> LblType
forall b. HasRefAddress b => b -> LblType
getRefAdd r
r) (r -> ShortName
forall s. HasShortName s => s -> ShortName
shortname r
r)

-- Maybe just use r ^. uid without 'ref'?
-- | Takes the reference 'UID' and wraps it into a 'Sentence'.
refS :: (HasUID r, HasRefAddress r, HasShortName r) => r -> Sentence
refS :: forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence
refS r
r = r -> Sentence -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence -> Sentence
namedRef r
r Sentence
EmptyS

-- | Takes a 'Reference' with a name to be displayed and wraps it into a 'Sentence'.
-- Does not overwrite the shortname contained in the reference, but will only display as the given 'Sentence'.
namedRef :: (HasUID r, HasRefAddress r, HasShortName r) => r -> Sentence -> Sentence
namedRef :: forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence -> Sentence
namedRef r
r Sentence
s = r -> Sentence -> RefInfo -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence -> RefInfo -> Sentence
namedComplexRef r
r Sentence
s RefInfo
None

-- | Takes a 'Reference' with additional display info. Uses the internal shortname for its display name.
complexRef :: (HasUID r, HasRefAddress r, HasShortName r) => r -> RefInfo -> Sentence
complexRef :: forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> RefInfo -> Sentence
complexRef r
r = UID -> Sentence -> RefInfo -> Sentence
Ref (r -> Reference
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Reference
ref r
r Reference -> Getting UID Reference UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID Reference UID
forall c. HasUID c => Getter c UID
Getter Reference UID
uid) Sentence
EmptyS

-- | Takes a 'Reference' with a name to be displayed and any additional information and wraps it into a 'Sentence'.
-- Does not overwrite the shortname contained in the reference, but will only display as the given 'Sentence' along with the given 'RefInfo'.
namedComplexRef :: (HasUID r, HasRefAddress r, HasShortName r) => r -> Sentence -> RefInfo -> Sentence
namedComplexRef :: forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence -> RefInfo -> Sentence
namedComplexRef r
r = UID -> Sentence -> RefInfo -> Sentence
Ref (r -> Reference
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Reference
ref r
r Reference -> Getting UID Reference UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID Reference UID
forall c. HasUID c => Getter c UID
Getter Reference UID
uid)