{-|
Module      : Board
Copyright   : (c) 2014 Kaashif Hymabaccus
License     : GPL-3
Maintainer  : kaashif@kaashif.co.uk
Stability   : experimental
Portability : POSIX
-}
{-# LANGUAGE OverloadedStrings #-}

module Board where

import Paths_venture
import Data.Aeson
import Data.Maybe (fromJust)
import qualified Data.Map as M
import qualified Data.ByteString.Lazy as BS
import Control.Monad
import Control.Applicative
import Vector
import qualified Player

-- | Essentially a sparse array of cells
type Board = M.Map Vector2D Cell

-- | The \"squares\" on the board the player moves through
data Cell = Cell { contents :: [Thing]      -- ^ Objects you can take
                 , position :: [Integer]    -- ^ Position vector in n-dimensional space. Also the Board key.
                 , description :: String    -- ^ Description you see after you visit for the first time
                 , initial :: String        -- ^ Description you see visiting for the first time
                 , seen :: Bool             -- ^ Whether you've been here before
                 }

instance FromJSON Cell where
    parseJSON (Object v) = Cell <$> v .: "contents" <*>
                                    v .: "position" <*>
                                    v .: "description" <*>
                                    v .: "initial" <*>
                                    v .: "seen"
    parseJSON _ = mzero

-- | Placeholder - this will be a data type for quest items, weapons etc.
type Thing = String

-- | Reads board from wherever cabal hides \"board.json\"
readBoard :: IO Board
readBoard = getDataFileName "board.json" >>= BS.readFile >>= \s -> return $ decodeBoard s

-- | Decodes ByteString JSON (read from a file) into a board
decodeBoard :: BS.ByteString -> Board
decodeBoard s = foldl insertCell M.empty decoded
    where decoded = fromJust (decode s :: Maybe [Cell])

-- | Inserts cell into the board map at the right position (i.e. with the right key)
insertCell :: Board -> Cell -> Board
insertCell m c = M.insert pos c m
    where pos = ( (position c !! 0),(position c !! 1) )

-- | Checks whether the player is actually on a cell of the /sparse/ board
valid :: Player.Player -> Board -> Bool
valid p b = M.member (Player.position p) b

-- | Gets an appropriate description for a cell, based on whether it has been seen
describe :: Board -> Vector2D -> String
describe b pos = case (M.lookup pos b) of
    Just cell -> if (seen cell)
                    then description cell
                    else initial cell
    Nothing -> "How did this even happen?"

-- | Marks the cell the player currently occupies as visited
markVisited :: Player.Player -> Board -> Board
markVisited p b = M.insert (Player.position p) newcell b
    where newcell = oldcell { seen = True }
          oldcell = fromJust $ M.lookup (Player.position p) b
