module Rattletrap.Decode.Attribute
  ( decodeAttributesBits
  , decodeAttributeBits
  ) where

import Data.Semigroup ((<>))
import Rattletrap.Decode.AttributeValue
import Rattletrap.Decode.Common
import Rattletrap.Decode.CompressedWord
import Rattletrap.Type.Attribute
import Rattletrap.Type.ClassAttributeMap
import Rattletrap.Type.Common
import Rattletrap.Type.CompressedWord
import Rattletrap.Type.Str
import Rattletrap.Type.Word32le

decodeAttributesBits
  :: (Int, Int, Int)
  -> ClassAttributeMap
  -> Map CompressedWord Word32le
  -> CompressedWord
  -> DecodeBits [Attribute]
decodeAttributesBits version classes actors actor = do
  hasAttribute <- getBool
  if hasAttribute
    then
      (:)
      <$> decodeAttributeBits version classes actors actor
      <*> decodeAttributesBits version classes actors actor
    else pure []

decodeAttributeBits
  :: (Int, Int, Int)
  -> ClassAttributeMap
  -> Map CompressedWord Word32le
  -> CompressedWord
  -> DecodeBits Attribute
decodeAttributeBits version classes actors actor = do
  attributes <- lookupAttributeMap classes actors actor
  limit <- lookupAttributeIdLimit attributes actor
  attribute <- decodeCompressedWordBits limit
  name <- lookupAttributeName classes attributes attribute
  Attribute attribute name
    <$> decodeAttributeValueBits
          version
          (classAttributeMapObjectMap classes)
          name

lookupAttributeMap
  :: ClassAttributeMap
  -> Map CompressedWord Word32le
  -> CompressedWord
  -> DecodeBits (Map Word32le Word32le)
lookupAttributeMap classes actors actor = fromMaybe
  ("could not get attribute map for " <> show actor)
  (getAttributeMap classes actors actor)

lookupAttributeIdLimit
  :: Map Word32le Word32le -> CompressedWord -> DecodeBits Word
lookupAttributeIdLimit attributes actor = fromMaybe
  ("could not get attribute ID limit for " <> show actor)
  (getAttributeIdLimit attributes)

lookupAttributeName
  :: ClassAttributeMap
  -> Map Word32le Word32le
  -> CompressedWord
  -> DecodeBits Str
lookupAttributeName classes attributes attribute = fromMaybe
  ("could not get attribute name for " <> show attribute)
  (getAttributeName classes attributes attribute)

fromMaybe :: String -> Maybe a -> DecodeBits a
fromMaybe message = maybe (fail message) pure