content: {-# LANGUAGE TypeFamilies #-}
  {-# LANGUAGE TypeSynonymInstances #-}
  {-# LANGUAGE FlexibleInstances #-}
  {-# LANGUAGE DataKinds #-}
  {-# LANGUAGE PolyKinds #-}
  {-# LANGUAGE TypeOperators #-}
  
  module JavaScript.TypedArray.Internal where
  
  import Prelude hiding ((!!))
  
  import GHC.Int
  import GHC.Word
  
  import GHCJS.Internal.Types
  
  import Control.Monad (void)
  import Control.Lens.Operators ((^.))
  
  import GHCJS.Marshal (fromJSValUnchecked)
  
  import JavaScript.Array.Internal (SomeJSArray(..))
  import JavaScript.TypedArray.ArrayBuffer
  import JavaScript.TypedArray.ArrayBuffer.Internal (SomeArrayBuffer(..))
  import JavaScript.TypedArray.Internal.Types
  
  import Language.Javascript.JSaddle.Types (JSM, GHCJSPure(..))
  import Language.Javascript.JSaddle.Object (js, jsg, js1, js2, new, (!!), (<##))
  
  elemSize :: SomeTypedArray e m -> GHCJSPure Int
  elemSize (SomeTypedArray a) = GHCJSPure $ a ^. js "BYTES_PER_ELEMENT" >>= fromJSValUnchecked
  {-# INLINE [1] elemSize #-}
  {-# RULES "elemSizeUint8Clamped" forall (x :: SomeUint8ClampedArray m). elemSize x = GHCJSPure $ return 1 #-}
  {-# RULES "elemSizeUint8"        forall (x :: SomeUint8Array m).        elemSize x = GHCJSPure $ return 1 #-}
  {-# RULES "elemSizeUint16"       forall (x :: SomeUint16Array m).       elemSize x = GHCJSPure $ return 2 #-}
  {-# RULES "elemSizeUint32"       forall (x :: SomeUint32Array m).       elemSize x = GHCJSPure $ return 4 #-}
  {-# RULES "elemSizeInt8"         forall (x :: SomeInt8Array m).         elemSize x = GHCJSPure $ return 1 #-}
  {-# RULES "elemSizeInt16"        forall (x :: SomeInt16Array m).        elemSize x = GHCJSPure $ return 2 #-}
  {-# RULES "elemSizeInt32"        forall (x :: SomeInt32Array m).        elemSize x = GHCJSPure $ return 4 #-}
  {-# RULES "elemSizeFloat32"      forall (x :: SomeFloat32Array m).      elemSize x = GHCJSPure $ return 4 #-}
  {-# RULES "elemSizeFloat64"      forall (x :: SomeFloat64Array m).      elemSize x = GHCJSPure $ return 8 #-}
  
  instance TypedArray IOInt8Array where
    index              = indexI8
    unsafeIndex        = unsafeIndexI8
    setIndex i x       = setIndexI i (fromIntegral x)
    unsafeSetIndex i x = unsafeSetIndexI i (fromIntegral x)
    indexOf s x        = indexOfI s (fromIntegral x)
    lastIndexOf s x    = lastIndexOfI s (fromIntegral x)
    create l           = SomeTypedArray <$> new (jsg "Int8Array") [l]
    fromArray          = int8ArrayFrom
    fromArrayBuffer    = undefined
  
  instance TypedArray IOInt16Array where
    index              = indexI16
    unsafeIndex        = unsafeIndexI16
    setIndex i x       = setIndexI i (fromIntegral x)
    unsafeSetIndex i x = unsafeSetIndexI i (fromIntegral x)
    indexOf s x        = indexOfI s (fromIntegral x)
    lastIndexOf s x    = lastIndexOfI s (fromIntegral x)
    create l           = SomeTypedArray <$> new (jsg "Int16Array") [l]
    fromArray          = int16ArrayFrom
    fromArrayBuffer    = undefined
  
  instance TypedArray IOInt32Array where
    index           = indexI
    unsafeIndex     = unsafeIndexI
    setIndex        = setIndexI
    unsafeSetIndex  = unsafeSetIndexI
    indexOf         = indexOfI
    lastIndexOf     = lastIndexOfI
    create l        = SomeTypedArray <$> new (jsg "Int32Array") [l]
    fromArray       = int32ArrayFrom
    fromArrayBuffer = undefined
  
  instance TypedArray IOUint8ClampedArray where
    index              = indexW8
    unsafeIndex        = unsafeIndexW8
    setIndex i x       = setIndexW i (fromIntegral x)
    unsafeSetIndex i x = unsafeSetIndexW i (fromIntegral x)
    indexOf s x        = indexOfW s (fromIntegral x)
    lastIndexOf s x    = lastIndexOfW s (fromIntegral x)
    create l           = SomeTypedArray <$> new (jsg "Uint8ClampedArray") [l]
    fromArray          = uint8ClampedArrayFrom
    fromArrayBuffer    = undefined
  
  instance TypedArray IOUint8Array where
    index              = indexW8
    unsafeIndex        = unsafeIndexW8
    setIndex i x       = setIndexW i (fromIntegral x)
    unsafeSetIndex i x = unsafeSetIndexW i (fromIntegral x)
    indexOf s x        = indexOfW s (fromIntegral x)
    lastIndexOf s x    = lastIndexOfW s (fromIntegral x)
    create l           = SomeTypedArray <$> new (jsg "Uint8Array") [l]
    fromArray          = uint8ArrayFrom
    fromArrayBuffer    = undefined
  
  instance TypedArray IOUint16Array where
    index              = indexW16
    unsafeIndex        = unsafeIndexW16
    setIndex i x       = setIndexW i (fromIntegral x)
    unsafeSetIndex i x = unsafeSetIndexW i (fromIntegral x)
    indexOf s x        = indexOfW s (fromIntegral x)
    lastIndexOf s x    = lastIndexOfW s (fromIntegral x)
    create l           = SomeTypedArray <$> new (jsg "Uint16Array") [l]
    fromArray          = uint16ArrayFrom
    fromArrayBuffer    = undefined
  
  instance TypedArray IOUint32Array where
    index           = indexW
    unsafeIndex     = unsafeIndexW
    setIndex        = setIndexW
    unsafeSetIndex  = unsafeSetIndexW
    indexOf         = indexOfW
    lastIndexOf     = lastIndexOfW
    create l        = SomeTypedArray <$> new (jsg "Uint32Array") [l]
    fromArray       = uint32ArrayFrom
    fromArrayBuffer = undefined
  
  instance TypedArray IOFloat32Array where
    index           = indexD
    unsafeIndex     = unsafeIndexD
    setIndex        = setIndexD
    unsafeSetIndex  = unsafeSetIndexD
    indexOf         = indexOfD
    lastIndexOf     = lastIndexOfD
    create l        = SomeTypedArray <$> new (jsg "Float32Array") [l]
    fromArray       = float32ArrayFrom
    fromArrayBuffer = undefined
  
  instance TypedArray IOFloat64Array where
    index           = indexD
    unsafeIndex     = unsafeIndexD
    setIndex        = setIndexD
    unsafeSetIndex  = unsafeSetIndexD
    indexOf         = indexOfD
    lastIndexOf     = lastIndexOfD
    create l        = SomeTypedArray <$> new (jsg "Float64Array") [l]
    fromArray       = float64ArrayFrom
    fromArrayBuffer = undefined
  
  
  class TypedArray a where
    unsafeIndex     :: Int           -> a -> JSM (Elem a)
    index           :: Int           -> a -> JSM (Elem a)
    unsafeSetIndex  :: Int -> Elem a -> a -> JSM ()
    setIndex        :: Int -> Elem a -> a -> JSM ()
    create          :: Int                -> JSM a
    fromArray       :: SomeJSArray m      -> JSM a
    fromArrayBuffer :: MutableArrayBuffer -> Int    -> Maybe Int -> JSM a
    indexOf         :: Int                -> Elem a -> a -> JSM Int
    lastIndexOf     :: Int                -> Elem a -> a -> JSM Int
  
  -- -----------------------------------------------------------------------------
  
  indexI :: Int -> SomeTypedArray e m -> JSM Int
  indexI i (SomeTypedArray a) = a !! i >>= fromJSValUnchecked
  {-# INLINE indexI #-}
  
  indexI16 :: Int -> SomeTypedArray e m -> JSM Int16
  indexI16 i (SomeTypedArray a) = a !! i >>= fromJSValUnchecked
  {-# INLINE indexI16 #-}
  
  indexI8 :: Int -> SomeTypedArray e m -> JSM Int8
  indexI8 i (SomeTypedArray a) = a !! i >>= fromJSValUnchecked
  {-# INLINE indexI8 #-}
  
  indexW :: Int -> SomeTypedArray e m -> JSM Word
  indexW i (SomeTypedArray a) = a !! i >>= fromJSValUnchecked
  {-# INLINE indexW #-}
  
  indexW16 :: Int -> SomeTypedArray e m -> JSM Word16
  indexW16 i (SomeTypedArray a) = a !! i >>= fromJSValUnchecked
  {-# INLINE indexW16 #-}
  
  indexW8 :: Int -> SomeTypedArray e m -> JSM Word8
  indexW8 i (SomeTypedArray a) = a !! i >>= fromJSValUnchecked
  {-# INLINE indexW8 #-}
  
  indexD :: Int -> SomeTypedArray e m -> JSM Double
  indexD i (SomeTypedArray a) = a !! i >>= fromJSValUnchecked
  {-# INLINE indexD #-}
  
  -- -----------------------------------------------------------------------------
  
  unsafeIndexI :: Int -> SomeTypedArray e m -> JSM Int
  unsafeIndexI i (SomeTypedArray a) = a !! i >>= fromJSValUnchecked
  {-# INLINE unsafeIndexI #-}
  
  unsafeIndexI16 :: Int -> SomeTypedArray e m -> JSM Int16
  unsafeIndexI16 i (SomeTypedArray a) = a !! i >>= fromJSValUnchecked
  {-# INLINE unsafeIndexI16 #-}
  
  unsafeIndexI8 :: Int -> SomeTypedArray e m -> JSM Int8
  unsafeIndexI8 i (SomeTypedArray a) = a !! i >>= fromJSValUnchecked
  {-# INLINE unsafeIndexI8 #-}
  
  unsafeIndexW :: Int -> SomeTypedArray e m -> JSM  Word
  unsafeIndexW i (SomeTypedArray a) = a !! i >>= fromJSValUnchecked
  {-# INLINE unsafeIndexW #-}
  
  unsafeIndexW16 :: Int -> SomeTypedArray e m -> JSM Word16
  unsafeIndexW16 i (SomeTypedArray a) = a !! i >>= fromJSValUnchecked
  {-# INLINE unsafeIndexW16 #-}
  
  unsafeIndexW8 :: Int -> SomeTypedArray e m -> JSM Word8
  unsafeIndexW8 i (SomeTypedArray a) = a !! i >>= fromJSValUnchecked
  {-# INLINE unsafeIndexW8 #-}
  
  unsafeIndexD :: Int -> SomeTypedArray e m -> JSM Double
  unsafeIndexD i (SomeTypedArray a) = a !! i >>= fromJSValUnchecked
  {-# INLINE unsafeIndexD #-}
  
  -- -----------------------------------------------------------------------------
  
  int8ArrayFrom :: SomeJSArray m0 -> JSM (SomeInt8Array m1)
  int8ArrayFrom (SomeJSArray a) = SomeTypedArray <$> jsg "Int8Array" ^. js1 "from" a
  {-# INLINE int8ArrayFrom #-}
  
  int16ArrayFrom :: SomeJSArray m0 -> JSM (SomeInt16Array m1)
  int16ArrayFrom (SomeJSArray a) = SomeTypedArray <$> jsg "Int16Array" ^. js1 "from" a
  {-# INLINE int16ArrayFrom #-}
  
  int32ArrayFrom :: SomeJSArray m0 -> JSM (SomeInt32Array m1)
  int32ArrayFrom (SomeJSArray a) = SomeTypedArray <$> jsg "Int32Array" ^. js1 "from" a
  {-# INLINE int32ArrayFrom #-}
  
  uint8ArrayFrom :: SomeJSArray m0 -> JSM (SomeUint8Array m1)
  uint8ArrayFrom (SomeJSArray a) = SomeTypedArray <$> jsg "Uint8Array" ^. js1 "from" a
  {-# INLINE uint8ArrayFrom #-}
  
  uint8ClampedArrayFrom :: SomeJSArray m0 -> JSM (SomeUint8ClampedArray m1)
  uint8ClampedArrayFrom (SomeJSArray a) = SomeTypedArray <$> jsg "Uint8ClampedArray" ^. js1 "from" a
  {-# INLINE uint8ClampedArrayFrom #-}
  
  uint16ArrayFrom :: SomeJSArray m0 -> JSM (SomeUint16Array m1)
  uint16ArrayFrom (SomeJSArray a) = SomeTypedArray <$> jsg "Uint16Array" ^. js1 "from" a
  {-# INLINE uint16ArrayFrom #-}
  
  uint32ArrayFrom :: SomeJSArray m0 -> JSM (SomeUint32Array m1)
  uint32ArrayFrom (SomeJSArray a) = SomeTypedArray <$> jsg "Uint32Array" ^. js1 "from" a
  {-# INLINE uint32ArrayFrom #-}
  
  float32ArrayFrom :: SomeJSArray m0 -> JSM (SomeFloat32Array m1)
  float32ArrayFrom (SomeJSArray a) = SomeTypedArray <$> jsg "Float32Array" ^. js1 "from" a
  {-# INLINE float32ArrayFrom #-}
  
  float64ArrayFrom :: SomeJSArray m0 -> JSM (SomeFloat64Array m1)
  float64ArrayFrom (SomeJSArray a) = SomeTypedArray <$> jsg "Float64Array" ^. js1 "from" a
  {-# INLINE float64ArrayFrom #-}
  
  -- -----------------------------------------------------------------------------
  
  setIndexI :: Mutability m ~ IsMutable
            => Int -> Int -> SomeTypedArray e m -> JSM ()
  setIndexI i x (SomeTypedArray a) = (a <## i) x
  {-# INLINE setIndexI #-}
  
  unsafeSetIndexI :: Mutability m ~ IsMutable
                  => Int -> Int -> SomeTypedArray e m -> JSM ()
  unsafeSetIndexI i x (SomeTypedArray a) = (a <## i) x
  {-# INLINE unsafeSetIndexI #-}
  
  setIndexW :: Mutability m ~ IsMutable
             => Int -> Word -> SomeTypedArray e m -> JSM ()
  setIndexW i x (SomeTypedArray a) = (a <## i) x
  {-# INLINE setIndexW #-}
  
  unsafeSetIndexW :: Mutability m ~ IsMutable
                  => Int -> Word -> SomeTypedArray e m -> JSM ()
  unsafeSetIndexW i x (SomeTypedArray a) = (a <## i) x
  {-# INLINE unsafeSetIndexW #-}
  
  setIndexD :: Mutability m ~ IsMutable
            => Int -> Double -> SomeTypedArray e m -> JSM ()
  setIndexD i x (SomeTypedArray a) = (a <## i) x
  {-# INLINE setIndexD #-}
  
  unsafeSetIndexD :: Mutability m ~ IsMutable
                  => Int -> Double -> SomeTypedArray e m -> JSM ()
  unsafeSetIndexD i x (SomeTypedArray a) = (a <## i) x
  {-# INLINE unsafeSetIndexD #-}
  
  indexOfI :: Mutability m ~ IsMutable
           => Int -> Int -> SomeTypedArray e m -> JSM Int
  indexOfI s x (SomeTypedArray a) = a ^. js2 "indexOf" x s >>= fromJSValUnchecked
  {-# INLINE indexOfI #-}
  
  indexOfW :: Int -> Word -> SomeTypedArray e m -> JSM Int
  indexOfW s x (SomeTypedArray a) = a ^. js2 "indexOf" x s >>= fromJSValUnchecked
  {-# INLINE indexOfW #-}
  
  indexOfD :: Int -> Double -> SomeTypedArray e m -> JSM Int
  indexOfD s x (SomeTypedArray a) = a ^. js2 "indexOf" x s >>= fromJSValUnchecked
  {-# INLINE indexOfD #-}
  
  lastIndexOfI :: Int -> Int -> SomeTypedArray e m -> JSM Int
  lastIndexOfI s x (SomeTypedArray a) = a ^. js2 "lastIndexOf" x s >>= fromJSValUnchecked
  {-# INLINE lastIndexOfI #-}
  
  lastIndexOfW :: Int -> Word -> SomeTypedArray e m -> JSM Int
  lastIndexOfW s x (SomeTypedArray a) = a ^. js2 "lastIndexOf" x s >>= fromJSValUnchecked
  {-# INLINE lastIndexOfW #-}
  
  lastIndexOfD :: Int -> Double -> SomeTypedArray e m -> JSM Int
  lastIndexOfD s x (SomeTypedArray a) = a ^. js2 "lastIndexOf" x s >>= fromJSValUnchecked
  {-# INLINE lastIndexOfD #-}
  
  -- -----------------------------------------------------------------------------
  -- non-class operations usable for all typed array
  {-| length of the typed array in elements -}
  length :: SomeTypedArray e m -> GHCJSPure Int
  length (SomeTypedArray a) = GHCJSPure $ a ^. js "length" >>= fromJSValUnchecked
  {-# INLINE length #-}
  
  {-| length of the array in bytes -}
  byteLength :: SomeTypedArray e m -> GHCJSPure Int
  byteLength (SomeTypedArray a) = GHCJSPure $ a ^. js "byteLength" >>= fromJSValUnchecked
  {-# INLINE byteLength #-}
  
  {-| offset of the array in the buffer -}
  byteOffset :: SomeTypedArray e m -> GHCJSPure Int
  byteOffset (SomeTypedArray a) = GHCJSPure $ a ^. js "byteOffset" >>= fromJSValUnchecked
  {-# INLINE byteOffset #-}
  
  {-| the underlying buffer of the array -}
  buffer :: SomeTypedArray e m -> GHCJSPure (SomeArrayBuffer m)
  buffer (SomeTypedArray a) = GHCJSPure $ SomeArrayBuffer <$> a ^. js "buffer"
  {-# INLINE buffer #-}
  
  {-| create a view of the existing array -}
  subarray :: Int -> Int -> SomeTypedArray e m -> GHCJSPure (SomeTypedArray e m)
  subarray begin end (SomeTypedArray a) = GHCJSPure$ SomeTypedArray <$> a ^. js2 "subarray" begin end
  {-# INLINE subarray #-}
  
  -- fixme convert JSException to Haskell exception
  {-| copy the elements of one typed array to another -}
  set :: Int -> SomeTypedArray e m -> SomeTypedArray e1 Mutable -> GHCJSPure ()
  set offset (SomeTypedArray src) (SomeTypedArray dest) = GHCJSPure $ void $ dest ^. js2 "set" offset src
  {-# INLINE set #-}
  
  unsafeSet :: Int -> SomeTypedArray e m -> SomeTypedArray e1 Mutable -> GHCJSPure ()
  unsafeSet offset (SomeTypedArray src) (SomeTypedArray dest) = GHCJSPure $ void $ dest ^. js2 "set" offset src
  {-# INLINE unsafeSet #-}
  
  