{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE CPP                #-}
{-# LANGUAGE DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Text.CSL.Data
-- Copyright   :  (c) John MacFarlane
-- License     :  BSD-style (see LICENSE)
--
-- Maintainer  :  John MacFarlane <fiddlosopher@gmail.com>
-- Stability   :  unstable
-- Portability :  unportable
--
-----------------------------------------------------------------------------

module Text.CSL.Data
    ( getLocale
    , CSLLocaleException(..)
    , getDefaultCSL
    , getManPage
    , getLicense
    , langBase
    ) where

import Prelude
import qualified Control.Exception      as E
import qualified Data.ByteString.Lazy   as L
import           Data.Typeable
import           System.FilePath        ()
import           Data.Maybe             (fromMaybe)
#ifdef EMBED_DATA_FILES
import           Text.CSL.Data.Embedded (defaultCSL, license, localeFiles,
                                         manpage)
#else
import           Paths_pandoc_citeproc  (getDataFileName)
import           System.Directory       (doesFileExist)
#endif

data CSLLocaleException =
    CSLLocaleNotFound String
  | CSLLocaleReadError E.IOException
  deriving Typeable
instance Show CSLLocaleException where
  show :: CSLLocaleException -> String
show (CSLLocaleNotFound s :: String
s)  = "Could not find locale data for " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
s
  show (CSLLocaleReadError e :: IOException
e) = IOException -> String
forall a. Show a => a -> String
show IOException
e
instance E.Exception CSLLocaleException

-- | Raises 'CSLLocaleException' on error.
getLocale :: String -> IO L.ByteString
getLocale :: String -> IO ByteString
getLocale s :: String
s = do
  let baseLocale :: String
baseLocale = (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/='.') String
s
#ifdef EMBED_DATA_FILES
  let toLazy x = L.fromChunks [x]
  let returnDefaultLocale =
        maybe (E.throwIO $ CSLLocaleNotFound "en-US") (return . toLazy)
           $ lookup "locales-en-US.xml" localeFiles
  case length baseLocale of
      0 -> returnDefaultLocale
      1 | baseLocale == "C" -> returnDefaultLocale
      _ -> case lookup ("locales-" ++ baseLocale ++ ".xml") localeFiles of
                 Just x' -> return $ toLazy x'
                 Nothing ->
                       -- try again with 2-letter locale (lang only)
                       let shortLocale = takeWhile (/='-') baseLocale in
                       case lookup ("locales-" ++ fromMaybe shortLocale
                              (lookup shortLocale langBase) ++ ".xml")
                              localeFiles of
                             Just x'' -> return $ toLazy x''
                             _        -> E.throwIO $ CSLLocaleNotFound s
#else
  String
f <- String -> IO String
getDataFileName (String -> IO String) -> String -> IO String
forall a b. (a -> b) -> a -> b
$
         case String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
baseLocale of
             0 -> "locales/locales-en-US.xml"
             1 | String
baseLocale String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== "C" -> "locales/locales-en-US.xml"
             2 -> "locales/locales-" String -> ShowS
forall a. [a] -> [a] -> [a]
++
                    String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe String
s (String -> [(String, String)] -> Maybe String
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup String
s [(String, String)]
langBase) String -> ShowS
forall a. [a] -> [a] -> [a]
++ ".xml"
             _ -> "locales/locales-" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> ShowS
forall a. Int -> [a] -> [a]
take 5 String
s String -> ShowS
forall a. [a] -> [a] -> [a]
++ ".xml"
  Bool
exists <- String -> IO Bool
doesFileExist String
f
  if Bool -> Bool
not Bool
exists Bool -> Bool -> Bool
&& String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
baseLocale Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> 2
     then String -> IO ByteString
getLocale (String -> IO ByteString) -> String -> IO ByteString
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/='-') String
baseLocale
          -- try again with lang only
     else (IOException -> IO ByteString) -> IO ByteString -> IO ByteString
forall e a. Exception e => (e -> IO a) -> IO a -> IO a
E.handle (CSLLocaleException -> IO ByteString
forall e a. Exception e => e -> IO a
E.throwIO (CSLLocaleException -> IO ByteString)
-> (IOException -> CSLLocaleException)
-> IOException
-> IO ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IOException -> CSLLocaleException
CSLLocaleReadError) (IO ByteString -> IO ByteString) -> IO ByteString -> IO ByteString
forall a b. (a -> b) -> a -> b
$ String -> IO ByteString
L.readFile String
f
#endif

getDefaultCSL :: IO L.ByteString
getDefaultCSL :: IO ByteString
getDefaultCSL =
#ifdef EMBED_DATA_FILES
  return $ L.fromChunks [defaultCSL]
#else
  String -> IO String
getDataFileName "chicago-author-date.csl" IO String -> (String -> IO ByteString) -> IO ByteString
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> IO ByteString
L.readFile
#endif

getManPage :: IO L.ByteString
getManPage :: IO ByteString
getManPage =
#ifdef EMBED_DATA_FILES
  return $ L.fromChunks [manpage]
#else
  String -> IO String
getDataFileName "man/man1/pandoc-citeproc.1" IO String -> (String -> IO ByteString) -> IO ByteString
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> IO ByteString
L.readFile
#endif

getLicense :: IO L.ByteString
getLicense :: IO ByteString
getLicense =
#ifdef EMBED_DATA_FILES
  return $ L.fromChunks [license]
#else
  String -> IO String
getDataFileName "LICENSE" IO String -> (String -> IO ByteString) -> IO ByteString
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> IO ByteString
L.readFile
#endif

langBase :: [(String, String)]
langBase :: [(String, String)]
langBase
    = [("af", "af-ZA")
      ,("bg", "bg-BG")
      ,("ca", "ca-AD")
      ,("cs", "cs-CZ")
      ,("da", "da-DK")
      ,("de", "de-DE")
      ,("el", "el-GR")
      ,("en", "en-US")
      ,("es", "es-ES")
      ,("et", "et-EE")
      ,("fa", "fa-IR")
      ,("fi", "fi-FI")
      ,("fr", "fr-FR")
      ,("he", "he-IL")
      ,("hr", "hr-HR")
      ,("hu", "hu-HU")
      ,("is", "is-IS")
      ,("it", "it-IT")
      ,("ja", "ja-JP")
      ,("km", "km-KH")
      ,("ko", "ko-KR")
      ,("lt", "lt-LT")
      ,("lv", "lv-LV")
      ,("mn", "mn-MN")
      ,("nb", "nb-NO")
      ,("nl", "nl-NL")
      ,("nn", "nn-NO")
      ,("pl", "pl-PL")
      ,("pt", "pt-PT")
      ,("ro", "ro-RO")
      ,("ru", "ru-RU")
      ,("sk", "sk-SK")
      ,("sl", "sl-SI")
      ,("sr", "sr-RS")
      ,("sv", "sv-SE")
      ,("th", "th-TH")
      ,("tr", "tr-TR")
      ,("uk", "uk-UA")
      ,("vi", "vi-VN")
      ,("zh", "zh-CN")
      ]