module WebDriverPreCore.BiDi.Log
  ( -- * Log Level
    Level (..),

    -- * Log Entry Types
    BaseLogEntry (..),
    GenericLogEntry (..),
    ConsoleLogEntry (..),
    JavascriptLogEntry (..),
    LogEntry (..),
    LogEvent (..)
  )
where

import Data.Aeson (FromJSON, Value (..), withObject, (.:))
import Data.Aeson.Types (FromJSON (..), Parser)
import Data.Functor ((<&>))
import Data.Text (Text)
import GHC.Generics (Generic)
import WebDriverPreCore.BiDi.CoreTypes (JSUInt)
import WebDriverPreCore.BiDi.Script (RemoteValue, Source, StackTrace)
import AesonUtils (fromJSONCamelCase, parseJSONOmitNothing)

-- ######### Local #########
-- Note: log module does not have a remote end

-- | Represents the log level
data Level = Debug | Info | Warn | Error
  deriving (Int -> Level -> ShowS
[Level] -> ShowS
Level -> String
(Int -> Level -> ShowS)
-> (Level -> String) -> ([Level] -> ShowS) -> Show Level
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Level -> ShowS
showsPrec :: Int -> Level -> ShowS
$cshow :: Level -> String
show :: Level -> String
$cshowList :: [Level] -> ShowS
showList :: [Level] -> ShowS
Show, Level -> Level -> Bool
(Level -> Level -> Bool) -> (Level -> Level -> Bool) -> Eq Level
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Level -> Level -> Bool
== :: Level -> Level -> Bool
$c/= :: Level -> Level -> Bool
/= :: Level -> Level -> Bool
Eq, (forall x. Level -> Rep Level x)
-> (forall x. Rep Level x -> Level) -> Generic Level
forall x. Rep Level x -> Level
forall x. Level -> Rep Level x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Level -> Rep Level x
from :: forall x. Level -> Rep Level x
$cto :: forall x. Rep Level x -> Level
to :: forall x. Rep Level x -> Level
Generic)

instance FromJSON Level where
  parseJSON :: Value -> Parser Level
  parseJSON :: Value -> Parser Level
parseJSON = Value -> Parser Level
forall a. (Generic a, GFromJSON Zero (Rep a)) => Value -> Parser a
fromJSONCamelCase

-- | Base structure for all log entries
data BaseLogEntry = MkBaseLogEntry
  { BaseLogEntry -> Level
level :: Level,
    BaseLogEntry -> Source
source :: Source,
    BaseLogEntry -> Maybe Text
text :: Maybe Text,
    BaseLogEntry -> JSUInt
timestamp :: JSUInt,
    BaseLogEntry -> Maybe StackTrace
stackTrace :: Maybe StackTrace
  }
  deriving (Int -> BaseLogEntry -> ShowS
[BaseLogEntry] -> ShowS
BaseLogEntry -> String
(Int -> BaseLogEntry -> ShowS)
-> (BaseLogEntry -> String)
-> ([BaseLogEntry] -> ShowS)
-> Show BaseLogEntry
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> BaseLogEntry -> ShowS
showsPrec :: Int -> BaseLogEntry -> ShowS
$cshow :: BaseLogEntry -> String
show :: BaseLogEntry -> String
$cshowList :: [BaseLogEntry] -> ShowS
showList :: [BaseLogEntry] -> ShowS
Show, BaseLogEntry -> BaseLogEntry -> Bool
(BaseLogEntry -> BaseLogEntry -> Bool)
-> (BaseLogEntry -> BaseLogEntry -> Bool) -> Eq BaseLogEntry
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: BaseLogEntry -> BaseLogEntry -> Bool
== :: BaseLogEntry -> BaseLogEntry -> Bool
$c/= :: BaseLogEntry -> BaseLogEntry -> Bool
/= :: BaseLogEntry -> BaseLogEntry -> Bool
Eq, (forall x. BaseLogEntry -> Rep BaseLogEntry x)
-> (forall x. Rep BaseLogEntry x -> BaseLogEntry)
-> Generic BaseLogEntry
forall x. Rep BaseLogEntry x -> BaseLogEntry
forall x. BaseLogEntry -> Rep BaseLogEntry x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. BaseLogEntry -> Rep BaseLogEntry x
from :: forall x. BaseLogEntry -> Rep BaseLogEntry x
$cto :: forall x. Rep BaseLogEntry x -> BaseLogEntry
to :: forall x. Rep BaseLogEntry x -> BaseLogEntry
Generic)

instance FromJSON BaseLogEntry where
  parseJSON :: Value -> Parser BaseLogEntry
  parseJSON :: Value -> Parser BaseLogEntry
parseJSON = Value -> Parser BaseLogEntry
forall a. (Generic a, GFromJSON Zero (Rep a)) => Value -> Parser a
parseJSONOmitNothing

-- | Generic log entry type
data GenericLogEntry = MkGenericLogEntry
  { GenericLogEntry -> Level
level :: Level,
    GenericLogEntry -> Source
source :: Source,
    GenericLogEntry -> Maybe Text
text :: Maybe Text,
    GenericLogEntry -> JSUInt
timestamp :: JSUInt,
    GenericLogEntry -> Maybe StackTrace
stackTrace :: Maybe StackTrace,
    GenericLogEntry -> Text
entryType :: Text
  }
  deriving (Int -> GenericLogEntry -> ShowS
[GenericLogEntry] -> ShowS
GenericLogEntry -> String
(Int -> GenericLogEntry -> ShowS)
-> (GenericLogEntry -> String)
-> ([GenericLogEntry] -> ShowS)
-> Show GenericLogEntry
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> GenericLogEntry -> ShowS
showsPrec :: Int -> GenericLogEntry -> ShowS
$cshow :: GenericLogEntry -> String
show :: GenericLogEntry -> String
$cshowList :: [GenericLogEntry] -> ShowS
showList :: [GenericLogEntry] -> ShowS
Show, GenericLogEntry -> GenericLogEntry -> Bool
(GenericLogEntry -> GenericLogEntry -> Bool)
-> (GenericLogEntry -> GenericLogEntry -> Bool)
-> Eq GenericLogEntry
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: GenericLogEntry -> GenericLogEntry -> Bool
== :: GenericLogEntry -> GenericLogEntry -> Bool
$c/= :: GenericLogEntry -> GenericLogEntry -> Bool
/= :: GenericLogEntry -> GenericLogEntry -> Bool
Eq, (forall x. GenericLogEntry -> Rep GenericLogEntry x)
-> (forall x. Rep GenericLogEntry x -> GenericLogEntry)
-> Generic GenericLogEntry
forall x. Rep GenericLogEntry x -> GenericLogEntry
forall x. GenericLogEntry -> Rep GenericLogEntry x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. GenericLogEntry -> Rep GenericLogEntry x
from :: forall x. GenericLogEntry -> Rep GenericLogEntry x
$cto :: forall x. Rep GenericLogEntry x -> GenericLogEntry
to :: forall x. Rep GenericLogEntry x -> GenericLogEntry
Generic)

instance FromJSON GenericLogEntry where
  parseJSON :: Value -> Parser GenericLogEntry
  parseJSON :: Value -> Parser GenericLogEntry
parseJSON = Value -> Parser GenericLogEntry
forall a. (Generic a, GFromJSON Zero (Rep a)) => Value -> Parser a
parseJSONOmitNothing

-- | Console log entry type
data ConsoleLogEntry = MkConsoleLogEntry
  { ConsoleLogEntry -> Level
level :: Level,
    ConsoleLogEntry -> Source
source :: Source,
    ConsoleLogEntry -> Maybe Text
text :: Maybe Text,
    ConsoleLogEntry -> JSUInt
timestamp :: JSUInt,
    ConsoleLogEntry -> Maybe StackTrace
stackTrace :: Maybe StackTrace,
    ConsoleLogEntry -> Text
method :: Text,
    ConsoleLogEntry -> [RemoteValue]
args :: [RemoteValue]
  }
  deriving (Int -> ConsoleLogEntry -> ShowS
[ConsoleLogEntry] -> ShowS
ConsoleLogEntry -> String
(Int -> ConsoleLogEntry -> ShowS)
-> (ConsoleLogEntry -> String)
-> ([ConsoleLogEntry] -> ShowS)
-> Show ConsoleLogEntry
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ConsoleLogEntry -> ShowS
showsPrec :: Int -> ConsoleLogEntry -> ShowS
$cshow :: ConsoleLogEntry -> String
show :: ConsoleLogEntry -> String
$cshowList :: [ConsoleLogEntry] -> ShowS
showList :: [ConsoleLogEntry] -> ShowS
Show, ConsoleLogEntry -> ConsoleLogEntry -> Bool
(ConsoleLogEntry -> ConsoleLogEntry -> Bool)
-> (ConsoleLogEntry -> ConsoleLogEntry -> Bool)
-> Eq ConsoleLogEntry
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ConsoleLogEntry -> ConsoleLogEntry -> Bool
== :: ConsoleLogEntry -> ConsoleLogEntry -> Bool
$c/= :: ConsoleLogEntry -> ConsoleLogEntry -> Bool
/= :: ConsoleLogEntry -> ConsoleLogEntry -> Bool
Eq, (forall x. ConsoleLogEntry -> Rep ConsoleLogEntry x)
-> (forall x. Rep ConsoleLogEntry x -> ConsoleLogEntry)
-> Generic ConsoleLogEntry
forall x. Rep ConsoleLogEntry x -> ConsoleLogEntry
forall x. ConsoleLogEntry -> Rep ConsoleLogEntry x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. ConsoleLogEntry -> Rep ConsoleLogEntry x
from :: forall x. ConsoleLogEntry -> Rep ConsoleLogEntry x
$cto :: forall x. Rep ConsoleLogEntry x -> ConsoleLogEntry
to :: forall x. Rep ConsoleLogEntry x -> ConsoleLogEntry
Generic)

instance FromJSON ConsoleLogEntry where 
  parseJSON :: Value -> Parser ConsoleLogEntry
  parseJSON :: Value -> Parser ConsoleLogEntry
parseJSON = Value -> Parser ConsoleLogEntry
forall a. (Generic a, GFromJSON Zero (Rep a)) => Value -> Parser a
parseJSONOmitNothing

-- | JavaScript log entry type
data JavascriptLogEntry = MkJavascriptLogEntry
  { JavascriptLogEntry -> Level
level :: Level,
    JavascriptLogEntry -> Source
source :: Source,
    JavascriptLogEntry -> Maybe Text
text :: Maybe Text,
    JavascriptLogEntry -> JSUInt
timestamp :: JSUInt,
    JavascriptLogEntry -> Maybe StackTrace
stackTrace :: Maybe StackTrace
  }
  deriving (Int -> JavascriptLogEntry -> ShowS
[JavascriptLogEntry] -> ShowS
JavascriptLogEntry -> String
(Int -> JavascriptLogEntry -> ShowS)
-> (JavascriptLogEntry -> String)
-> ([JavascriptLogEntry] -> ShowS)
-> Show JavascriptLogEntry
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> JavascriptLogEntry -> ShowS
showsPrec :: Int -> JavascriptLogEntry -> ShowS
$cshow :: JavascriptLogEntry -> String
show :: JavascriptLogEntry -> String
$cshowList :: [JavascriptLogEntry] -> ShowS
showList :: [JavascriptLogEntry] -> ShowS
Show, JavascriptLogEntry -> JavascriptLogEntry -> Bool
(JavascriptLogEntry -> JavascriptLogEntry -> Bool)
-> (JavascriptLogEntry -> JavascriptLogEntry -> Bool)
-> Eq JavascriptLogEntry
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: JavascriptLogEntry -> JavascriptLogEntry -> Bool
== :: JavascriptLogEntry -> JavascriptLogEntry -> Bool
$c/= :: JavascriptLogEntry -> JavascriptLogEntry -> Bool
/= :: JavascriptLogEntry -> JavascriptLogEntry -> Bool
Eq, (forall x. JavascriptLogEntry -> Rep JavascriptLogEntry x)
-> (forall x. Rep JavascriptLogEntry x -> JavascriptLogEntry)
-> Generic JavascriptLogEntry
forall x. Rep JavascriptLogEntry x -> JavascriptLogEntry
forall x. JavascriptLogEntry -> Rep JavascriptLogEntry x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. JavascriptLogEntry -> Rep JavascriptLogEntry x
from :: forall x. JavascriptLogEntry -> Rep JavascriptLogEntry x
$cto :: forall x. Rep JavascriptLogEntry x -> JavascriptLogEntry
to :: forall x. Rep JavascriptLogEntry x -> JavascriptLogEntry
Generic)

instance FromJSON JavascriptLogEntry where
  parseJSON :: Value -> Parser JavascriptLogEntry
  parseJSON :: Value -> Parser JavascriptLogEntry
parseJSON = Value -> Parser JavascriptLogEntry
forall a. (Generic a, GFromJSON Zero (Rep a)) => Value -> Parser a
parseJSONOmitNothing

-- | Union type for all log entry types
data LogEntry
  = GenericEntry GenericLogEntry
  | ConsoleEntry ConsoleLogEntry
  | JavascriptEntry JavascriptLogEntry
  deriving (Int -> LogEntry -> ShowS
[LogEntry] -> ShowS
LogEntry -> String
(Int -> LogEntry -> ShowS)
-> (LogEntry -> String) -> ([LogEntry] -> ShowS) -> Show LogEntry
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> LogEntry -> ShowS
showsPrec :: Int -> LogEntry -> ShowS
$cshow :: LogEntry -> String
show :: LogEntry -> String
$cshowList :: [LogEntry] -> ShowS
showList :: [LogEntry] -> ShowS
Show, LogEntry -> LogEntry -> Bool
(LogEntry -> LogEntry -> Bool)
-> (LogEntry -> LogEntry -> Bool) -> Eq LogEntry
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: LogEntry -> LogEntry -> Bool
== :: LogEntry -> LogEntry -> Bool
$c/= :: LogEntry -> LogEntry -> Bool
/= :: LogEntry -> LogEntry -> Bool
Eq, (forall x. LogEntry -> Rep LogEntry x)
-> (forall x. Rep LogEntry x -> LogEntry) -> Generic LogEntry
forall x. Rep LogEntry x -> LogEntry
forall x. LogEntry -> Rep LogEntry x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. LogEntry -> Rep LogEntry x
from :: forall x. LogEntry -> Rep LogEntry x
$cto :: forall x. Rep LogEntry x -> LogEntry
to :: forall x. Rep LogEntry x -> LogEntry
Generic)

-- | Event wrapper for log entries (consistent with other event types)
newtype LogEvent = MkLogEvent LogEntry
  deriving (Int -> LogEvent -> ShowS
[LogEvent] -> ShowS
LogEvent -> String
(Int -> LogEvent -> ShowS)
-> (LogEvent -> String) -> ([LogEvent] -> ShowS) -> Show LogEvent
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> LogEvent -> ShowS
showsPrec :: Int -> LogEvent -> ShowS
$cshow :: LogEvent -> String
show :: LogEvent -> String
$cshowList :: [LogEvent] -> ShowS
showList :: [LogEvent] -> ShowS
Show, LogEvent -> LogEvent -> Bool
(LogEvent -> LogEvent -> Bool)
-> (LogEvent -> LogEvent -> Bool) -> Eq LogEvent
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: LogEvent -> LogEvent -> Bool
== :: LogEvent -> LogEvent -> Bool
$c/= :: LogEvent -> LogEvent -> Bool
/= :: LogEvent -> LogEvent -> Bool
Eq, (forall x. LogEvent -> Rep LogEvent x)
-> (forall x. Rep LogEvent x -> LogEvent) -> Generic LogEvent
forall x. Rep LogEvent x -> LogEvent
forall x. LogEvent -> Rep LogEvent x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. LogEvent -> Rep LogEvent x
from :: forall x. LogEvent -> Rep LogEvent x
$cto :: forall x. Rep LogEvent x -> LogEvent
to :: forall x. Rep LogEvent x -> LogEvent
Generic)

instance FromJSON LogEvent where
  parseJSON :: Value -> Parser LogEvent
  parseJSON :: Value -> Parser LogEvent
parseJSON = String -> (Object -> Parser LogEvent) -> Value -> Parser LogEvent
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"LogEvent" ((Object -> Parser LogEvent) -> Value -> Parser LogEvent)
-> (Object -> Parser LogEvent) -> Value -> Parser LogEvent
forall a b. (a -> b) -> a -> b
$ \Object
o -> do
    params <- Object
o Object -> Key -> Parser Object
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"params"
    entryType <- params .: "type"
    let parsedPrms :: forall a b. (FromJSON a) => (a -> b) -> Parser b
        parsedPrms = Parser a -> (a -> b) -> Parser b
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
(<&>) (Value -> Parser a
forall a. FromJSON a => Value -> Parser a
parseJSON (Object -> Value
Object Object
params))
    case entryType of
      String
"generic" -> (GenericLogEntry -> LogEvent) -> Parser LogEvent
forall a b. FromJSON a => (a -> b) -> Parser b
parsedPrms (LogEntry -> LogEvent
MkLogEvent (LogEntry -> LogEvent)
-> (GenericLogEntry -> LogEntry) -> GenericLogEntry -> LogEvent
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GenericLogEntry -> LogEntry
GenericEntry)
      String
"console" -> (ConsoleLogEntry -> LogEvent) -> Parser LogEvent
forall a b. FromJSON a => (a -> b) -> Parser b
parsedPrms (LogEntry -> LogEvent
MkLogEvent (LogEntry -> LogEvent)
-> (ConsoleLogEntry -> LogEntry) -> ConsoleLogEntry -> LogEvent
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ConsoleLogEntry -> LogEntry
ConsoleEntry)
      String
"javascript" -> (JavascriptLogEntry -> LogEvent) -> Parser LogEvent
forall a b. FromJSON a => (a -> b) -> Parser b
parsedPrms (LogEntry -> LogEvent
MkLogEvent (LogEntry -> LogEvent)
-> (JavascriptLogEntry -> LogEntry)
-> JavascriptLogEntry
-> LogEvent
forall b c a. (b -> c) -> (a -> b) -> a -> c
. JavascriptLogEntry -> LogEntry
JavascriptEntry)
      String
_ -> String -> Parser LogEvent
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Parser LogEvent) -> String -> Parser LogEvent
forall a b. (a -> b) -> a -> b
$ String
"Unknown log entry type: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
entryType

instance FromJSON LogEntry where
  parseJSON :: Value -> Parser LogEntry
  parseJSON :: Value -> Parser LogEntry
parseJSON = String -> (Object -> Parser LogEntry) -> Value -> Parser LogEntry
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"LogEntry" ((Object -> Parser LogEntry) -> Value -> Parser LogEntry)
-> (Object -> Parser LogEntry) -> Value -> Parser LogEntry
forall a b. (a -> b) -> a -> b
$ \Object
o -> do
    entryType <- Object
o Object -> Key -> Parser String
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"type"
    let val = Object -> Value
Object Object
o
    case entryType of
      String
"generic" -> GenericLogEntry -> LogEntry
GenericEntry (GenericLogEntry -> LogEntry)
-> Parser GenericLogEntry -> Parser LogEntry
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser GenericLogEntry
forall a. FromJSON a => Value -> Parser a
parseJSON Value
val
      String
"console" -> ConsoleLogEntry -> LogEntry
ConsoleEntry (ConsoleLogEntry -> LogEntry)
-> Parser ConsoleLogEntry -> Parser LogEntry
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser ConsoleLogEntry
forall a. FromJSON a => Value -> Parser a
parseJSON Value
val
      String
"javascript" -> JavascriptLogEntry -> LogEntry
JavascriptEntry (JavascriptLogEntry -> LogEntry)
-> Parser JavascriptLogEntry -> Parser LogEntry
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser JavascriptLogEntry
forall a. FromJSON a => Value -> Parser a
parseJSON Value
val
      String
_ -> String -> Parser LogEntry
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Parser LogEntry) -> String -> Parser LogEntry
forall a b. (a -> b) -> a -> b
$ String
"Unknown log entry type: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
entryType