{-# LANGUAGE TypeFamilies #-}

{-# OPTIONS_GHC -Wall #-}
module Data.RingBuffer.Chord
(
  Chord
, emptyChord
, cToVec
)

where

import Prelude hiding (length)
import Data.RingBuffer.Class
import qualified Data.Vector.Unboxed as V
import           Data.Vector.Unboxed (Vector, Unbox)

-- A structure for pushing elements
-- params:
--   partial chunk fill
--   partial chunk
--   full chunk quantity
--   full chunks
data Chord a = Chord !Int [a] !Int [Vector a]
  deriving (Show, Eq, Ord)

-- | an empty chord.
emptyChord :: a -> Chord a
emptyChord _ = Chord 0 [] 0 []

cToVec :: Unbox a => Chord a -> Vector a
cToVec (Chord pf pc _ cs) = V.concat (V.fromListN pf pc : cs)
{-# INLINE cToVec #-}

type instance (El (Chord a)) = a

instance V.Unbox a => RingBuffer (Chord a) where
  {-# INLINE length #-}
  length (Chord pfill _ c _) = 32*c + pfill
  {-# INLINE push #-}
  push   (Chord 31 pc n cs) el =
     let new = V.fromListN 32 (el:pc)
     in  new `seq` Chord 0 [] (n+1) (new:cs)
  push   (Chord pf pc n cs) el =
     Chord (pf+1) (el : pc) n cs
  {-# INLINE (!) #-}
  (Chord pf pc _ cs) ! ix
     | ix <= pf  = pc !! ix
     | otherwise = let (major,minor) = (ix - pf) `divMod` 32
                   in (cs !! major) `V.unsafeIndex` minor