{-# Language TemplateHaskell #-}
-- | Defines the chunk type to hold citations.
module Language.Drasil.Chunk.Citation (
  -- * Types
  Citation, BibRef, EntryID,
  -- * Class
  HasCitation(..),
  -- * Accessors
  citeID, citeKind,
  -- * Citation smart constructors
  cArticle, cBookA, cBookE, cBooklet,
  cInBookACP, cInBookECP, cInBookAC, cInBookEC, cInBookAP, cInBookEP,
  cInCollection, cInProceedings, cManual, cMThesis, cMisc, cPhDThesis,
  cProceedings, cTechReport, cUnpublished
) where

import Language.Drasil.People (People)

import Language.Drasil.ShortName (HasShortName(..), ShortName, shortname')
import Language.Drasil.Data.Citation (HasFields(..), CitationKind(..), CiteField,
  author, chapter, pages, editor, bookTitle, title,
  year, school, journal, institution, note, publisher)
import Language.Drasil.Sentence (Sentence(S))
import Language.Drasil.Label.Type (LblType(Citation), Referable(..), HasRefAddress(..))
import Language.Drasil.UID (UID, HasUID(..), showUID, mkUid)

import Control.Lens (makeLenses, Lens')

-- | A list of 'Citation's.
type BibRef = [Citation]
-- | A 'String' that should contain no spaces.
type EntryID = String

-- | All citations require a unique identifier used by the Drasil chunk.
-- We will re-use the 'UID' part as an EntryID ('String') used for creating reference links.
-- Finally we will have the reference information ('CitationKind', 'CiteField's, and a 'ShortName').
--
-- Ex. A reference to a thesis paper like Koothoor's "Document driven approach to certifying
-- scientific computing software" would include the affiliated university, publishing year, and city.
data Citation = Cite
  { Citation -> CitationKind
_citeKind :: CitationKind
  , Citation -> [CiteField]
_fields   :: [CiteField]
  , Citation -> UID
_citeID   :: UID
  ,  Citation -> ShortName
sn       :: ShortName
  }
makeLenses ''Citation

-- | Some documents, as well as some pieces of knowledge, have citations.
class HasCitation c where
  -- | Provides a 'Lens' to the citations.
  getCitations :: Lens' c [Citation]

-- | Finds 'UID' of the 'Citation'.
instance HasUID       Citation where uid :: Getter Citation UID
uid       = (UID -> f UID) -> Citation -> f Citation
Lens' Citation UID
citeID
-- | Finds 'ShortName' of the 'Citation'.
instance HasShortName Citation where shortname :: Citation -> ShortName
shortname = Citation -> ShortName
sn
-- | Finds 'Fields' of the 'Citation'.
instance HasFields    Citation where getFields :: Lens' Citation [CiteField]
getFields = ([CiteField] -> f [CiteField]) -> Citation -> f Citation
Lens' Citation [CiteField]
fields
-- | Gets the reference information of a 'Citation'.
instance Referable    Citation where
  refAdd :: Citation -> String
refAdd    = Citation -> String
forall a. HasUID a => a -> String
showUID -- Citation UID should be unique as a reference address.
  renderRef :: Citation -> LblType
renderRef = String -> LblType
Citation (String -> LblType) -> (Citation -> String) -> Citation -> LblType
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Citation -> String
forall s. Referable s => s -> String
refAdd -- Get the alternate form of reference address.
-- | Gets the reference address of a 'Citation'.
instance HasRefAddress Citation where getRefAdd :: Citation -> LblType
getRefAdd = String -> LblType
Citation (String -> LblType) -> (Citation -> String) -> Citation -> LblType
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Citation -> String
forall a. HasUID a => a -> String
showUID

-- | Smart constructor which implicitly uses EntryID as chunk id.
cite :: CitationKind -> [CiteField] -> String -> Citation
cite :: CitationKind -> [CiteField] -> String -> Citation
cite CitationKind
ck [CiteField]
cfs String
n
  | Char
' ' Char -> String -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
n = String -> Citation
forall a. HasCallStack => String -> a
error String
"Citation names may not contain spaces." -- TODO: Why not?
  | Bool
otherwise    = CitationKind -> [CiteField] -> UID -> ShortName -> Citation
Cite CitationKind
ck [CiteField]
cfs (String -> UID
mkUid String
n) (Sentence -> ShortName
shortname' (String -> Sentence
S String
n))

-- | Article citation requires author(s), title, journal, year.
-- Optional fields can be: volume, number, pages, month, and note.
-- Implicitly uses the EntryID as the chunk id.
cArticle :: People -> String -> String -> Int -> [CiteField] -> String -> Citation
cArticle :: People
-> String -> String -> Int -> [CiteField] -> String -> Citation
cArticle People
aut String
t String
journ Int
yr [CiteField]
opt = CitationKind -> [CiteField] -> String -> Citation
cite CitationKind
Article
  (People -> CiteField
author People
aut CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> CiteField
title String
t CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> CiteField
journal String
journ CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: Int -> CiteField
year Int
yr CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: [CiteField]
opt)

-- | Book citation requires author or editor, title, publisher, year.
-- Optional fields can be volume or number, series, address, edition, month, and note.
-- Implicitly uses the EntryID as the chunk id.
cBookA, cBookE :: People -> String -> String -> Int ->
  [CiteField] -> String -> Citation
-- | Book citation by author.
cBookA :: People
-> String -> String -> Int -> [CiteField] -> String -> Citation
cBookA People
aut String
t String
pub Int
yr [CiteField]
opt = CitationKind -> [CiteField] -> String -> Citation
cite CitationKind
Book (People -> CiteField
author People
aut CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> String -> Int -> [CiteField] -> [CiteField]
stdFields String
t String
pub Int
yr [CiteField]
opt)
-- | Book citation by editor.
cBookE :: People
-> String -> String -> Int -> [CiteField] -> String -> Citation
cBookE People
ed String
t String
pub Int
yr [CiteField]
opt = CitationKind -> [CiteField] -> String -> Citation
cite CitationKind
Book (People -> CiteField
editor People
ed CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> String -> Int -> [CiteField] -> [CiteField]
stdFields String
t String
pub Int
yr [CiteField]
opt)

-- | Booklet citation requires title.
-- Optional fields can be author, how published, address, month, year, note.
-- Implicitly uses the EntryID as the chunk id.
cBooklet :: String -> [CiteField] -> String -> Citation
cBooklet :: String -> [CiteField] -> String -> Citation
cBooklet String
t [CiteField]
opt = CitationKind -> [CiteField] -> String -> Citation
cite CitationKind
Booklet (String -> CiteField
title String
t CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: [CiteField]
opt)

-- | InBook citation requires author or editor, title, chapter and/or pages,
-- publisher, year. Optional fields can be volume or number, series, type,
-- address, edition, month, and note.
-- Implicitly uses the EntryID as the chunk id.
-- This smart constructor includes both chapter and page numbers.
cInBookACP, cInBookECP :: People -> String -> Int -> [Int] ->
  String -> Int -> [CiteField] -> String -> Citation
-- | InBook citation by author.
cInBookACP :: People
-> String
-> Int
-> [Int]
-> String
-> Int
-> [CiteField]
-> String
-> Citation
cInBookACP People
auth String
t Int
chap [Int]
pgs String
pub Int
yr [CiteField]
opt = CitationKind -> [CiteField] -> String -> Citation
cite CitationKind
InBook
  (People -> CiteField
author People
auth CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: Int -> CiteField
chapter Int
chap CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: [Int] -> CiteField
pages [Int]
pgs CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> String -> Int -> [CiteField] -> [CiteField]
stdFields String
t String
pub Int
yr [CiteField]
opt)
-- | InBook citation by editor.
cInBookECP :: People
-> String
-> Int
-> [Int]
-> String
-> Int
-> [CiteField]
-> String
-> Citation
cInBookECP People
ed String
t Int
chap [Int]
pgs String
pub Int
yr [CiteField]
opt = CitationKind -> [CiteField] -> String -> Citation
cite CitationKind
InBook
  (People -> CiteField
editor People
ed CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: Int -> CiteField
chapter Int
chap CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: [Int] -> CiteField
pages [Int]
pgs CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> String -> Int -> [CiteField] -> [CiteField]
stdFields String
t String
pub Int
yr [CiteField]
opt)

-- | InBook citation excluding page numbers.
cInBookAC, cInBookEC :: People -> String -> Int ->
  String -> Int -> [CiteField] -> String -> Citation

-- | Otherwise identical to 'cInBookACP'.
cInBookAC :: People
-> String
-> Int
-> String
-> Int
-> [CiteField]
-> String
-> Citation
cInBookAC People
auth String
t Int
chap String
pub Int
yr [CiteField]
opt = CitationKind -> [CiteField] -> String -> Citation
cite CitationKind
InBook
  (People -> CiteField
author People
auth CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: Int -> CiteField
chapter Int
chap CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> String -> Int -> [CiteField] -> [CiteField]
stdFields String
t String
pub Int
yr [CiteField]
opt)
-- | Otherwise identical to 'cInBookECP'.
cInBookEC :: People
-> String
-> Int
-> String
-> Int
-> [CiteField]
-> String
-> Citation
cInBookEC People
ed String
t Int
chap String
pub Int
yr [CiteField]
opt = CitationKind -> [CiteField] -> String -> Citation
cite CitationKind
InBook
  (People -> CiteField
editor People
ed CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: Int -> CiteField
chapter Int
chap CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> String -> Int -> [CiteField] -> [CiteField]
stdFields String
t String
pub Int
yr [CiteField]
opt)

-- | InBook citation excluding chapter.
cInBookAP, cInBookEP :: People -> String -> [Int] ->
  String -> Int -> [CiteField] -> String -> Citation

-- | Otherwise identical to 'cInBookACP'.
cInBookAP :: People
-> String
-> [Int]
-> String
-> Int
-> [CiteField]
-> String
-> Citation
cInBookAP People
auth String
t [Int]
pgs String
pub Int
yr [CiteField]
opt = CitationKind -> [CiteField] -> String -> Citation
cite CitationKind
InBook
  (People -> CiteField
author People
auth CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: [Int] -> CiteField
pages [Int]
pgs CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> String -> Int -> [CiteField] -> [CiteField]
stdFields String
t String
pub Int
yr [CiteField]
opt)
-- | Otherwise identical to 'cInBookECP'.
cInBookEP :: People
-> String
-> [Int]
-> String
-> Int
-> [CiteField]
-> String
-> Citation
cInBookEP People
ed String
t [Int]
pgs String
pub Int
yr [CiteField]
opt = CitationKind -> [CiteField] -> String -> Citation
cite CitationKind
InBook
  (People -> CiteField
editor People
ed CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: [Int] -> CiteField
pages [Int]
pgs CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> String -> Int -> [CiteField] -> [CiteField]
stdFields String
t String
pub Int
yr [CiteField]
opt)

-- | InCollection citation requires author, title, bookTitle, publisher, year.
-- Optional fields can be editor, volume or number, series, type, chapter,
-- pages, address, edition, month, and note.
-- Implicitly uses the EntryID as the chunk id.
cInCollection :: People -> String -> String -> String -> Int ->
  [CiteField] -> String -> Citation
cInCollection :: People
-> String
-> String
-> String
-> Int
-> [CiteField]
-> String
-> Citation
cInCollection People
auth String
t String
bt String
pub Int
yr [CiteField]
opt = CitationKind -> [CiteField] -> String -> Citation
cite CitationKind
InCollection
  (People -> CiteField
author People
auth CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> CiteField
bookTitle String
bt CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> String -> Int -> [CiteField] -> [CiteField]
stdFields String
t String
pub Int
yr [CiteField]
opt)

-- | InProceedings citation requires author, title, bookTitle, year.
-- Optional fields can be editor, volume or number, series, pages,
-- address, month, organization, publisher, and note.
-- Implicitly uses the EntryID as the chunk id.
cInProceedings :: People -> String -> String -> Int ->
  [CiteField] -> String -> Citation
cInProceedings :: People
-> String -> String -> Int -> [CiteField] -> String -> Citation
cInProceedings People
auth String
t String
bt Int
yr [CiteField]
opt = CitationKind -> [CiteField] -> String -> Citation
cite CitationKind
InProceedings
  (People -> CiteField
author People
auth CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> CiteField
title String
t CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> CiteField
bookTitle String
bt CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: Int -> CiteField
year Int
yr CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: [CiteField]
opt)

-- | Manual (technical documentation) citation requires title.
-- Optional fields can be author, organization, address, edition, month, year, and note.
-- Implicitly uses the EntryID as the chunk id.
cManual :: String -> [CiteField] -> String -> Citation
cManual :: String -> [CiteField] -> String -> Citation
cManual String
t [CiteField]
opt = CitationKind -> [CiteField] -> String -> Citation
cite CitationKind
Manual (String -> CiteField
title String
t CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: [CiteField]
opt)

-- | Master's Thesis citation requires author, title, school, and year.
-- Optional fields can be type, address, month, and note.
-- Implicitly uses the EntryID as the chunk id.
cMThesis :: People -> String -> String -> Int -> [CiteField] -> String -> Citation
cMThesis :: People
-> String -> String -> Int -> [CiteField] -> String -> Citation
cMThesis People
auth String
t String
sch Int
yr [CiteField]
opt = CitationKind -> [CiteField] -> String -> Citation
cite CitationKind
MThesis (People -> String -> String -> Int -> [CiteField] -> [CiteField]
thesis People
auth String
t String
sch Int
yr [CiteField]
opt)

-- | Misc citation requires nothing.
-- Optional fields can be author, title, howpublished, month, year, and note.
-- Implicitly uses the EntryID as the chunk id.
cMisc :: [CiteField] -> String -> Citation
cMisc :: [CiteField] -> String -> Citation
cMisc = CitationKind -> [CiteField] -> String -> Citation
cite CitationKind
Misc

-- | PhD Thesis citation requires author, title, school, and year.
-- Optional fields can be type, address, month, and note.
-- Implicitly uses the EntryID as the chunk id.
cPhDThesis :: People -> String -> String -> Int -> [CiteField] -> String -> Citation
cPhDThesis :: People
-> String -> String -> Int -> [CiteField] -> String -> Citation
cPhDThesis People
auth String
t String
sch Int
yr [CiteField]
opt = CitationKind -> [CiteField] -> String -> Citation
cite CitationKind
PhDThesis (People -> String -> String -> Int -> [CiteField] -> [CiteField]
thesis People
auth String
t String
sch Int
yr [CiteField]
opt)

-- | Proceedings citation requires title and year.
-- Optional fields can be editor, volume or number, series, address,
-- publisher, note, month, and organization.
-- Implicitly uses the EntryID as the chunk id.
cProceedings :: String -> Int -> [CiteField] -> String -> Citation
cProceedings :: String -> Int -> [CiteField] -> String -> Citation
cProceedings String
t Int
yr [CiteField]
opt = CitationKind -> [CiteField] -> String -> Citation
cite CitationKind
Proceedings (String -> CiteField
title String
t CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: Int -> CiteField
year Int
yr CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: [CiteField]
opt)

-- | Technical Report citation requires author, title, institution, and year.
-- Optional fields can be type, number, address, month, and note.
-- Implicitly uses the EntryID as the chunk id.
cTechReport :: People -> String -> String -> Int -> [CiteField] -> String -> Citation
cTechReport :: People
-> String -> String -> Int -> [CiteField] -> String -> Citation
cTechReport People
auth String
t String
inst Int
yr [CiteField]
opt = CitationKind -> [CiteField] -> String -> Citation
cite CitationKind
TechReport
  (People -> CiteField
author People
auth CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> CiteField
title String
t CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> CiteField
institution String
inst CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: Int -> CiteField
year Int
yr CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: [CiteField]
opt)

-- | Unpublished citation requires author, title, and note.
-- Optional fields can be month and year.
-- Implicitly uses the EntryID as the chunk id.
cUnpublished :: People -> String -> String -> [CiteField] -> String -> Citation
cUnpublished :: People -> String -> String -> [CiteField] -> String -> Citation
cUnpublished People
auth String
t String
n [CiteField]
opt = CitationKind -> [CiteField] -> String -> Citation
cite CitationKind
Unpublished
  (People -> CiteField
author People
auth CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> CiteField
title String
t CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> CiteField
note String
n CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: [CiteField]
opt)

-- | Helper function (do not export) for creating book reference.
stdFields :: String -> String -> Int -> [CiteField] -> [CiteField]
stdFields :: String -> String -> Int -> [CiteField] -> [CiteField]
stdFields String
t String
pub Int
yr [CiteField]
opt = String -> CiteField
title String
t CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> CiteField
publisher String
pub CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: Int -> CiteField
year Int
yr CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: [CiteField]
opt

-- | Helper function (do not export) for creating thesis reference.
thesis :: People -> String -> String -> Int -> [CiteField] -> [CiteField]
thesis :: People -> String -> String -> Int -> [CiteField] -> [CiteField]
thesis People
auth String
t String
sch Int
yr [CiteField]
opt = People -> CiteField
author People
auth CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> CiteField
title String
t CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: String -> CiteField
school String
sch CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: Int -> CiteField
year Int
yr CiteField -> [CiteField] -> [CiteField]
forall a. a -> [a] -> [a]
: [CiteField]
opt