{-| Metadata functions.

-}
module Shikensu.Metadata
    ( transposeMetadata
    , transposeToMetadata
    ) where

import Flow
import Shikensu.Internal.Types

import qualified Data.Aeson as Aeson (FromJSON, Result(..), ToJSON, fromJSON, toJSON)
import qualified Data.HashMap.Strict as HashMap (empty)


{-| Transpose metadata.

Transpose our metadata object to a given type
which implements the Aeson.FromJSON instance.

> data Example =
>     Example { some :: Text }
>     deriving (Generic, FromJSON)
>
> hashMap     = HashMap.fromList [ ("some", "metadata") ]
> defaultEx   = Example { some = "default" }
> example     = transposeMetadata hashMap defaultEx :: Example

-}
transposeMetadata :: Aeson.FromJSON a => Metadata -> a -> a
transposeMetadata hashMap fallback =
    let
        result = hashMap
            |> Aeson.toJSON
            |> Aeson.fromJSON :: Aeson.FromJSON b => Aeson.Result b
    in
        case result of
            Aeson.Success x -> x
            Aeson.Error _   -> fallback


{-| Inverse of `transposeMetadata`.
-}
transposeToMetadata :: (Aeson.ToJSON a) => a -> Metadata
transposeToMetadata generic =
    let
        result = generic
            |> Aeson.toJSON
            |> Aeson.fromJSON :: Aeson.FromJSON b => Aeson.Result b
    in
        case result of
            Aeson.Success x -> x
            Aeson.Error _   -> HashMap.empty