{-# LANGUAGE TemplateHaskell #-}
-- | The lowest level of chunks in Drasil. It all starts with an identifier and a term.
module Language.Drasil.Chunk.NamedIdea (
  -- * Types
  NamedChunk, IdeaDict,
  -- * Classes
  NamedIdea(..), Idea(..),
  -- * Constructors
  nc, ncUID, nw, mkIdea, mkIdeaUID
) where

import Language.Drasil.UID (mkUid, UID, HasUID(..))
import Control.Lens ((^.), makeLenses)

import Language.Drasil.NounPhrase.Core ( NP )
import Control.Lens.Lens (Lens')

-- TODO: Why does a NamedIdea need a UID? It might need a UID to be registered in the chunk map.
-- | A NamedIdea is a 'term' that we've identified (has a 'UID') as 
-- being worthy of naming.
class HasUID c => NamedIdea c where
  -- | Lens to the term (a noun phrase).
  term :: Lens' c NP

-- | An 'Idea' is the combination of a 'NamedIdea' and a 'CommonIdea'.
-- In other words, it /may/ have an acronym/abbreviation.
class NamedIdea c => Idea c where
  -- | Gets the acronym/abbreviation.
  getA :: c -> Maybe String
  --Get Abbreviation/Acronym? These might need to be separated 
  --depending on contexts, but for now I don't see a problem with it.

-- === DATA TYPES/INSTANCES === --
-- | Used for anything worth naming. Note that a 'NamedChunk' does not have an acronym/abbreviation
-- as that's a 'CommonIdea', which has its own representation. Contains
-- a 'UID' and a term that we can capitalize or pluralize ('NP').
--
-- Ex. Anything worth naming must start out somewhere. Before we can assign equations
-- and values and symbols to something like the arm of a pendulum, we must first give it a name. 
data NamedChunk = NC {
  NamedChunk -> UID
_uu :: UID,
  NamedChunk -> NP
_np :: NP
}
makeLenses ''NamedChunk

-- | Equal if 'UID's are equal.
instance Eq        NamedChunk where c1 :: NamedChunk
c1 == :: NamedChunk -> NamedChunk -> Bool
== c2 :: NamedChunk
c2 = (NamedChunk
c1 NamedChunk -> Getting UID NamedChunk UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID NamedChunk UID
forall c. HasUID c => Lens' c UID
uid) UID -> UID -> Bool
forall a. Eq a => a -> a -> Bool
== (NamedChunk
c2 NamedChunk -> Getting UID NamedChunk UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID NamedChunk UID
forall c. HasUID c => Lens' c UID
uid)
-- | Finds the 'UID' of the 'NamedChunk'.
instance HasUID    NamedChunk where uid :: (UID -> f UID) -> NamedChunk -> f NamedChunk
uid = (UID -> f UID) -> NamedChunk -> f NamedChunk
Lens' NamedChunk UID
uu
-- | Finds the term ('NP') of the 'NamedChunk'.
instance NamedIdea NamedChunk where term :: (NP -> f NP) -> NamedChunk -> f NamedChunk
term = (NP -> f NP) -> NamedChunk -> f NamedChunk
Lens' NamedChunk NP
np
-- | Finds the idea of a 'NamedChunk' (always 'Nothing').
instance Idea      NamedChunk where getA :: NamedChunk -> Maybe String
getA _ = Maybe String
forall a. Maybe a
Nothing

-- TODO: Add in function to check UIDs (see #2788).
-- TODO: Any constructor that takes in a UID should be built off of this one so that
-- the UID may be checked by the first TODO.
-- | 'NamedChunk' constructor, takes a 'String' for its 'UID' and a term.
nc :: String -> NP -> NamedChunk
nc :: String -> NP -> NamedChunk
nc s :: String
s = UID -> NP -> NamedChunk
NC (String -> UID
mkUid String
s)

-- | Similar to 'nc', but takes in the 'UID' in the form of a 'UID' rather than a 'String'.
ncUID :: UID -> NP -> NamedChunk
ncUID :: UID -> NP -> NamedChunk
ncUID = UID -> NP -> NamedChunk
NC

-- Don't export the record accessors.
-- | 'IdeaDict' is the canonical dictionary associated to an 'Idea'.
-- Contains a 'NamedChunk' that could have an abbreviation ('Maybe' 'String').
--
-- Ex. The project name "Double Pendulum" may have the abbreviation "DblPendulum".
data IdeaDict = IdeaDict {
  IdeaDict -> NamedChunk
_nc' :: NamedChunk,
  IdeaDict -> Maybe String
mabbr :: Maybe String
}
makeLenses ''IdeaDict

-- | Equal if 'UID's are equal.
instance Eq        IdeaDict where a :: IdeaDict
a == :: IdeaDict -> IdeaDict -> Bool
== b :: IdeaDict
b = IdeaDict
a IdeaDict -> Getting UID IdeaDict UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID IdeaDict UID
forall c. HasUID c => Lens' c UID
uid UID -> UID -> Bool
forall a. Eq a => a -> a -> Bool
== IdeaDict
b IdeaDict -> Getting UID IdeaDict UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID IdeaDict UID
forall c. HasUID c => Lens' c UID
uid
-- | Finds the 'UID' of the 'NamedChunk' used to make the 'IdeaDict'.
instance HasUID    IdeaDict where uid :: (UID -> f UID) -> IdeaDict -> f IdeaDict
uid = (NamedChunk -> f NamedChunk) -> IdeaDict -> f IdeaDict
Lens' IdeaDict NamedChunk
nc' ((NamedChunk -> f NamedChunk) -> IdeaDict -> f IdeaDict)
-> ((UID -> f UID) -> NamedChunk -> f NamedChunk)
-> (UID -> f UID)
-> IdeaDict
-> f IdeaDict
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UID -> f UID) -> NamedChunk -> f NamedChunk
forall c. HasUID c => Lens' c UID
uid
-- | Finds the term ('NP') of the 'NamedChunk' used to make the 'IdeaDict'.
instance NamedIdea IdeaDict where term :: (NP -> f NP) -> IdeaDict -> f IdeaDict
term = (NamedChunk -> f NamedChunk) -> IdeaDict -> f IdeaDict
Lens' IdeaDict NamedChunk
nc' ((NamedChunk -> f NamedChunk) -> IdeaDict -> f IdeaDict)
-> ((NP -> f NP) -> NamedChunk -> f NamedChunk)
-> (NP -> f NP)
-> IdeaDict
-> f IdeaDict
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (NP -> f NP) -> NamedChunk -> f NamedChunk
forall c. NamedIdea c => Lens' c NP
term
-- | Finds the abbreviation of the 'IdeaDict'.
instance Idea      IdeaDict where getA :: IdeaDict -> Maybe String
getA = IdeaDict -> Maybe String
mabbr
  
-- | 'IdeaDict' constructor, takes a 'UID', 'NP', and 
-- an abbreviation in the form of 'Maybe' 'String'.
mkIdea :: String -> NP -> Maybe String -> IdeaDict
mkIdea :: String -> NP -> Maybe String -> IdeaDict
mkIdea s :: String
s np' :: NP
np' = NamedChunk -> Maybe String -> IdeaDict
IdeaDict (String -> NP -> NamedChunk
nc String
s NP
np')

-- | Same as 'mkIdea' but takes a 'UID' rather than a 'String'.
mkIdeaUID :: UID -> NP -> Maybe String -> IdeaDict
mkIdeaUID :: UID -> NP -> Maybe String -> IdeaDict
mkIdeaUID s :: UID
s np' :: NP
np' = NamedChunk -> Maybe String -> IdeaDict
IdeaDict (UID -> NP -> NamedChunk
ncUID UID
s NP
np')

-- | Historical name: nw comes from 'named wrapped' from when
-- 'NamedIdea' exported 'getA' (now in 'Idea'). But there are
-- no more wrappers, instead we have explicit dictionaries. Unwraps
-- an 'Idea' and places its 'UID' and 'NP' into an 'IdeaDict' with
-- 'Nothing' for an abbreviation.
nw :: Idea c => c -> IdeaDict
nw :: c -> IdeaDict
nw c :: c
c = NamedChunk -> Maybe String -> IdeaDict
IdeaDict (UID -> NP -> NamedChunk
NC (c
c c -> Getting UID c UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID c UID
forall c. HasUID c => Lens' c UID
uid) (c
c c -> Getting NP c NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP c NP
forall c. NamedIdea c => Lens' c NP
term)) (c -> Maybe String
forall c. Idea c => c -> Maybe String
getA c
c)