{-# LANGUAGE FlexibleInstances #-}

module Argo.Class.FromValue where

import qualified Argo.Type.Array as Array
import qualified Argo.Type.Boolean as Boolean
import qualified Argo.Type.Number as Number
import qualified Argo.Type.Object as Object
import qualified Argo.Type.Pair as Pair
import qualified Argo.Type.String as String
import qualified Argo.Type.Value as Value
import qualified Data.Array
import qualified Data.Text as Text

class FromValue a where
    fromValue :: Value.Value -> Maybe a

instance FromValue Value.Value where
    fromValue :: Value -> Maybe Value
fromValue = Value -> Maybe Value
forall a. a -> Maybe a
Just

instance FromValue Bool where
    fromValue :: Value -> Maybe Bool
fromValue = String -> (Bool -> Maybe Bool) -> Value -> Maybe Bool
forall a. String -> (Bool -> Maybe a) -> Value -> Maybe a
withBoolean String
"Bool" Bool -> Maybe Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure

instance FromValue Integer where
    fromValue :: Value -> Maybe Integer
fromValue = String
-> (Integer -> Integer -> Maybe Integer) -> Value -> Maybe Integer
forall a.
String -> (Integer -> Integer -> Maybe a) -> Value -> Maybe a
withNumber String
"Integer" ((Integer -> Integer -> Maybe Integer) -> Value -> Maybe Integer)
-> (Integer -> Integer -> Maybe Integer) -> Value -> Maybe Integer
forall a b. (a -> b) -> a -> b
$ \ Integer
x Integer
y ->
        if Integer
y Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
0 then String -> Maybe Integer
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"fractional" else Integer -> Maybe Integer
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Integer -> Maybe Integer) -> Integer -> Maybe Integer
forall a b. (a -> b) -> a -> b
$ Integer
x Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
10 Integer -> Integer -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ Integer
y

instance FromValue Text.Text where
    fromValue :: Value -> Maybe Text
fromValue = String -> (Text -> Maybe Text) -> Value -> Maybe Text
forall a. String -> (Text -> Maybe a) -> Value -> Maybe a
withString String
"Text" Text -> Maybe Text
forall (f :: * -> *) a. Applicative f => a -> f a
pure

instance FromValue a => FromValue (Data.Array.Array Int a) where
    fromValue :: Value -> Maybe (Array Int a)
fromValue = String
-> (Array Int Value -> Maybe (Array Int a))
-> Value
-> Maybe (Array Int a)
forall a.
String -> (Array Int Value -> Maybe a) -> Value -> Maybe a
withArray String
"Array" ((Array Int Value -> Maybe (Array Int a))
 -> Value -> Maybe (Array Int a))
-> (Array Int Value -> Maybe (Array Int a))
-> Value
-> Maybe (Array Int a)
forall a b. (a -> b) -> a -> b
$ (Value -> Maybe a) -> Array Int Value -> Maybe (Array Int a)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Value -> Maybe a
forall a. FromValue a => Value -> Maybe a
fromValue

instance FromValue a => FromValue (Data.Array.Array Int (Pair.Pair String.String a)) where
    fromValue :: Value -> Maybe (Array Int (Pair String a))
fromValue = String
-> (Array Int (Pair String Value)
    -> Maybe (Array Int (Pair String a)))
-> Value
-> Maybe (Array Int (Pair String a))
forall a.
String
-> (Array Int (Pair String Value) -> Maybe a) -> Value -> Maybe a
withObject String
"Object" ((Array Int (Pair String Value)
  -> Maybe (Array Int (Pair String a)))
 -> Value -> Maybe (Array Int (Pair String a)))
-> (Array Int (Pair String Value)
    -> Maybe (Array Int (Pair String a)))
-> Value
-> Maybe (Array Int (Pair String a))
forall a b. (a -> b) -> a -> b
$ (Pair String Value -> Maybe (Pair String a))
-> Array Int (Pair String Value)
-> Maybe (Array Int (Pair String a))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse ((Pair String Value -> Maybe (Pair String a))
 -> Array Int (Pair String Value)
 -> Maybe (Array Int (Pair String a)))
-> (Pair String Value -> Maybe (Pair String a))
-> Array Int (Pair String Value)
-> Maybe (Array Int (Pair String a))
forall a b. (a -> b) -> a -> b
$ \ (Pair.Pair (String
k, Value
v)) -> (String, a) -> Pair String a
forall k v. (k, v) -> Pair k v
Pair.Pair ((String, a) -> Pair String a)
-> (a -> (String, a)) -> a -> Pair String a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (,) String
k (a -> Pair String a) -> Maybe a -> Maybe (Pair String a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Maybe a
forall a. FromValue a => Value -> Maybe a
fromValue Value
v

withBoolean :: String -> (Bool -> Maybe a) -> Value.Value -> Maybe a
withBoolean :: String -> (Bool -> Maybe a) -> Value -> Maybe a
withBoolean String
s Bool -> Maybe a
f Value
x = case Value
x of
    Value.Boolean (Boolean.Boolean Bool
y) -> Bool -> Maybe a
f Bool
y
    Value
_ -> String -> Maybe a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
s

withNumber :: String -> (Integer -> Integer -> Maybe a) -> Value.Value -> Maybe a
withNumber :: String -> (Integer -> Integer -> Maybe a) -> Value -> Maybe a
withNumber String
s Integer -> Integer -> Maybe a
f Value
x = case Value
x of
    Value.Number (Number.Number Integer
y Integer
z) -> Integer -> Integer -> Maybe a
f Integer
y Integer
z
    Value
_ -> String -> Maybe a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
s

withString :: String -> (Text.Text -> Maybe a) -> Value.Value -> Maybe a
withString :: String -> (Text -> Maybe a) -> Value -> Maybe a
withString String
s Text -> Maybe a
f Value
x = case Value
x of
    Value.String (String.String Text
y) -> Text -> Maybe a
f Text
y
    Value
_ -> String -> Maybe a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
s

withArray :: String -> (Data.Array.Array Int Value.Value -> Maybe a) -> Value.Value -> Maybe a
withArray :: String -> (Array Int Value -> Maybe a) -> Value -> Maybe a
withArray String
s Array Int Value -> Maybe a
f Value
x = case Value
x of
    Value.Array (Array.Array Array Int Value
y) -> Array Int Value -> Maybe a
f Array Int Value
y
    Value
_ -> String -> Maybe a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
s

withObject :: String -> (Data.Array.Array Int (Pair.Pair String.String Value.Value) -> Maybe a) -> Value.Value -> Maybe a
withObject :: String
-> (Array Int (Pair String Value) -> Maybe a) -> Value -> Maybe a
withObject String
s Array Int (Pair String Value) -> Maybe a
f Value
x = case Value
x of
    Value.Object (Object.Object Array Int (Pair String Value)
y) -> Array Int (Pair String Value) -> Maybe a
f Array Int (Pair String Value)
y
    Value
_ -> String -> Maybe a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
s