{- This code really doesn't belong here, but it didn't belong in drasil-printers
   either! It will need to find a proper home, later. Right now, it needs to be
   'here' because it depends on things defined in this package
-}
module Drasil.Database.SearchTools (
  -- * Types
  TermAbbr, DomDefn,
  -- * Field Accessors
  longForm, shortForm, domain, definition,
  -- * Resolvers
  termResolve, termResolve',
  defResolve, defResolve',
  refResolve,
  findAllConcInsts
) where

import Control.Lens ((^.))

import Drasil.Database (ChunkDB, UID, find, findAll)
import Language.Drasil
import Language.Drasil.Document
import Theory.Drasil.DataDefinition (DataDefinition)
import Theory.Drasil.InstanceModel (InstanceModel)
import Theory.Drasil.GenDefn (GenDefn)
import Theory.Drasil.Theory (TheoryModel)

-- This is only needed for as long as `TypedUIDRef` is underused.
data TermAbbr = TermAbbr { TermAbbr -> NP
longForm :: NP, TermAbbr -> Maybe String
shortForm :: Maybe String }

-- | Search for a chunk that is an instance of 'Idea' and return its "term" and
-- abbreviation, erroring out if it doesn't exist.
termResolve :: (NP -> Maybe String -> c) -> ChunkDB -> UID -> c
termResolve :: forall c. (NP -> Maybe String -> c) -> ChunkDB -> UID -> c
termResolve NP -> Maybe String -> c
f ChunkDB
db UID
trg
  | (Just IdeaDict
c) <- UID -> ChunkDB -> Maybe IdeaDict
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe IdeaDict            = (NP -> Maybe String -> c) -> IdeaDict -> c
forall t c. Idea t => (NP -> Maybe String -> c) -> t -> c
go NP -> Maybe String -> c
f IdeaDict
c
  | (Just CI
c) <- UID -> ChunkDB -> Maybe CI
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe CI                  = (NP -> Maybe String -> c) -> CI -> c
forall t c. Idea t => (NP -> Maybe String -> c) -> t -> c
go NP -> Maybe String -> c
f CI
c
  | (Just DefinedQuantityDict
c) <- UID -> ChunkDB -> Maybe DefinedQuantityDict
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe DefinedQuantityDict = (NP -> Maybe String -> c) -> DefinedQuantityDict -> c
forall t c. Idea t => (NP -> Maybe String -> c) -> t -> c
go NP -> Maybe String -> c
f DefinedQuantityDict
c
  | (Just ConceptChunk
c) <- UID -> ChunkDB -> Maybe ConceptChunk
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe ConceptChunk        = (NP -> Maybe String -> c) -> ConceptChunk -> c
forall t c. Idea t => (NP -> Maybe String -> c) -> t -> c
go NP -> Maybe String -> c
f ConceptChunk
c
  | (Just UnitDefn
c) <- UID -> ChunkDB -> Maybe UnitDefn
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe UnitDefn            = (NP -> Maybe String -> c) -> UnitDefn -> c
forall t c. Idea t => (NP -> Maybe String -> c) -> t -> c
go NP -> Maybe String -> c
f UnitDefn
c
  | (Just DataDefinition
c) <- UID -> ChunkDB -> Maybe DataDefinition
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe DataDefinition      = (NP -> Maybe String -> c) -> DataDefinition -> c
forall t c. Idea t => (NP -> Maybe String -> c) -> t -> c
go NP -> Maybe String -> c
f DataDefinition
c
  | (Just InstanceModel
c) <- UID -> ChunkDB -> Maybe InstanceModel
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe InstanceModel       = (NP -> Maybe String -> c) -> InstanceModel -> c
forall t c. Idea t => (NP -> Maybe String -> c) -> t -> c
go NP -> Maybe String -> c
f InstanceModel
c
  | (Just GenDefn
c) <- UID -> ChunkDB -> Maybe GenDefn
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe GenDefn             = (NP -> Maybe String -> c) -> GenDefn -> c
forall t c. Idea t => (NP -> Maybe String -> c) -> t -> c
go NP -> Maybe String -> c
f GenDefn
c
  | (Just TheoryModel
c) <- UID -> ChunkDB -> Maybe TheoryModel
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe TheoryModel         = (NP -> Maybe String -> c) -> TheoryModel -> c
forall t c. Idea t => (NP -> Maybe String -> c) -> t -> c
go NP -> Maybe String -> c
f TheoryModel
c
  | (Just ConceptInstance
c) <- UID -> ChunkDB -> Maybe ConceptInstance
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe ConceptInstance     = (NP -> Maybe String -> c) -> ConceptInstance -> c
forall t c. Idea t => (NP -> Maybe String -> c) -> t -> c
go NP -> Maybe String -> c
f ConceptInstance
c
  | Bool
otherwise = String -> c
forall a. HasCallStack => String -> a
error (String -> c) -> String -> c
forall a b. (a -> b) -> a -> b
$ String
"Term: `" String -> String -> String
forall a. [a] -> [a] -> [a]
++ UID -> String
forall a. Show a => a -> String
show UID
trg String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"` not found in TermMap"
  where
    go :: Idea t => (NP -> Maybe String -> c) -> t -> c
    go :: forall t c. Idea t => (NP -> Maybe String -> c) -> t -> c
go NP -> Maybe String -> c
f' t
c = NP -> Maybe String -> c
f' (t
c t -> Getting NP t NP -> NP
forall s a. s -> Getting a s a -> a
^. Getting NP t NP
forall c. NamedIdea c => Lens' c NP
Lens' t NP
term) (t -> Maybe String
forall c. Idea c => c -> Maybe String
getA t
c)

-- | Find a chunk's "term" and abbreviation, erroring out if it doesn't exist.
termResolve' :: ChunkDB -> UID -> TermAbbr
termResolve' :: ChunkDB -> UID -> TermAbbr
termResolve' = (NP -> Maybe String -> TermAbbr) -> ChunkDB -> UID -> TermAbbr
forall c. (NP -> Maybe String -> c) -> ChunkDB -> UID -> c
termResolve NP -> Maybe String -> TermAbbr
TermAbbr

data DomDefn = DomDefn { DomDefn -> [UID]
domain :: [UID], DomDefn -> Sentence
definition :: Sentence }

-- | Looks up a 'UID' in the 'ChunkDB' for a chunk's definition concept domain
-- and definition. If nothing is found, an error is thrown.
defResolve :: ([UID] -> Sentence -> c) -> ChunkDB -> UID -> c
defResolve :: forall c. ([UID] -> Sentence -> c) -> ChunkDB -> UID -> c
defResolve [UID] -> Sentence -> c
f ChunkDB
db UID
trg
  | (Just DefinedQuantityDict
c) <- UID -> ChunkDB -> Maybe DefinedQuantityDict
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe DefinedQuantityDict = ([UID] -> Sentence -> c) -> DefinedQuantityDict -> c
forall c r. Concept c => ([UID] -> Sentence -> r) -> c -> r
go [UID] -> Sentence -> c
f DefinedQuantityDict
c
  | (Just ConceptChunk
c) <- UID -> ChunkDB -> Maybe ConceptChunk
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe ConceptChunk        = ([UID] -> Sentence -> c) -> ConceptChunk -> c
forall c r. Concept c => ([UID] -> Sentence -> r) -> c -> r
go [UID] -> Sentence -> c
f ConceptChunk
c
  | (Just UnitDefn
c) <- UID -> ChunkDB -> Maybe UnitDefn
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe UnitDefn            = ([UID] -> Sentence -> c) -> UnitDefn -> c
forall c r. Concept c => ([UID] -> Sentence -> r) -> c -> r
go [UID] -> Sentence -> c
f UnitDefn
c
  | (Just InstanceModel
c) <- UID -> ChunkDB -> Maybe InstanceModel
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe InstanceModel       = ([UID] -> Sentence -> c) -> InstanceModel -> c
forall c r. Concept c => ([UID] -> Sentence -> r) -> c -> r
go [UID] -> Sentence -> c
f InstanceModel
c
  | (Just GenDefn
c) <- UID -> ChunkDB -> Maybe GenDefn
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe GenDefn             = ([UID] -> Sentence -> c) -> GenDefn -> c
forall c r. Concept c => ([UID] -> Sentence -> r) -> c -> r
go [UID] -> Sentence -> c
f GenDefn
c
  | (Just TheoryModel
c) <- UID -> ChunkDB -> Maybe TheoryModel
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe TheoryModel         = ([UID] -> Sentence -> c) -> TheoryModel -> c
forall c r. Concept c => ([UID] -> Sentence -> r) -> c -> r
go [UID] -> Sentence -> c
f TheoryModel
c
  | (Just ConceptInstance
c) <- UID -> ChunkDB -> Maybe ConceptInstance
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe ConceptInstance     = ([UID] -> Sentence -> c) -> ConceptInstance -> c
forall c r. Concept c => ([UID] -> Sentence -> r) -> c -> r
go [UID] -> Sentence -> c
f ConceptInstance
c
  | Bool
otherwise = String -> c
forall a. HasCallStack => String -> a
error (String -> c) -> String -> c
forall a b. (a -> b) -> a -> b
$ String
"Definition: `" String -> String -> String
forall a. [a] -> [a] -> [a]
++ UID -> String
forall a. Show a => a -> String
show UID
trg String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"` not found in ConceptMap"
  where
    go :: Concept c => ([UID] -> Sentence -> r) -> c -> r
    go :: forall c r. Concept c => ([UID] -> Sentence -> r) -> c -> r
go [UID] -> Sentence -> r
f' c
c = [UID] -> Sentence -> r
f' (c -> [UID]
forall c. ConceptDomain c => c -> [UID]
cdom c
c) (c
c c -> Getting Sentence c Sentence -> Sentence
forall s a. s -> Getting a s a -> a
^. Getting Sentence c Sentence
forall c. Definition c => Lens' c Sentence
Lens' c Sentence
defn)

defResolve' :: ChunkDB -> UID -> DomDefn
defResolve' :: ChunkDB -> UID -> DomDefn
defResolve' = ([UID] -> Sentence -> DomDefn) -> ChunkDB -> UID -> DomDefn
forall c. ([UID] -> Sentence -> c) -> ChunkDB -> UID -> c
defResolve [UID] -> Sentence -> DomDefn
DomDefn

-- | Looks up a 'UID' in a 'ChunkDB' with a /referrable/ handle.
refResolve :: ChunkDB -> UID -> Reference
refResolve :: ChunkDB -> UID -> Reference
refResolve ChunkDB
db UID
trg
  | (Just DataDefinition
c) <- UID -> ChunkDB -> Maybe DataDefinition
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe DataDefinition      = DataDefinition -> Reference
forall r.
(IsChunk r, HasRefAddress r, HasShortName r) =>
r -> Reference
ref DataDefinition
c
  | (Just InstanceModel
c) <- UID -> ChunkDB -> Maybe InstanceModel
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe InstanceModel       = InstanceModel -> Reference
forall r.
(IsChunk r, HasRefAddress r, HasShortName r) =>
r -> Reference
ref InstanceModel
c
  | (Just GenDefn
c) <- UID -> ChunkDB -> Maybe GenDefn
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe GenDefn             = GenDefn -> Reference
forall r.
(IsChunk r, HasRefAddress r, HasShortName r) =>
r -> Reference
ref GenDefn
c
  | (Just TheoryModel
c) <- UID -> ChunkDB -> Maybe TheoryModel
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe TheoryModel         = TheoryModel -> Reference
forall r.
(IsChunk r, HasRefAddress r, HasShortName r) =>
r -> Reference
ref TheoryModel
c
  | (Just ConceptInstance
c) <- UID -> ChunkDB -> Maybe ConceptInstance
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe ConceptInstance     = ConceptInstance -> Reference
forall r.
(IsChunk r, HasRefAddress r, HasShortName r) =>
r -> Reference
ref ConceptInstance
c
  | (Just LabelledContent
c) <- UID -> ChunkDB -> Maybe LabelledContent
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe LabelledContent     = LabelledContent -> Reference
forall r.
(IsChunk r, HasRefAddress r, HasShortName r) =>
r -> Reference
ref LabelledContent
c
  | (Just Citation
c) <- UID -> ChunkDB -> Maybe Citation
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe Citation            = Citation -> Reference
forall r.
(IsChunk r, HasRefAddress r, HasShortName r) =>
r -> Reference
ref Citation
c
  | (Just Section
c) <- UID -> ChunkDB -> Maybe Section
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe Section             = Section -> Reference
forall r.
(IsChunk r, HasRefAddress r, HasShortName r) =>
r -> Reference
ref Section
c
  -- FIXME: When URIs are made not-`Reference`-types, we can (should) remove the
  -- below `Just` case.
  | (Just Reference
c) <- UID -> ChunkDB -> Maybe Reference
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
trg ChunkDB
db :: Maybe Reference           = Reference
c
  | Bool
otherwise = String -> Reference
forall a. HasCallStack => String -> a
error (String -> Reference) -> String -> Reference
forall a b. (a -> b) -> a -> b
$ String
"Reference for `" String -> String -> String
forall a. [a] -> [a] -> [a]
++ UID -> String
forall a. Show a => a -> String
show UID
trg String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"` not found."

findAllConcInsts :: ChunkDB -> [ConceptInstance]
findAllConcInsts :: ChunkDB -> [ConceptInstance]
findAllConcInsts = ChunkDB -> [ConceptInstance]
forall a. TypeableChunk a => ChunkDB -> [a]
findAll