module Sound.OSC.Transport.FD.TCP where
import qualified Control.Exception as Exception 
import qualified Data.ByteString.Lazy as B 
import qualified Network.Socket as N 
import qualified System.IO as IO 
import qualified Sound.OSC.Coding.Decode.Binary as Binary 
import qualified Sound.OSC.Coding.Encode.Builder as Builder 
import qualified Sound.OSC.Coding.Byte as Byte 
import qualified Sound.OSC.Coding.Convert as Convert 
import qualified Sound.OSC.Packet as Packet 
import qualified Sound.OSC.Transport.FD as FD 
data TCP = TCP {tcpHandle :: IO.Handle}
tcp_send_packet :: TCP -> Packet.Packet -> IO ()
tcp_send_packet (TCP fd) p = do
  let b = Builder.encodePacket p
      n = Convert.int64_to_word32 (B.length b)
  B.hPut fd (B.append (Byte.encode_word32 n) b)
  IO.hFlush fd
tcp_recv_packet :: TCP -> IO Packet.Packet
tcp_recv_packet (TCP fd) = do
  b0 <- B.hGet fd 4
  b1 <- B.hGet fd (Convert.word32_to_int (Byte.decode_word32 b0))
  return (Binary.decodePacket b1)
tcp_close :: TCP -> IO ()
tcp_close = IO.hClose . tcpHandle
instance FD.Transport TCP where
   sendPacket = tcp_send_packet
   recvPacket = tcp_recv_packet
   close = tcp_close
with_tcp :: IO TCP -> (TCP -> IO t) -> IO t
with_tcp u = Exception.bracket u tcp_close
tcp_socket :: (N.Socket -> N.SockAddr -> IO ()) -> Maybe String -> Int -> IO N.Socket
tcp_socket f host port = do
  fd <- N.socket N.AF_INET N.Stream 0
  i:_ <- N.getAddrInfo Nothing host (Just (show port))
  let sa = N.addrAddress i
  _ <- f fd sa
  return fd
socket_to_tcp :: N.Socket -> IO TCP
socket_to_tcp fd = fmap TCP (N.socketToHandle fd IO.ReadWriteMode)
tcp_handle :: (N.Socket -> N.SockAddr -> IO ()) -> String -> Int -> IO TCP
tcp_handle f host port = tcp_socket f (Just host) port >>= socket_to_tcp
openTCP :: String -> Int -> IO TCP
openTCP = tcp_handle N.connect
tcp_server_f :: N.Socket -> (TCP -> IO ()) -> IO ()
tcp_server_f s f = do
  (fd, _) <- N.accept s
  h <- socket_to_tcp fd
  f h
repeatM_ :: (Monad m) => m a -> m ()
repeatM_ = sequence_ . repeat
tcp_server :: Int -> (TCP -> IO ()) -> IO ()
tcp_server port f = do
  s <- tcp_socket N.bind Nothing port
  N.listen s 1
  repeatM_ (tcp_server_f s f)