content: {-# 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 (Show, Eq, Enum, Generic)
  
  instance Binary KillHow
  
  type KillMap = EM.EnumMap FactionId (EM.EnumMap ItemId Int)
  
  -- | Statistics of past events concerning an actor.
  newtype Analytics = Analytics
    { akillCounts :: EM.EnumMap KillHow KillMap
    }
    deriving (Show, Eq, Binary)
  
  emptyAnalytics :: Analytics
  emptyAnalytics = Analytics
    { akillCounts = EM.empty
    }
  
  addKill :: KillHow -> FactionId -> ItemId -> Maybe Analytics -> Analytics
  addKill killHow fid iid =
    let f Nothing = Analytics {akillCounts =
          EM.singleton killHow $ EM.singleton fid $ EM.singleton iid 1}
        f (Just an) = an {akillCounts =
          EM.alter g killHow $ akillCounts an}
        g Nothing = Just $ EM.singleton fid $ EM.singleton iid 1
        g (Just fidMap) = Just $ EM.alter h fid fidMap
        h Nothing = Just $ EM.singleton iid 1
        h (Just iidMap) = Just $ EM.alter i iid iidMap
        i Nothing = Just 1
        i (Just n) = Just $ n + 1
    in f
  
  addFactionKill :: FactionId -> KillHow -> FactionId -> ItemId
                 -> FactionAnalytics
                 -> FactionAnalytics
  addFactionKill fidOfKiller killHow fid iid =
    EM.alter (Just . addKill killHow fid iid) fidOfKiller
  
  addActorKill :: ActorId -> KillHow -> FactionId -> ItemId
               -> ActorAnalytics
               -> ActorAnalytics
  addActorKill aid killHow fid iid =
    EM.alter (Just . addKill killHow fid iid) aid
  