module Sound.OSC.Transport.Monad.ByteString (T, run, ) where

import qualified Sound.OSC.Transport.Monad as TM

import qualified Sound.OSC.Type as OSC
import Sound.OSC.Class (encodeOSC, )

import qualified Data.ByteString.Lazy as B
import qualified Data.Binary.Put as Put

import Control.Monad.Trans.Reader (ReaderT, runReaderT, ask, )
import Control.Monad.Trans.Class (lift, )
import Control.Monad (ap, )
import Control.Applicative (Applicative, pure, (<*>), )


newtype T a = Cons {decons :: ReaderT OSC.Packet Put.PutM a}


instance Functor T where
   fmap f (Cons act) = Cons $ fmap f act

instance Applicative T where
   pure = return
   (<*>) = ap

instance Monad T where
   return = Cons . return
   Cons x >>= k  =
      Cons  $  decons . k =<< x


instance TM.SendOSC T where
   sendOSC msg = Cons $ lift $
      let b = encodeOSC msg
      in  Put.putWord32be (fromIntegral (B.length b)) >>
          Put.putLazyByteString b

instance TM.RecvOSC T where
   recvPacket = Cons ask

instance TM.DuplexOSC T where


{- |
Write sent messages to a ByteString.
All 'recv' calls are answered with @msg@.
-}
run :: OSC.Packet -> T () -> B.ByteString
run msg (Cons m) = Put.runPut (runReaderT m msg)