module FFProbe.Data.Tags (TagList, TagValue (..), HasTags (..), lookupTag) where

import Data.Aeson
import Data.Scientific (floatingOrInteger)
import Data.Text (unpack)

type TagList = [(String, TagValue)]

data TagValue
    = StringTag String
    | IntTag Integer
    | FloatTag Float
    | -- | If the constructor is 'Other', the String is a JSON representation of the value
      Other String
    | Null
    deriving (Int -> TagValue -> ShowS
[TagValue] -> ShowS
TagValue -> String
(Int -> TagValue -> ShowS)
-> (TagValue -> String) -> ([TagValue] -> ShowS) -> Show TagValue
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TagValue -> ShowS
showsPrec :: Int -> TagValue -> ShowS
$cshow :: TagValue -> String
show :: TagValue -> String
$cshowList :: [TagValue] -> ShowS
showList :: [TagValue] -> ShowS
Show, TagValue -> TagValue -> Bool
(TagValue -> TagValue -> Bool)
-> (TagValue -> TagValue -> Bool) -> Eq TagValue
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: TagValue -> TagValue -> Bool
== :: TagValue -> TagValue -> Bool
$c/= :: TagValue -> TagValue -> Bool
/= :: TagValue -> TagValue -> Bool
Eq)

instance FromJSON TagValue where
    parseJSON :: Value -> Parser TagValue
parseJSON (String Text
v) = TagValue -> Parser TagValue
forall a. a -> Parser a
forall (m :: * -> *) a. Monad m => a -> m a
return (TagValue -> Parser TagValue) -> TagValue -> Parser TagValue
forall a b. (a -> b) -> a -> b
$ String -> TagValue
StringTag (String -> TagValue) -> String -> TagValue
forall a b. (a -> b) -> a -> b
$ Text -> String
unpack Text
v
    parseJSON (Number Scientific
v) = TagValue -> Parser TagValue
forall a. a -> Parser a
forall (m :: * -> *) a. Monad m => a -> m a
return (TagValue -> Parser TagValue) -> TagValue -> Parser TagValue
forall a b. (a -> b) -> a -> b
$ (Float -> TagValue)
-> (Integer -> TagValue) -> Either Float Integer -> TagValue
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Float -> TagValue
FloatTag Integer -> TagValue
IntTag (Scientific -> Either Float Integer
forall r i. (RealFloat r, Integral i) => Scientific -> Either r i
floatingOrInteger Scientific
v)
    parseJSON Value
Data.Aeson.Null = TagValue -> Parser TagValue
forall a. a -> Parser a
forall (m :: * -> *) a. Monad m => a -> m a
return TagValue
FFProbe.Data.Tags.Null
    parseJSON Value
x = TagValue -> Parser TagValue
forall a. a -> Parser a
forall (m :: * -> *) a. Monad m => a -> m a
return (TagValue -> Parser TagValue) -> TagValue -> Parser TagValue
forall a b. (a -> b) -> a -> b
$ String -> TagValue
Other (String -> TagValue) -> String -> TagValue
forall a b. (a -> b) -> a -> b
$ Value -> String
forall a. Show a => a -> String
show Value
x

class HasTags a where
    getTags :: a -> TagList

-- | Lookup a tag in a TagList, using a key
lookupTag :: (HasTags a) => String -> a -> Maybe TagValue
lookupTag :: forall a. HasTags a => String -> a -> Maybe TagValue
lookupTag String
key a
obj = String -> [(String, TagValue)] -> Maybe TagValue
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup String
key (a -> [(String, TagValue)]
forall a. HasTags a => a -> [(String, TagValue)]
getTags a
obj)