-- | Utilities to get grab certain chunks (from 'Expr', 'Sentence', etc) by
-- 'UID' and dereference the chunk it refers to.
module Drasil.GetChunks (
  ccss, ccss', combine, vars,
  resolveBibliography
) where

import Data.List (nub, sortBy)
import Data.Maybe (mapMaybe)
import qualified Data.Set as Set

import Language.Drasil
import Language.Drasil.Development (sdep)
import Language.Drasil.ModelExpr.Development (meDep)
import Drasil.Database (ChunkDB, findOrErr, find, UID)
import Drasil.Database.SearchTools (defResolve', DomDefn(definition))

-- | Gets a list of quantities ('DefinedQuantityDict') from an equation in order to print.
vars :: ModelExpr -> ChunkDB -> [DefinedQuantityDict]
vars :: ModelExpr -> ChunkDB -> [DefinedQuantityDict]
vars ModelExpr
e ChunkDB
m = (UID -> DefinedQuantityDict) -> [UID] -> [DefinedQuantityDict]
forall a b. (a -> b) -> [a] -> [b]
map (UID -> ChunkDB -> DefinedQuantityDict
forall a. Typeable a => UID -> ChunkDB -> a
`findOrErr` ChunkDB
m) ([UID] -> [DefinedQuantityDict]) -> [UID] -> [DefinedQuantityDict]
forall a b. (a -> b) -> a -> b
$ ModelExpr -> [UID]
meDep ModelExpr
e

-- | Gets a list of quantities ('DefinedQuantityDict') from a 'Sentence' in order to print.
vars' :: Sentence -> ChunkDB -> [DefinedQuantityDict]
vars' :: Sentence -> ChunkDB -> [DefinedQuantityDict]
vars' Sentence
a ChunkDB
m = (UID -> DefinedQuantityDict) -> [UID] -> [DefinedQuantityDict]
forall a b. (a -> b) -> [a] -> [b]
map (UID -> ChunkDB -> DefinedQuantityDict
forall a. Typeable a => UID -> ChunkDB -> a
`findOrErr` ChunkDB
m) ([UID] -> [DefinedQuantityDict]) -> [UID] -> [DefinedQuantityDict]
forall a b. (a -> b) -> a -> b
$ Set UID -> [UID]
forall a. Set a -> [a]
Set.toList (Sentence -> Set UID
sdep Sentence
a)

-- | Combines the functions of 'vars' and 'concpt' to create a list of 'DefinedQuantityDict's from a 'Sentence'.
combine :: Sentence -> ChunkDB -> [DefinedQuantityDict]
combine :: Sentence -> ChunkDB -> [DefinedQuantityDict]
combine Sentence
a ChunkDB
m = (DefinedQuantityDict -> Sentence -> DefinedQuantityDict)
-> [DefinedQuantityDict] -> [Sentence] -> [DefinedQuantityDict]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith DefinedQuantityDict -> Sentence -> DefinedQuantityDict
forall c.
(Quantity c, MayHaveUnit c) =>
c -> Sentence -> DefinedQuantityDict
dqdQd (Sentence -> ChunkDB -> [DefinedQuantityDict]
vars' Sentence
a ChunkDB
m) (Sentence -> ChunkDB -> [Sentence]
concpt Sentence
a ChunkDB
m)

-- | Combines the functions of 'vars' and 'concpt' to create a list of 'DefinedQuantityDict's from an equation.
combine' :: ModelExpr -> ChunkDB -> [DefinedQuantityDict]
combine' :: ModelExpr -> ChunkDB -> [DefinedQuantityDict]
combine' ModelExpr
a ChunkDB
m = (DefinedQuantityDict -> Sentence -> DefinedQuantityDict)
-> [DefinedQuantityDict] -> [Sentence] -> [DefinedQuantityDict]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith DefinedQuantityDict -> Sentence -> DefinedQuantityDict
forall c.
(Quantity c, MayHaveUnit c) =>
c -> Sentence -> DefinedQuantityDict
dqdQd (ModelExpr -> ChunkDB -> [DefinedQuantityDict]
vars ModelExpr
a ChunkDB
m) (ModelExpr -> ChunkDB -> [Sentence]
concpt' ModelExpr
a ChunkDB
m)

-- | Gets a list of defined quantities ('DefinedQuantityDict's) from 'Sentence's and expressions that are contained in the database ('ChunkDB').
ccss :: [Sentence] -> [ModelExpr] -> ChunkDB -> [DefinedQuantityDict]
ccss :: [Sentence] -> [ModelExpr] -> ChunkDB -> [DefinedQuantityDict]
ccss [Sentence]
s [ModelExpr]
e ChunkDB
c = [DefinedQuantityDict] -> [DefinedQuantityDict]
forall a. Eq a => [a] -> [a]
nub ([DefinedQuantityDict] -> [DefinedQuantityDict])
-> [DefinedQuantityDict] -> [DefinedQuantityDict]
forall a b. (a -> b) -> a -> b
$ (Sentence -> [DefinedQuantityDict])
-> [Sentence] -> [DefinedQuantityDict]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (Sentence -> ChunkDB -> [DefinedQuantityDict]
`combine` ChunkDB
c) [Sentence]
s [DefinedQuantityDict]
-> [DefinedQuantityDict] -> [DefinedQuantityDict]
forall a. [a] -> [a] -> [a]
++ (ModelExpr -> [DefinedQuantityDict])
-> [ModelExpr] -> [DefinedQuantityDict]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (ModelExpr -> ChunkDB -> [DefinedQuantityDict]
`combine'` ChunkDB
c) [ModelExpr]
e

-- | Gets a list of quantities ('DefinedQuantityDict's) from 'Sentence's and expressions that are contained in the database ('ChunkDB').
ccss' :: [Sentence] -> [ModelExpr] -> ChunkDB -> [DefinedQuantityDict]
ccss' :: [Sentence] -> [ModelExpr] -> ChunkDB -> [DefinedQuantityDict]
ccss' [Sentence]
s [ModelExpr]
e ChunkDB
c = [DefinedQuantityDict] -> [DefinedQuantityDict]
forall a. Eq a => [a] -> [a]
nub ([DefinedQuantityDict] -> [DefinedQuantityDict])
-> [DefinedQuantityDict] -> [DefinedQuantityDict]
forall a b. (a -> b) -> a -> b
$ (Sentence -> [DefinedQuantityDict])
-> [Sentence] -> [DefinedQuantityDict]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (Sentence -> ChunkDB -> [DefinedQuantityDict]
`vars'` ChunkDB
c) [Sentence]
s [DefinedQuantityDict]
-> [DefinedQuantityDict] -> [DefinedQuantityDict]
forall a. [a] -> [a] -> [a]
++ (ModelExpr -> [DefinedQuantityDict])
-> [ModelExpr] -> [DefinedQuantityDict]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (ModelExpr -> ChunkDB -> [DefinedQuantityDict]
`vars` ChunkDB
c) [ModelExpr]
e

-- | Gets a list of concepts ('ConceptChunk') from a 'Sentence' in order to print.
concpt :: Sentence -> ChunkDB -> [Sentence]
concpt :: Sentence -> ChunkDB -> [Sentence]
concpt Sentence
a ChunkDB
m = (UID -> Sentence) -> [UID] -> [Sentence]
forall a b. (a -> b) -> [a] -> [b]
map (DomDefn -> Sentence
definition (DomDefn -> Sentence) -> (UID -> DomDefn) -> UID -> Sentence
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ChunkDB -> UID -> DomDefn
defResolve' ChunkDB
m) ([UID] -> [Sentence]) -> [UID] -> [Sentence]
forall a b. (a -> b) -> a -> b
$ Set UID -> [UID]
forall a. Set a -> [a]
Set.toList (Sentence -> Set UID
sdep Sentence
a)

-- | Gets a list of concepts ('ConceptChunk') from an expression in order to print.
concpt' :: ModelExpr -> ChunkDB -> [Sentence]
concpt' :: ModelExpr -> ChunkDB -> [Sentence]
concpt' ModelExpr
a ChunkDB
m = (UID -> Sentence) -> [UID] -> [Sentence]
forall a b. (a -> b) -> [a] -> [b]
map (DomDefn -> Sentence
definition (DomDefn -> Sentence) -> (UID -> DomDefn) -> UID -> Sentence
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ChunkDB -> UID -> DomDefn
defResolve' ChunkDB
m) ([UID] -> [Sentence]) -> [UID] -> [Sentence]
forall a b. (a -> b) -> a -> b
$ ModelExpr -> [UID]
meDep ModelExpr
a

-- | Given a 'ChunkDB' and a set of 'UID's, looks up the corresponding
-- 'Citation's and returns them sorted by author, year, and title.
--
-- FIXME: This function assumes that all 'UID's in the set correspond to
-- 'Citation's in the database. If a 'UID' does not correspond to a 'Citation',
-- it is simply ignored. This should rather rely on a set of 'UIDRef Citation's.
resolveBibliography :: ChunkDB -> Set.Set UID -> [Citation]
resolveBibliography :: ChunkDB -> Set UID -> [Citation]
resolveBibliography ChunkDB
db Set UID
uids = (Citation -> Citation -> Ordering) -> [Citation] -> [Citation]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy Citation -> Citation -> Ordering
forall c. HasFields c => c -> c -> Ordering
compareAuthYearTitle [Citation]
cites
  where
    cites :: [Citation]
cites = (UID -> Maybe Citation) -> [UID] -> [Citation]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (UID -> ChunkDB -> Maybe Citation
forall a. Typeable a => UID -> ChunkDB -> Maybe a
`find` ChunkDB
db) (Set UID -> [UID]
forall a. Set a -> [a]
Set.toList Set UID
uids)