-- Map-related types and routines.
module Map where

import Data.List
import Loc

type CartesianCoord = (Int, Int)
type LinearCoord = Int

data Map = Map {
      mpTitle :: String,
      mpSize :: CartesianCoord,
      mpLocs :: [Loc] }

instance Show Map where
    show (Map t (x,y) ls) = "Map title: " ++ t ++ ", size: " ++ show x ++ " x " ++ show y ++ "\n" ++ "Locs not displayed (use mapLocToString)..."
    --breakLines x (mapLocsToStringList (Map t (x,y) ls))

-- create a map filled with clear terrain
createClearMap :: String -> CartesianCoord -> Map
createClearMap t (x,y) = Map t (x,y) (createClearLocList (x * y))

-- convert between 1d/2d coordinates for a map; return error if out of map
cartesianToLinear :: Map -> CartesianCoord -> LinearCoord
cartesianToLinear m (x, y) = if x < 0 || y < 0 || x > mx - 1 || y > my - 1
                             then error "2d coords is out of map"
                             else ( y * mx) + x
                                 where (mx, my) = mpSize m

linearToCartesian :: Map -> LinearCoord -> CartesianCoord
linearToCartesian m c = if c < 0 || c > mx * my - 1
                        then error "1d coord is out of map"
                        else (x, y)
                            where (mx, my) = mpSize m
                                  y = div c mx
                                  x = c - (mx * y)

-- get a loc from a map
getLoc :: Map -> CartesianCoord -> Loc
getLoc m cc = mpLocs m !! (cartesianToLinear m cc)

-- pretty-print locs' characters for a map to a string
mapLocsToStringList :: Map -> [String]
mapLocsToStringList (Map _ (x,_) ls) = map (\x->lcTextRepresentation x) ls

breakLines  :: Int -> [String] -> String
breakLines _ [] = []
breakLines width lss = (unwords (take width lss)) ++ "\n" ++ breakLines width (drop width lss)

-- get string representation of a map
mapLocsToString :: Map -> String
mapLocsToString m = breakLines x $ mapLocsToStringList m
    where x = fst $ mpSize m
