-- | The type of kinds of terrain tiles.
module Game.LambdaHack.Content.TileKind
  ( TileKind(..), tvalidate
  ) where

import qualified Data.List as L
import qualified Data.Map.Strict as M
import Data.Text (Text)

import Game.LambdaHack.Common.Color
import Game.LambdaHack.Common.Feature
import Game.LambdaHack.Common.Misc
import Game.LambdaHack.Utils.Assert

-- | The type of kinds of terrain tiles. See @Tile.hs@ for explanation
-- of the absence of a corresponding type @Tile@ that would hold
-- particular concrete tiles in the dungeon.
data TileKind = TileKind
  { tsymbol  :: !Char       -- ^ map symbol
  , tname    :: !Text       -- ^ short description
  , tfreq    :: !Freqs      -- ^ frequency within groups
  , tcolor   :: !Color      -- ^ map color
  , tcolor2  :: !Color      -- ^ map color when not in FOV
  , tfeature :: ![Feature]  -- ^ properties
  }
  deriving Show  -- No Eq and Ord to make extending it logically sound, see #53

-- TODO: check that all posible solid place fences have hidden counterparts.
-- | Filter a list of kinds, passing through only the incorrect ones, if any.
--
-- If tiles look the same on the map, the description should be the same, too.
-- Otherwise, the player has to inspect manually all the tiles of that kind
-- to see if any is special. This is a part of a stronger
-- but less precise property that tiles that look the same can't be
-- distinguished by player actions (but may behave differently
-- wrt dungeon generation, AI preferences, etc.).
tvalidate :: [TileKind] -> [TileKind]
tvalidate lt =
  let listFov f = L.map (\ kt -> ( ( tsymbol kt
                                   , Suspect `elem` tfeature kt
                                   , f kt
                                   )
                                 , [kt] )) lt
      mapFov :: (TileKind -> Color) -> M.Map (Char, Bool, Color) [TileKind]
      mapFov f = M.fromListWith (++) $ listFov f
      namesUnequal [] = assert `failure` lt
      namesUnequal (hd : tl) = let name = tname hd
                               -- Check that at least one is different.
                               in L.any (/= name) (L.map tname tl)
      confusions f = L.filter namesUnequal $ M.elems $ mapFov f
  in case confusions tcolor ++ confusions tcolor2 of
    [] -> []
    l : _ -> l