module Data.Binary.Defer.Array(
    (!), Array, array, elems, arraySize
    ) where

import Data.Array hiding ((!), Array, array, elems)
import qualified Data.Array as A
import Data.Binary.Defer
import Data.Binary.Raw
import System.IO.Unsafe
import Control.Monad.Reader


newtype Array a = Array (A.Array Int a)

array :: [a] -> Array a
array xs = Array $ listArray (0, length xs - 1) xs

(!) :: Array a -> Int -> a
(!) (Array a) i = a A.! i

elems :: Array a -> [a]
elems (Array a) = A.elems a


arraySize (Array a) = 1 + y - x
    where (x,y) = bounds a

instance Functor Array where
    fmap f (Array x) = Array (fmap f x)

instance Eq a => Eq (Array a) where
    Array x == Array y = x == y

instance Show a => Show (Array a) where
    show (Array x) = show x

instance BinaryDefer a => BinaryDefer (Array a) where
    put (Array xs) = putDefer $ do
        putInt $ snd $ bounds xs
        mapM_ putFixed (A.elems xs)

    get = getDefer ans
        where
            ans = do
                n <- getInt
                h <- asks fst
                s <- ask
                i <- lift $ hGetPos h
                let f j = unsafePerformIO $ do
                             hSetPos h (i + toInteger (sz*j))
                             runReaderT getFixed s
                return $ Array $ listArray (0,n) $ map f [0..n]

            unwrap = undefined :: DeferGet (Array a) -> a
            sz = size $ unwrap ans