{-# LANGUAGE OverloadedStrings #-}
module JavaScript.Array.Internal
    ( SomeJSArray(..)
    , JSArray
    , MutableJSArray
    , STJSArray
    , create
    , fromList
    , fromListIO
    , toList
    , toListIO
    , index
    , read
    , push
    ) where

import Prelude hiding(read)
import Control.Monad (void)
import GHCJS.Types (JSVal)
import Data.JSString.Internal.Type (JSString(..))
import Language.Javascript.JSaddle.Types (JSM, SomeJSArray(..), JSArray, MutableJSArray, STJSArray, Object(..), GHCJSPure(..))
import Language.Javascript.JSaddle.Native.Internal
       (newArray, getPropertyByName, getPropertyAtIndex, callAsFunction, valueToNumber)
import Language.Javascript.JSaddle.Run
       (Command(..), Result(..), AsyncCommand(..), sendCommand, sendLazyCommand)

create :: JSM MutableJSArray
create = SomeJSArray <$> newArray []
{-# INLINE create #-}

fromList :: [JSVal] -> GHCJSPure (SomeJSArray m)
fromList = GHCJSPure . fromListIO
{-# INLINE fromList #-}

fromListIO :: [JSVal] -> JSM (SomeJSArray m)
fromListIO xs = SomeJSArray <$> newArray xs
{-# INLINE fromListIO #-}

toList :: SomeJSArray m -> GHCJSPure [JSVal]
toList = GHCJSPure . toListIO
{-# INLINE toList #-}

toListIO :: SomeJSArray m -> JSM [JSVal]
toListIO (SomeJSArray x) = do
    len <- getPropertyByName (JSString "length") (Object x) >>= valueToNumber
    mapM (`getPropertyAtIndex` Object x) [0..round len - 1]
{-# INLINE toListIO #-}

index :: Int -> SomeJSArray m -> GHCJSPure JSVal
index n = GHCJSPure . read n
{-# INLINE index #-}

read :: Int -> SomeJSArray m -> JSM JSVal
read n (SomeJSArray x) = getPropertyAtIndex n $ Object x
{-# INLINE read #-}

push :: JSVal -> MutableJSArray -> JSM ()
push e (SomeJSArray x) = void $ do
    f <- getPropertyByName (JSString "push") (Object x)
    void $ callAsFunction (Object f) (Object x) [e]
{-# INLINE push #-}