    {-# LANGUAGE DeriveGeneric, GeneralizedNewtypeDeriving #-}
    -- | Per-actor analytics of personal feats.
    module Game.LambdaHack.Common.Analytics
      ( FactionAnalytics, ActorAnalytics, GenerationAnalytics
      , KillMap, Analytics(..), KillHow(..)
      , emptyAnalytics, addFactionKill, addActorKill
    #ifdef EXPOSE_INTERNAL
        -- * Internal operations
      , addKill
    #endif
      ) where

    import Prelude ()

    import Game.LambdaHack.Core.Prelude

    import           Data.Binary
    import qualified Data.EnumMap.Strict as EM
    import           GHC.Generics (Generic)

    import Game.LambdaHack.Common.Types
    import Game.LambdaHack.Definition.Defs

    -- | Summary analytics data for each faction.
    type FactionAnalytics = EM.EnumMap FactionId Analytics

    -- | Analytics data for each live actor.
    type ActorAnalytics = EM.EnumMap ActorId Analytics

    -- | Statistics of possible and actual generation of items for each lore kind.
    type GenerationAnalytics = EM.EnumMap SLore (EM.EnumMap ItemId Int)

    -- | Labels of individual kill count analytics.
    data KillHow =
        KillKineticMelee
      | KillKineticRanged
      | KillKineticBlast
      | KillKineticPush
      | KillOtherMelee
      | KillOtherRanged
      | KillOtherBlast
      | KillOtherPush
      | KillActorLaunch
      | KillTileLaunch
      | KillDropLaunch
      | KillCatch
      deriving (Int -> KillHow -> ShowS
    [KillHow] -> ShowS
    KillHow -> String
    (Int -> KillHow -> ShowS)
    -> (KillHow -> String) -> ([KillHow] -> ShowS) -> Show KillHow
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> KillHow -> ShowS
    showsPrec :: Int -> KillHow -> ShowS
    $cshow :: KillHow -> String
    show :: KillHow -> String
    $cshowList :: [KillHow] -> ShowS
    showList :: [KillHow] -> ShowS
    Show, KillHow -> KillHow -> Bool
    (KillHow -> KillHow -> Bool)
    -> (KillHow -> KillHow -> Bool) -> Eq KillHow
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: KillHow -> KillHow -> Bool
    == :: KillHow -> KillHow -> Bool
    $c/= :: KillHow -> KillHow -> Bool
    /= :: KillHow -> KillHow -> Bool
    Eq, Int -> KillHow
    KillHow -> Int
    KillHow -> [KillHow]
    KillHow -> KillHow
    KillHow -> KillHow -> [KillHow]
    KillHow -> KillHow -> KillHow -> [KillHow]
    (KillHow -> KillHow)
    -> (KillHow -> KillHow)
    -> (Int -> KillHow)
    -> (KillHow -> Int)
    -> (KillHow -> [KillHow])
    -> (KillHow -> KillHow -> [KillHow])
    -> (KillHow -> KillHow -> [KillHow])
    -> (KillHow -> KillHow -> KillHow -> [KillHow])
    -> Enum KillHow
    forall a.
    (a -> a)
    -> (a -> a)
    -> (Int -> a)
    -> (a -> Int)
    -> (a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> a -> [a])
    -> Enum a
    $csucc :: KillHow -> KillHow
    succ :: KillHow -> KillHow
    $cpred :: KillHow -> KillHow
    pred :: KillHow -> KillHow
    $ctoEnum :: Int -> KillHow
    toEnum :: Int -> KillHow
    $cfromEnum :: KillHow -> Int
    fromEnum :: KillHow -> Int
    $cenumFrom :: KillHow -> [KillHow]
    enumFrom :: KillHow -> [KillHow]
    $cenumFromThen :: KillHow -> KillHow -> [KillHow]
    enumFromThen :: KillHow -> KillHow -> [KillHow]
    $cenumFromTo :: KillHow -> KillHow -> [KillHow]
    enumFromTo :: KillHow -> KillHow -> [KillHow]
    $cenumFromThenTo :: KillHow -> KillHow -> KillHow -> [KillHow]
    enumFromThenTo :: KillHow -> KillHow -> KillHow -> [KillHow]
    Enum, (forall x. KillHow -> Rep KillHow x)
    -> (forall x. Rep KillHow x -> KillHow) -> Generic KillHow
    forall x. Rep KillHow x -> KillHow
    forall x. KillHow -> Rep KillHow x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    $cfrom :: forall x. KillHow -> Rep KillHow x
    from :: forall x. KillHow -> Rep KillHow x
    $cto :: forall x. Rep KillHow x -> KillHow
    to :: forall x. Rep KillHow x -> KillHow
    Generic)

    instance Binary KillHow

    type KillMap = EM.EnumMap FactionId (EM.EnumMap ItemId Int)

    -- | Statistics of past events concerning an actor.
    newtype Analytics = Analytics
      { Analytics -> EnumMap KillHow KillMap
    akillCounts :: EM.EnumMap KillHow KillMap
      }
      deriving (Int -> Analytics -> ShowS
    [Analytics] -> ShowS
    Analytics -> String
    (Int -> Analytics -> ShowS)
    -> (Analytics -> String)
    -> ([Analytics] -> ShowS)
    -> Show Analytics
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> Analytics -> ShowS
    showsPrec :: Int -> Analytics -> ShowS
    $cshow :: Analytics -> String
    show :: Analytics -> String
    $cshowList :: [Analytics] -> ShowS
    showList :: [Analytics] -> ShowS
    Show, Analytics -> Analytics -> Bool
    (Analytics -> Analytics -> Bool)
    -> (Analytics -> Analytics -> Bool) -> Eq Analytics
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Analytics -> Analytics -> Bool
    == :: Analytics -> Analytics -> Bool
    $c/= :: Analytics -> Analytics -> Bool
    /= :: Analytics -> Analytics -> Bool
    Eq, Get Analytics
    [Analytics] -> Put
    Analytics -> Put
    (Analytics -> Put)
    -> Get Analytics -> ([Analytics] -> Put) -> Binary Analytics
    forall t. (t -> Put) -> Get t -> ([t] -> Put) -> Binary t
    $cput :: Analytics -> Put
    put :: Analytics -> Put
    $cget :: Get Analytics
    get :: Get Analytics
    $cputList :: [Analytics] -> Put
    putList :: [Analytics] -> Put
    Binary)

    emptyAnalytics :: Analytics
    emptyAnalytics :: Analytics
    emptyAnalytics = Analytics
      { akillCounts :: EnumMap KillHow KillMap
    akillCounts = EnumMap KillHow KillMap
    forall k a. EnumMap k a
    EM.empty
      }

    addKill :: KillHow -> FactionId -> ItemId -> Maybe Analytics -> Analytics
    addKill :: KillHow -> FactionId -> ItemId -> Maybe Analytics -> Analytics
    addKill KillHow
    killHow FactionId
    fid ItemId
    iid =
      let f :: Maybe Analytics -> Analytics
    f Maybe Analytics
    Nothing = Analytics {akillCounts :: EnumMap KillHow KillMap
    akillCounts =
            KillHow -> KillMap -> EnumMap KillHow KillMap
    forall k a. Enum k => k -> a -> EnumMap k a
    EM.singleton KillHow
    killHow (KillMap -> EnumMap KillHow KillMap)
    -> KillMap -> EnumMap KillHow KillMap
    forall a b. (a -> b) -> a -> b
    $ FactionId -> EnumMap ItemId Int -> KillMap
    forall k a. Enum k => k -> a -> EnumMap k a
    EM.singleton FactionId
    fid (EnumMap ItemId Int -> KillMap) -> EnumMap ItemId Int -> KillMap
    forall a b. (a -> b) -> a -> b
    $ ItemId -> Int -> EnumMap ItemId Int
    forall k a. Enum k => k -> a -> EnumMap k a
    EM.singleton ItemId
    iid Int
    1}
          f (Just Analytics
    an) = Analytics
    an {akillCounts =
            EM.alter g killHow $ akillCounts an}
          g :: Maybe KillMap -> Maybe KillMap
    g Maybe KillMap
    Nothing = KillMap -> Maybe KillMap
    forall a. a -> Maybe a
    Just (KillMap -> Maybe KillMap) -> KillMap -> Maybe KillMap
    forall a b. (a -> b) -> a -> b
    $ FactionId -> EnumMap ItemId Int -> KillMap
    forall k a. Enum k => k -> a -> EnumMap k a
    EM.singleton FactionId
    fid (EnumMap ItemId Int -> KillMap) -> EnumMap ItemId Int -> KillMap
    forall a b. (a -> b) -> a -> b
    $ ItemId -> Int -> EnumMap ItemId Int
    forall k a. Enum k => k -> a -> EnumMap k a
    EM.singleton ItemId
    iid Int
    1
          g (Just KillMap
    fidMap) = KillMap -> Maybe KillMap
    forall a. a -> Maybe a
    Just (KillMap -> Maybe KillMap) -> KillMap -> Maybe KillMap
    forall a b. (a -> b) -> a -> b
    $ (Maybe (EnumMap ItemId Int) -> Maybe (EnumMap ItemId Int))
    -> FactionId -> KillMap -> KillMap
    forall k a.
    Enum k =>
    (Maybe a -> Maybe a) -> k -> EnumMap k a -> EnumMap k a
    EM.alter Maybe (EnumMap ItemId Int) -> Maybe (EnumMap ItemId Int)
    h FactionId
    fid KillMap
    fidMap
          h :: Maybe (EnumMap ItemId Int) -> Maybe (EnumMap ItemId Int)
    h Maybe (EnumMap ItemId Int)
    Nothing = EnumMap ItemId Int -> Maybe (EnumMap ItemId Int)
    forall a. a -> Maybe a
    Just (EnumMap ItemId Int -> Maybe (EnumMap ItemId Int))
    -> EnumMap ItemId Int -> Maybe (EnumMap ItemId Int)
    forall a b. (a -> b) -> a -> b
    $ ItemId -> Int -> EnumMap ItemId Int
    forall k a. Enum k => k -> a -> EnumMap k a
    EM.singleton ItemId
    iid Int
    1
          h (Just EnumMap ItemId Int
    iidMap) = EnumMap ItemId Int -> Maybe (EnumMap ItemId Int)
    forall a. a -> Maybe a
    Just (EnumMap ItemId Int -> Maybe (EnumMap ItemId Int))
    -> EnumMap ItemId Int -> Maybe (EnumMap ItemId Int)
    forall a b. (a -> b) -> a -> b
    $ (Maybe Int -> Maybe Int)
    -> ItemId -> EnumMap ItemId Int -> EnumMap ItemId Int
    forall k a.
    Enum k =>
    (Maybe a -> Maybe a) -> k -> EnumMap k a -> EnumMap k a
    EM.alter Maybe Int -> Maybe Int
    forall {a}. Num a => Maybe a -> Maybe a
    i ItemId
    iid EnumMap ItemId Int
    iidMap
          i :: Maybe a -> Maybe a
    i Maybe a
    Nothing = a -> Maybe a
    forall a. a -> Maybe a
    Just a
    1
          i (Just a
    n) = a -> Maybe a
    forall a. a -> Maybe a
    Just (a -> Maybe a) -> a -> Maybe a
    forall a b. (a -> b) -> a -> b
    $ a
    n a -> a -> a
    forall a. Num a => a -> a -> a
    + a
    1
      in Maybe Analytics -> Analytics
    f

    addFactionKill :: FactionId -> KillHow -> FactionId -> ItemId
                   -> FactionAnalytics
                   -> FactionAnalytics
    addFactionKill :: FactionId
    -> KillHow
    -> FactionId
    -> ItemId
    -> FactionAnalytics
    -> FactionAnalytics
    addFactionKill FactionId
    fidOfKiller KillHow
    killHow FactionId
    fid ItemId
    iid =
      (Maybe Analytics -> Maybe Analytics)
    -> FactionId -> FactionAnalytics -> FactionAnalytics
    forall k a.
    Enum k =>
    (Maybe a -> Maybe a) -> k -> EnumMap k a -> EnumMap k a
    EM.alter (Analytics -> Maybe Analytics
    forall a. a -> Maybe a
    Just (Analytics -> Maybe Analytics)
    -> (Maybe Analytics -> Analytics)
    -> Maybe Analytics
    -> Maybe Analytics
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . KillHow -> FactionId -> ItemId -> Maybe Analytics -> Analytics
    addKill KillHow
    killHow FactionId
    fid ItemId
    iid) FactionId
    fidOfKiller

    addActorKill :: ActorId -> KillHow -> FactionId -> ItemId
                 -> ActorAnalytics
                 -> ActorAnalytics
    addActorKill :: ActorId
    -> KillHow
    -> FactionId
    -> ItemId
    -> ActorAnalytics
    -> ActorAnalytics
    addActorKill ActorId
    aid KillHow
    killHow FactionId
    fid ItemId
    iid =
      (Maybe Analytics -> Maybe Analytics)
    -> ActorId -> ActorAnalytics -> ActorAnalytics
    forall k a.
    Enum k =>
    (Maybe a -> Maybe a) -> k -> EnumMap k a -> EnumMap k a
    EM.alter (Analytics -> Maybe Analytics
    forall a. a -> Maybe a
    Just (Analytics -> Maybe Analytics)
    -> (Maybe Analytics -> Analytics)
    -> Maybe Analytics
    -> Maybe Analytics
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . KillHow -> FactionId -> ItemId -> Maybe Analytics -> Analytics
    addKill KillHow
    killHow FactionId
    fid ItemId
    iid) ActorId
    aid