module Test.Marionette.Frame where

import Data.Aeson.Types
import Data.Hashable (Hashable)
import GHC.Generics (Generic)
import Test.Marionette.Element (Element (..))
import Prelude

data Frame
    = FrameIndex Int
    | FrameElement Element
    | TopFrame
    deriving stock ((forall x. Frame -> Rep Frame x)
-> (forall x. Rep Frame x -> Frame) -> Generic Frame
forall x. Rep Frame x -> Frame
forall x. Frame -> Rep Frame x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Frame -> Rep Frame x
from :: forall x. Frame -> Rep Frame x
$cto :: forall x. Rep Frame x -> Frame
to :: forall x. Rep Frame x -> Frame
Generic, Frame -> Frame -> Bool
(Frame -> Frame -> Bool) -> (Frame -> Frame -> Bool) -> Eq Frame
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Frame -> Frame -> Bool
== :: Frame -> Frame -> Bool
$c/= :: Frame -> Frame -> Bool
/= :: Frame -> Frame -> Bool
Eq, Int -> Frame -> ShowS
[Frame] -> ShowS
Frame -> String
(Int -> Frame -> ShowS)
-> (Frame -> String) -> ([Frame] -> ShowS) -> Show Frame
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Frame -> ShowS
showsPrec :: Int -> Frame -> ShowS
$cshow :: Frame -> String
show :: Frame -> String
$cshowList :: [Frame] -> ShowS
showList :: [Frame] -> ShowS
Show)
    deriving anyclass (Eq Frame
Eq Frame =>
(Int -> Frame -> Int) -> (Frame -> Int) -> Hashable Frame
Int -> Frame -> Int
Frame -> Int
forall a. Eq a => (Int -> a -> Int) -> (a -> Int) -> Hashable a
$chashWithSalt :: Int -> Frame -> Int
hashWithSalt :: Int -> Frame -> Int
$chash :: Frame -> Int
hash :: Frame -> Int
Hashable)

instance FromJSON Frame where
    parseJSON :: Value -> Parser Frame
parseJSON = String -> (Object -> Parser Frame) -> Value -> Parser Frame
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"Frame" \Object
o ->
        (Maybe Int -> Maybe Text -> (Maybe Int, Maybe Text))
-> Parser (Maybe Int)
-> Parser (Maybe Text)
-> Parser (Maybe Int, Maybe Text)
forall a b c. (a -> b -> c) -> Parser a -> Parser b -> Parser c
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 (,) (Object
o Object -> Key -> Parser (Maybe Int)
forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"id") (Object
o Object -> Key -> Parser (Maybe Text)
forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"element") Parser (Maybe Int, Maybe Text)
-> ((Maybe Int, Maybe Text) -> Parser Frame) -> Parser Frame
forall a b. Parser a -> (a -> Parser b) -> Parser b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
            (Just Int
_, Just Text
_) -> String -> Parser Frame
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"conflicting frame identifiers"
            (Just Int
index, Maybe Text
Nothing) -> Frame -> Parser Frame
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Frame -> Parser Frame) -> (Int -> Frame) -> Int -> Parser Frame
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Frame
FrameIndex (Int -> Parser Frame) -> Int -> Parser Frame
forall a b. (a -> b) -> a -> b
$ Int
index
            (Maybe Int
Nothing, Just Text
elementId) -> Frame -> Parser Frame
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Frame -> Parser Frame) -> (Text -> Frame) -> Text -> Parser Frame
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Element -> Frame
FrameElement (Element -> Frame) -> (Text -> Element) -> Text -> Frame
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Element
Element (Text -> Parser Frame) -> Text -> Parser Frame
forall a b. (a -> b) -> a -> b
$ Text
elementId
            (Maybe Int
Nothing, Maybe Text
Nothing) -> Frame -> Parser Frame
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Frame
TopFrame

instance ToJSON Frame where
    toJSON :: Frame -> Value
toJSON (FrameIndex Int
index) = [Pair] -> Value
object [Key
"id" Key -> Int -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Int
index]
    toJSON (FrameElement Element{Text
elementId :: Text
elementId :: Element -> Text
..}) = [Pair] -> Value
object [Key
"element" Key -> Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Text
elementId]
    toJSON Frame
TopFrame = [Pair] -> Value
object [Key
"id" Key -> Value -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Value
Null]