{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}

-- | Default and active values for options
--   They can be defined and / or overridden separately from the
--   option definition themselves
module Data.Registry.Options.DefaultValues where

import Data.Dynamic
import Data.Registry
import Protolude

-- | Contain an optional value to return when an option is missing
newtype DefaultValue (s :: Symbol) a = DefaultValue (Maybe Dynamic)

-- | Contain an optional value to return when an option is present
newtype ActiveValue (s :: Symbol) a = ActiveValue (Maybe Dynamic)

-- | Get the default value in DefaultValue if it exists and has the right type
getDefaultValue :: forall (a :: Type) s. (Typeable a, KnownSymbol s) => DefaultValue s a -> Maybe a
getDefaultValue :: forall a (s :: Symbol).
(Typeable a, KnownSymbol s) =>
DefaultValue s a -> Maybe a
getDefaultValue (DefaultValue Maybe Dynamic
Nothing) = Maybe a
forall a. Maybe a
Nothing
getDefaultValue (DefaultValue (Just Dynamic
v)) = Dynamic -> Maybe a
forall a. Typeable a => Dynamic -> Maybe a
fromDynamic Dynamic
v

-- | Get the active value in ActiveValue if it exists and has the right type
getActiveValue :: forall (a :: Type) s. (Typeable a, KnownSymbol s) => ActiveValue s a -> Maybe a
getActiveValue :: forall a (s :: Symbol).
(Typeable a, KnownSymbol s) =>
ActiveValue s a -> Maybe a
getActiveValue (ActiveValue Maybe Dynamic
Nothing) = Maybe a
forall a. Maybe a
Nothing
getActiveValue (ActiveValue (Just Dynamic
v)) = Dynamic -> Maybe a
forall a. Typeable a => Dynamic -> Maybe a
fromDynamic Dynamic
v

-- | Allow to specify that a given field name and type has no default value
noDefaultValue :: forall s (a :: Type). (KnownSymbol s, Typeable a) => Typed (DefaultValue s a)
noDefaultValue :: forall (s :: Symbol) a.
(KnownSymbol s, Typeable a) =>
Typed (DefaultValue s a)
noDefaultValue = forall a. Typeable a => a -> Typed a
fun @(DefaultValue s a) (Maybe Dynamic -> DefaultValue s a
forall (s :: Symbol) a. Maybe Dynamic -> DefaultValue s a
DefaultValue Maybe Dynamic
forall a. Maybe a
Nothing)

-- | Allow to specify that a given field name and type has no active value
noActiveValue :: forall s (a :: Type). (KnownSymbol s, Typeable a) => Typed (ActiveValue s a)
noActiveValue :: forall (s :: Symbol) a.
(KnownSymbol s, Typeable a) =>
Typed (ActiveValue s a)
noActiveValue = ActiveValue s a -> Typed (ActiveValue s a)
forall a. Typeable a => a -> Typed a
fun (Maybe Dynamic -> ActiveValue s a
forall (s :: Symbol) a. Maybe Dynamic -> ActiveValue s a
ActiveValue Maybe Dynamic
forall a. Maybe a
Nothing)

-- | Add a default value for a given field name and type
createDefaultValue :: forall s (a :: Type). (Typeable a, KnownSymbol s) => a -> DefaultValue s a
createDefaultValue :: forall (s :: Symbol) a.
(Typeable a, KnownSymbol s) =>
a -> DefaultValue s a
createDefaultValue = Maybe Dynamic -> DefaultValue s a
forall (s :: Symbol) a. Maybe Dynamic -> DefaultValue s a
DefaultValue (Maybe Dynamic -> DefaultValue s a)
-> (a -> Maybe Dynamic) -> a -> DefaultValue s a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dynamic -> Maybe Dynamic
forall a. a -> Maybe a
Just (Dynamic -> Maybe Dynamic) -> (a -> Dynamic) -> a -> Maybe Dynamic
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Dynamic
forall a. Typeable a => a -> Dynamic
toDyn

-- | Add a default value for a given field name and type
createActiveValue :: forall s (a :: Type). (Typeable a, KnownSymbol s) => a -> ActiveValue s a
createActiveValue :: forall (s :: Symbol) a.
(Typeable a, KnownSymbol s) =>
a -> ActiveValue s a
createActiveValue = Maybe Dynamic -> ActiveValue s a
forall (s :: Symbol) a. Maybe Dynamic -> ActiveValue s a
ActiveValue (Maybe Dynamic -> ActiveValue s a)
-> (a -> Maybe Dynamic) -> a -> ActiveValue s a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dynamic -> Maybe Dynamic
forall a. a -> Maybe a
Just (Dynamic -> Maybe Dynamic) -> (a -> Dynamic) -> a -> Maybe Dynamic
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Dynamic
forall a. Typeable a => a -> Dynamic
toDyn