{-# LANGUAGE ScopedTypeVariables #-}
module Network.ADB.Transport where


import Control.Exception
import Control.Monad.Error
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as C
import Data.Monoid
import Network.Socket.ByteString
import System.IO.Error (IOError(..))
import Prelude hiding (read)


-- | \'m\' is the monad to to run it in, \'h\' is the heuristic value which, where
-- \'e\' is 'ByteString', is the number of bytes to read.  \'e\' is the stream
-- element type.
data Transport m = Transport {
        write :: ByteString -> m (),  -- ^ Write an item.
        read  :: Int -> m ByteString, -- ^ Read an item with 'h' being the heuristic to say what it
                                      -- is we want to read.
        close :: m ()
    }

data TransportError = ADBFailure String
                    | SocketFailure IOError
                    | ConnectionFailure ByteString
                    | ClosedByPeer
                    | IllegalData
    deriving Show

instance Error TransportError where
    noMsg = IllegalData
    strMsg _ = IllegalData

-- | Block until the specified number of bytes has been read.
readFully :: Monad m => Transport m -> Int -> m ByteString
readFully rem n = doRecv C.empty
  where
    doRecv sofar | C.length sofar == n = return sofar
    doRecv sofar = do
        blk <- read rem (n - C.length sofar)
        doRecv (sofar `mappend` blk)