{-# LANGUAGE MultiParamTypeClasses      #-}
{-# LANGUAGE FunctionalDependencies     #-}
{-# LANGUAGE FlexibleInstances          #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Control.Monad.Queue.Class
-- Copyright   :  (c) Leon P Smith 2009
-- License     :  BSD3
--
-- Maintainer  :  leon at melding-monads dot com
-- Stability   :  experimental
-- Portability :  portable
--
-----------------------------------------------------------------------------

module Control.Monad.Queue.Class where

import Control.Monad.Queue.Util
import qualified Control.Monad.Queue.Allison as Allison
import qualified Control.Monad.Queue.Corec   as Corec

class Monad q => MonadQueue e q | q -> e where
  -- | Enqueue an element to a queue
  enQ     :: e -> q ()
  -- | Dequeue an element,  returns 'Nothing' if the queue is empty.
  deQ     :: q (Maybe e)
  -- | Dequeue up to @maxlen@ elements.
  deQs    :: Integral maxlen => maxlen -> q [e]
  -- | Examines the front element of the queue without removing it.
  peekQ   :: q (Maybe e)
  -- | Examines up to @maxlen@ elements of the queue without removing them.
  peekQs  :: Integral maxlen  => maxlen -> q [e]
  -- | Examines the element currently at position @index@,  indexing starts at @0@.
  peekQn  :: Integral index   => index  -> q (Maybe e)
  -- | Returns the current length of the queue
  lenQ    :: Integral len => q len

  deQ = do
          es <- deQs (1 :: LenType)
          case es of
           []    -> return Nothing
           (e:_) -> return (Just e)

  deQs n
     | n <= 0    = return []
     | otherwise = deQ >>=  maybe (return [])
                            (\e ->  do
                                    es <- deQs (n-1)
                                    return (e:es))

instance MonadQueue e (Allison.Q e) where
  enQ     = Allison.enQ
  peekQ   = Allison.peekQ
  peekQs  = Allison.peekQs
  peekQn  = Allison.peekQn
  deQ     = Allison.deQ
  deQs    = Allison.deQs
  lenQ    = Allison.lenQ

instance MonadQueue e (Corec.Q w e) where
  enQ     = Corec.enQ
  peekQ   = Corec.peekQ
  peekQs  = Corec.peekQs
  peekQn  = Corec.peekQn
  deQ     = Corec.deQ
  deQs    = Corec.deQs
  lenQ    = Corec.lenQ