{-# OPTIONS_GHC -fno-warn-orphans #-}

module Crypto.Hash.Instances
  () where

import ClassyPrelude

import Crypto.Hash

import Database.Persist
import Database.Persist.Sql

import Data.ByteArray (convert)
import Data.ByteArray.Encoding

import qualified Data.ByteString.Char8 as CBS

import Web.PathPieces
import Web.HttpApiData
import Data.Aeson as Aeson

import Text.Read as Read


instance HashAlgorithm hash => PersistField (Digest hash) where
  toPersistValue = PersistByteString . convert
  fromPersistValue (PersistByteString bs) = maybe (Left "Could not convert Digest from ByteString") Right $ digestFromByteString bs
  fromPersistValue (PersistText t) = maybe (Left "Cours not convert Digest from String") Right $ readMay t
  fromPersistValue _ = Left "Digest values must be converted from PersistByteString or PersistText"

instance HashAlgorithm hash => PersistFieldSql (Digest hash) where
  sqlType _ = SqlBlob 

instance HashAlgorithm hash => Read (Digest hash) where
  readPrec = do
    str <- replicateM (2 * hashDigestSize (error "Value of type hash forced" :: hash)) Read.get
    bs <- either fail return . convertFromBase Base16 $ CBS.pack str
    maybe (fail "Could not convert digestFromByteString") return $ digestFromByteString (bs :: ByteString)

instance HashAlgorithm hash => PathPiece (Digest hash) where
  toPathPiece = showToPathPiece
  fromPathPiece = readFromPathPiece

instance HashAlgorithm hash => ToHttpApiData (Digest hash) where
  toUrlPiece = tshow

instance HashAlgorithm hash => FromHttpApiData (Digest hash) where
  parseUrlPiece = maybe (Left "Could not read Digest") Right . readMay

instance HashAlgorithm hash => ToJSON (Digest hash) where
  toJSON = Aeson.String . toUrlPiece

instance HashAlgorithm hash => FromJSON (Digest hash) where
  parseJSON = withText "Digest" $ either (fail . unpack) return . parseUrlPiece
