module Text.CSL.Reference where
import Data.Char ( isUpper, toLower )
import Data.List ( elemIndex, isPrefixOf )
import Data.Maybe ( fromJust )
import Data.Generics
data Value = forall a . Data a => Value a
instance Show Value where
show (Value a) = gshow a
type ReferenceMap = [(String, Value)]
mkRefMap :: Data a => a -> ReferenceMap
mkRefMap a = zip fields (gmapQ Value a)
where fields = map formatField . constrFields . toConstr $ a
formatField :: String -> String
formatField = foldr f [] . g
where f x xs = if isUpper x then '-' : toLower x : xs else x : xs
g (x:xs) = toLower x : xs
g [] = []
fromValue :: Data a => Value -> Maybe a
fromValue (Value a) = cast a
isValueSet :: Value -> Bool
isValueSet val
| Just v <- fromValue val :: Maybe String = v /= []
| Just v <- fromValue val :: Maybe [Agent] = v /= []
| Just v <- fromValue val :: Maybe [RefDate] = v /= []
| Just v <- fromValue val :: Maybe Int = v /= 0
| Just v <- fromValue val :: Maybe CNum = v /= 0
| Just v <- fromValue val :: Maybe Locator = v /= NoneLoc
| otherwise = False
data Empty = Empty deriving ( Typeable, Data )
data Agent
= Entity String
| Person { namePrefix :: String
, givenName :: [String]
, initials :: String
, articular :: String
, familyName :: String
, nameSuffix :: String
} deriving ( Show, Read, Eq, Typeable, Data )
data RefDate =
RefDate { year :: Int
, month :: Int
, day :: Int
, other :: String
} deriving ( Show, Read, Eq, Typeable, Data )
data RefType
= NoType
| Article
| ArticleMagazine
| ArticleNewspaper
| ArticleJournal
| Bill
| Book
| Broadcast
| Chapter
| Entry
| EntryDictionary
| EntryEncyclopedia
| Figure
| Graphic
| Interview
| Legislation
| LegalCase
| Manuscript
| Map
| MotionPicture
| MusicalScore
| Pamphlet
| PaperConference
| Patent
| Post
| PostWeblog
| PersonalCommunication
| Report
| Review
| ReviewBook
| Song
| Speech
| Thesis
| Treaty
| Webpage
deriving ( Read, Eq, Typeable, Data )
instance Show RefType where
show = map toLower . formatField . showConstr . toConstr
newtype CNum = CNum { unCNum :: Int } deriving ( Show, Read, Eq, Num, Typeable, Data )
data Reference =
Reference
{ citeKey :: String
, refType :: RefType
, author :: [Agent]
, editor :: [Agent]
, translator :: [Agent]
, recipient :: [Agent]
, interviewer :: [Agent]
, publisher :: [Agent]
, composer :: [Agent]
, originalPublisher :: [Agent]
, originalAuthor :: [Agent]
, containerAuthor :: [Agent]
, collectionEditor :: [Agent]
, issued :: [RefDate]
, eventDate :: [RefDate]
, accessed :: [RefDate]
, container :: [RefDate]
, originalDate :: [RefDate]
, title :: String
, containerTitle :: String
, collectionTitle :: String
, collectionNumber :: Int
, originalTitle :: String
, publisherPlace :: String
, archive :: String
, archivePlace :: String
, archiveLocation :: String
, event :: String
, eventPlace :: String
, page :: String
, locator :: Locator
, version :: String
, volume :: String
, numberOfVolumes :: Int
, issue :: String
, chapterNumber :: String
, medium :: String
, status :: String
, edition :: String
, section :: String
, genre :: String
, note :: String
, annote :: String
, abstract :: String
, keyword :: String
, number :: String
, references :: String
, url :: String
, doi :: String
, isbn :: String
, citationNumber :: CNum
, yearSuffix :: String
, citationLabel :: String
} deriving ( Eq, Show, Read, Typeable, Data )
emptyReference :: Reference
emptyReference =
Reference
{ citeKey = []
, refType = NoType
, author = []
, editor = []
, translator = []
, recipient = []
, interviewer = []
, publisher = []
, composer = []
, originalPublisher = []
, originalAuthor = []
, containerAuthor = []
, collectionEditor = []
, issued = []
, eventDate = []
, accessed = []
, container = []
, originalDate = []
, title = []
, containerTitle = []
, collectionTitle = []
, collectionNumber = 0
, originalTitle = []
, publisherPlace = []
, archive = []
, archivePlace = []
, archiveLocation = []
, event = []
, eventPlace = []
, page = []
, locator = NoneLoc
, version = []
, volume = []
, numberOfVolumes = 0
, issue = []
, chapterNumber = []
, medium = []
, status = []
, edition = []
, section = []
, genre = []
, note = []
, annote = []
, abstract = []
, keyword = []
, number = []
, references = []
, url = []
, doi = []
, isbn = []
, citationNumber = CNum 0
, yearSuffix = []
, citationLabel = []
}
getReference :: [Reference] -> (String,String) -> Reference
getReference r
= snd . getReference' r . flip (,) ("",0)
getReference' :: [Reference] -> ((String,String),(String,Int)) -> (String, Reference)
getReference' r ((c,l),(p,n))
= case c `elemIndex` map citeKey r of
Just i -> (,) p $ (r !! i)
{ locator = parseLocator l
, citationNumber = CNum n }
Nothing -> (,) p $ emptyReference
{ title = c ++ " not found!"
, citationNumber = CNum n }
data Locator
= NoneLoc
| BookLoc String
| ChapterLoc String
| ColumnLoc String
| FigureLoc String
| FolioLoc String
| IssueLoc String
| LineLoc String
| NoteLoc String
| OpusLoc String
| PageLoc String
| PageFstLoc String
| ParaLoc String
| PartLoc String
| SecLoc String
| SubVerbLoc String
| VolLoc String
| VerseLoc String
deriving ( Read, Eq, Typeable, Data )
instance Show Locator where
show = map toLower . reverse . drop 3 . reverse . showConstr . toConstr
locString :: Locator -> String
locString l
| BookLoc s <- l = s
| ChapterLoc s <- l = s
| ColumnLoc s <- l = s
| FigureLoc s <- l = s
| FolioLoc s <- l = s
| IssueLoc s <- l = s
| LineLoc s <- l = s
| NoteLoc s <- l = s
| OpusLoc s <- l = s
| PageLoc s <- l = s
| PageFstLoc s <- l = s
| ParaLoc s <- l = s
| PartLoc s <- l = s
| SecLoc s <- l = s
| SubVerbLoc s <- l = s
| VolLoc s <- l = s
| VerseLoc s <- l = s
| otherwise = []
parseLocator :: String -> Locator
parseLocator s
| "b" `isPrefixOf` formatField s = mk BookLoc
| "ch" `isPrefixOf` formatField s = mk ChapterLoc
| "co" `isPrefixOf` formatField s = mk ColumnLoc
| "fi" `isPrefixOf` formatField s = mk FigureLoc
| "fo" `isPrefixOf` formatField s = mk FolioLoc
| "i" `isPrefixOf` formatField s = mk IssueLoc
| "l" `isPrefixOf` formatField s = mk LineLoc
| "n" `isPrefixOf` formatField s = mk NoteLoc
| "o" `isPrefixOf` formatField s = mk OpusLoc
| "para" `isPrefixOf` formatField s = mk ParaLoc
| "part" `isPrefixOf` formatField s = mk PartLoc
| "p" `isPrefixOf` formatField s = mk PageLoc
| "sec" `isPrefixOf` formatField s = mk SecLoc
| "sub" `isPrefixOf` formatField s = mk SubVerbLoc
| "ve" `isPrefixOf` formatField s = mk VerseLoc
| "v" `isPrefixOf` formatField s = mk VolLoc
| otherwise = NoneLoc
where
mk c = if null s then NoneLoc else c . concat . tail . words $ s
generatePosition :: [[(String,String)]] -> [[((String,String),(String,Int))]]
generatePosition = getPos ([],[])
getPos :: (Eq a) => ([a], [a])
-> [[(a, String)]] -> [[((a, String), (String, Int))]]
getPos _ [] = []
getPos (ac,cl) (x:xs)
= doGroup : getPos (ac ++ (map fst x), cl ++ fstcits) xs
where
fstcits = map (fst . fst) . filter ((==) "first" . fst . snd) $ doGroup
doGroup = doGet (ac,cl) x
doGet _ [] = []
doGet (a,c) ((k,l):ys)
| isIbid
, isSet = ((k, l), ("ibid-with-locator", citNum)) : doGet (a ++ [k], c ) ys
| isIbid = ((k, l), ("ibid" , citNum)) : doGet (a ++ [k], c ) ys
| isElem = ((k, l), ("subsequent" , citNum)) : doGet (a ++ [k], c ) ys
| otherwise = ((k, l), ("first" , newCit)) : doGet (a ++ [k], c ++ [k]) ys
where
newCit = 1 + length c
citNum = (+) 1 . fromJust . elemIndex k $ c
isSet = l /= ""
isElem = k `elem` a
isIbid = isElem && k == last a