{-# LANGUAGE TypeFamilies #-}

-- | 'JSMap' provides an abstract and more type-safe access to maps
--   in JavaScript. It is a wrapper around the dictionary each object
--   in JavaScript is.
module Language.Sunroof.JS.Map
  ( JSMap
  , newMap
  , insert
  , lookup'
  , size
  ) where

import Data.Boolean ( IfB(..), BooleanOf )

import Language.Sunroof.Classes
  ( Sunroof(..) )
import Language.Sunroof.Types
import Language.Sunroof.Selector ( (!) )
import Language.Sunroof.JS.Object ( JSObject )
import Language.Sunroof.JS.Bool ( JSBool, jsIfB )
import Language.Sunroof.JS.Number

-- -------------------------------------------------------------
-- JSMap Type
-- -------------------------------------------------------------

-- | 'JSMap' abstraction. The first type parameter gives
--   the type of keys used by the name and the second gives
--   the type of values.
newtype JSMap k a = JSMap JSObject

instance (SunroofKey k, Sunroof a) => Show (JSMap k a) where
  show (JSMap o) = show o

instance (SunroofKey k, Sunroof a) => Sunroof (JSMap k a) where
  box = JSMap . box
  unbox (JSMap o) = unbox o

type instance BooleanOf (JSMap k a) = JSBool

instance (SunroofKey k, Sunroof a) => IfB (JSMap k a) where
  ifB = jsIfB

-- -------------------------------------------------------------
-- JSMap Combinators
-- -------------------------------------------------------------

-- | Create a new empty 'JSMap'.
newMap :: JS t (JSMap k a)
newMap = do
  o <- new "Object" ()
  return $ JSMap o

-- | @insert k x@ inserts an element @x@ associated with the given
--   key @k@ into a map.
insert :: (SunroofKey k, Sunroof a) => k -> a -> JSMap k a -> JS t ()
insert k a (JSMap o) = do
        o # jsKey k := a

-- | @lookup k@ selects the value associated with the key @k@.
lookup' :: (SunroofKey k, Sunroof a) => k -> JSMap k a -> JS t a
lookup' k (JSMap o) = do
        evaluate $ o ! jsKey k

size :: JSMap k a -> JS t JSNumber
size (JSMap o) = fun "Object.size" $$ o

--deleteMap :: (SunroofKey k, Sunroof a) => k -> JSMap k a -> JS t ()
--deleteMap k (JSMap o) = fun "delete" $$ (o ! jsKey k)