module Sound.MED.Basic.Utility where

import qualified Data.List.Reverse.StrictSpine as ListRev
import qualified Data.Traversable as Trav
import Data.List.HT (sliceVertical)
import Data.Maybe.HT (toMaybe)

import Data.Word (Word8, Word16, Word32)
import Data.Int (Int8, Int16, Int32)


type PTR   = Word32
type LONG  = Int32
type ULONG = Word32
type WORD  = Int16
type UWORD = Word16
type BYTE  = Int8
type UBYTE = Word8

infixr 0 $?

($?) :: (Monad m) => (PTR -> m a) -> PTR -> m (Maybe a)
PTR -> m a
f $? :: (PTR -> m a) -> PTR -> m (Maybe a)
$? PTR
ptr = Bool -> m a -> m (Maybe a)
forall (m :: * -> *) a. Monad m => Bool -> m a -> m (Maybe a)
skipIf (PTR
ptr PTR -> PTR -> Bool
forall a. Eq a => a -> a -> Bool
== PTR
0) (PTR -> m a
f PTR
ptr)

skipIf :: (Monad m) => Bool -> m a -> m (Maybe a)
skipIf :: Bool -> m a -> m (Maybe a)
skipIf Bool
cond m a
act = Maybe (m a) -> m (Maybe a)
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
Trav.sequence (Maybe (m a) -> m (Maybe a)) -> Maybe (m a) -> m (Maybe a)
forall a b. (a -> b) -> a -> b
$ Bool -> m a -> Maybe (m a)
forall a. Bool -> a -> Maybe a
toMaybe (Bool -> Bool
not Bool
cond) m a
act


pointerRange :: PTR -> ULONG -> Int -> [PTR]
pointerRange :: PTR -> PTR -> Int -> [PTR]
pointerRange PTR
start PTR
step Int
len =
  Int -> [PTR] -> [PTR]
forall a. Int -> [a] -> [a]
take Int
len ([PTR] -> [PTR]) -> [PTR] -> [PTR]
forall a b. (a -> b) -> a -> b
$ (PTR -> PTR) -> PTR -> [PTR]
forall a. (a -> a) -> a -> [a]
iterate (PTR -> PTR
forall a b. (Integral a, Num b) => a -> b
fromIntegral PTR
step PTR -> PTR -> PTR
forall a. Num a => a -> a -> a
+) PTR
start

pointerRangeGen :: (Integral i) => PTR -> ULONG -> i -> [PTR]
pointerRangeGen :: PTR -> PTR -> i -> [PTR]
pointerRangeGen PTR
start PTR
step i
len = PTR -> PTR -> Int -> [PTR]
pointerRange PTR
start PTR
step (i -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral i
len)

{- |
Return empty list if start pointer is zero.
-}
pointerRangeGenCheck :: (Integral i) => PTR -> ULONG -> i -> [PTR]
pointerRangeGenCheck :: PTR -> PTR -> i -> [PTR]
pointerRangeGenCheck PTR
start PTR
step i
len =
  if PTR
start PTR -> PTR -> Bool
forall a. Eq a => a -> a -> Bool
== PTR
0 then [] else PTR -> PTR -> i -> [PTR]
forall i. Integral i => PTR -> PTR -> i -> [PTR]
pointerRangeGen PTR
start PTR
step i
len

pointerRangeGen2 :: (Integral i, Integral j) => PTR -> ULONG -> i -> j -> [PTR]
pointerRangeGen2 :: PTR -> PTR -> i -> j -> [PTR]
pointerRangeGen2 PTR
start PTR
step i
len0 j
len1 =
  PTR -> PTR -> Int -> [PTR]
pointerRange PTR
start PTR
step (i -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral i
len0 Int -> Int -> Int
forall a. Num a => a -> a -> a
* j -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral j
len1)


chunk :: (Integral i) => i -> [a] -> [[a]]
chunk :: i -> [a] -> [[a]]
chunk i
k = Int -> [a] -> [[a]]
forall a. Int -> [a] -> [[a]]
sliceVertical (i -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral i
k)

-- | Strings tend to be fixed width fields with trailing zeros.
stringFromBytes :: [UBYTE] -> String
stringFromBytes :: [UBYTE] -> String
stringFromBytes = (UBYTE -> Char) -> [UBYTE] -> String
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Char
forall a. Enum a => Int -> a
toEnum (Int -> Char) -> (UBYTE -> Int) -> UBYTE -> Char
forall b c a. (b -> c) -> (a -> b) -> a -> c
. UBYTE -> Int
forall a. Enum a => a -> Int
fromEnum) ([UBYTE] -> String) -> ([UBYTE] -> [UBYTE]) -> [UBYTE] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UBYTE -> Bool) -> [UBYTE] -> [UBYTE]
forall a. (a -> Bool) -> [a] -> [a]
ListRev.dropWhile (UBYTE -> UBYTE -> Bool
forall a. Eq a => a -> a -> Bool
==UBYTE
0)