content: {-|
  Copyright   : Written by David Himmelstrup
  License     : Unlicense
  Maintainer  : lemmih@gmail.com
  Stability   : experimental
  Portability : POSIX
  -}
  module Reanimate.ColorSpace
    ( Nanometer
    , coneSensitivity
    , bigXYZCoordinates
    , lightXYZCoordinates
    , nmToColor
    ) where
  
  import qualified Data.ByteString.Lazy       as BS
  import           Data.Colour.CIE
  import           Data.Csv
  import           Data.Map                   (Map)
  import qualified Data.Map                   as Map
  import           Data.Maybe
  import qualified Data.Vector                as V
  import           Paths_reanimate
  import           System.IO.Unsafe
  
  -- | Wavelengths in nanometers.
  type Nanometer = Integer
  
  {-# NOINLINE lightXYZCoordinates #-}
  -- | (small) xyz values for each wavelength of light.
  lightXYZCoordinates :: Map Nanometer (Double, Double, Double)
  lightXYZCoordinates = unsafePerformIO $ do
    dat <- BS.readFile =<< getDataFileName "data/CIExyz.csv"
    case decode NoHeader dat of
      Left err -> error err
      Right vec -> return $ Map.fromList
        [ (nm, (x,y,z)) | (nm,x,y,z) <- V.toList vec, nm <= 700 ]
  
  {-# NOINLINE bigXYZCoordinates #-}
  -- | (big) XYZ values for each wavelength of light.
  bigXYZCoordinates :: Map Nanometer (Double, Double, Double)
  bigXYZCoordinates = unsafePerformIO $ do
    dat <- BS.readFile =<< getDataFileName "data/CIE_XYZ.csv"
    case decode NoHeader dat of
      Left err -> error err
      Right vec -> return $ Map.fromList
        [ (nm, (x,y,z)) | (nm,x,y,z) <- V.toList vec, nm <= 700 ]
  
  -- | Helper function for converting a wavelength of light into the
  --   perceived color.
  nmToColor :: Nanometer -> Maybe (Colour Double)
  nmToColor nm = do
    (x, y, z) <- Map.lookup nm bigXYZCoordinates
    return $ cieXYZ x y z
  
  {-# NOINLINE coneSensitivity #-}
  -- (Long, Medium, Short)
  -- | Cone sensitivity by light wavelength.
  coneSensitivity :: Map Nanometer (Double, Double, Double)
  coneSensitivity = unsafePerformIO $ do
    dat <- BS.readFile =<< getDataFileName "data/cone_sensitivity_lms.csv"
    case decode NoHeader dat of
      Left err -> error err
      Right vec -> return $ Map.fromList
        [ (nm, (l,m,fromMaybe 0 s)) | (nm,l,m,s) <- V.toList vec, nm <= 700 ]
  