readMessage :: Net.PalaceConnection -> Net.PalaceMessageConverters -> Inbound.Header -> IO Inbound.InboundMessage
readMessage connection messageConverters header =
  let messageType = Inbound.messageType header
      byteSource = Net.palaceByteSource connection
      readByte = Receive.readByteFromNetwork byteSource
      readBytes = Receive.readBytesFromNetwork byteSource
      readShort = Receive.readShortFromNetwork (Net.palaceShortReader messageConverters) byteSource
      readInt = Receive.readIntFromNetwork (Net.palaceIntReader messageConverters) byteSource
      readText = Receive.readTextFromNetwork byteSource
      readNullTerminatedText = Receive.readNullTerminatedTextFromNetwork byteSource
      
  in case messageType of
    PalaceMsgTypes.BigEndianServer    -> readHandshake PalaceMsgTypes.BigEndianServer connection header
    PalaceMsgTypes.LittleEndianServer -> readHandshake PalaceMsgTypes.LittleEndianServer connection header
    PalaceMsgTypes.UnknownServer      -> readHandshake PalaceMsgTypes.UnknownServer connection header
    PalaceMsgTypes.AlternateLogonReply -> readAlternateLogonReply readByte readShort readInt readText
    PalaceMsgTypes.ServerVersion -> readServerVersion header
    PalaceMsgTypes.ServerInfo -> readServerInfo readByte readInt readText
    PalaceMsgTypes.UserStatus -> readUserStatus readBytes readShort header
    PalaceMsgTypes.UserLoggedOnAndMax -> readUserLogonNotification readInt header
    PalaceMsgTypes.GotHttpServerLocation -> readMediaServerInfo readNullTerminatedText header
    PalaceMsgTypes.GotRoomDescription -> readRoomDescription readBytes readShort readInt header
    PalaceMsgTypes.GotUserList -> readUserList readByte readBytes readShort readInt readText header
    PalaceMsgTypes.RoomDescend -> return $ Inbound.NoOpMessage (Inbound.NoOp $ show messageType)
    -- RoomDescend message just means we're done receiving the room description & user list
    PalaceMsgTypes.UserNew -> readUserEnteredRoomNotification readByte readBytes readShort readInt readText
    -- End logon sequence

    PalaceMsgTypes.Talk -> readTalk readNullTerminatedText header Inbound.PublicChat
    PalaceMsgTypes.CrossRoomWhisper -> readTalk readNullTerminatedText header Inbound.PrivateChat
    PalaceMsgTypes.Say -> readEncodedTalk readBytes readShort header Inbound.PublicChat
    PalaceMsgTypes.Whisper -> readEncodedTalk readBytes readShort header Inbound.PrivateChat
    PalaceMsgTypes.Move -> readMovement readShort header

    PalaceMsgTypes.UserExitRoom -> readUserExitedRoomNotification header
    PalaceMsgTypes.UserLeaving -> readUserDisconnectedNotification readInt header

    PalaceMsgTypes.Superuser -> readUnknownMessage readBytes header
    PalaceMsgTypes.SusrMsg -> readUnknownMessage readBytes header
    PalaceMsgTypes.GlobalMsg -> readUnknownMessage readBytes header
    PalaceMsgTypes.RoomMsg -> readUnknownMessage readBytes header

    PalaceMsgTypes.GotRoomDescriptionAlt -> readUnknownMessage readBytes header
    PalaceMsgTypes.RequestRoomList -> readUnknownMessage readBytes header
    PalaceMsgTypes.GotRoomList -> readUnknownMessage readBytes header
    PalaceMsgTypes.GotReplyOfAllRooms -> readUnknownMessage readBytes header
    PalaceMsgTypes.RequestUserList -> readUnknownMessage readBytes header
    PalaceMsgTypes.GotReplyOfAllUsers -> readUnknownMessage readBytes header

    PalaceMsgTypes.Logon -> readUnknownMessage readBytes header
    PalaceMsgTypes.Authenticate -> readUnknownMessage readBytes header
    PalaceMsgTypes.Authresponse -> readUnknownMessage readBytes header
    PalaceMsgTypes.Bye -> readUnknownMessage readBytes header

    PalaceMsgTypes.ChangeName -> readUnknownMessage readBytes header
    PalaceMsgTypes.UserRename -> readUnknownMessage readBytes header
    PalaceMsgTypes.UserDescription -> readUnknownMessage readBytes header
    PalaceMsgTypes.UserColor -> readUnknownMessage readBytes header
    PalaceMsgTypes.UserFace -> readUnknownMessage readBytes header
    PalaceMsgTypes.UserProp -> readUnknownMessage readBytes header
    PalaceMsgTypes.GotoRoom -> readUnknownMessage readBytes header
    PalaceMsgTypes.Blowthru -> readUnknownMessage readBytes header
    PalaceMsgTypes.NavError -> readUnknownMessage readBytes header

    PalaceMsgTypes.PropNew -> readUnknownMessage readBytes header
    PalaceMsgTypes.PropMove -> readUnknownMessage readBytes header
    PalaceMsgTypes.PropDelete -> readUnknownMessage readBytes header
    PalaceMsgTypes.PictMove -> readUnknownMessage readBytes header

    PalaceMsgTypes.IncomingFile -> readUnknownMessage readBytes header
    PalaceMsgTypes.RequestAsset -> readUnknownMessage readBytes header
    PalaceMsgTypes.AssetQuery -> readUnknownMessage readBytes header
    PalaceMsgTypes.AssetIncoming -> readUnknownMessage readBytes header
    PalaceMsgTypes.AssetRegi -> readUnknownMessage readBytes header

    PalaceMsgTypes.DoorLock -> readUnknownMessage readBytes header
    PalaceMsgTypes.DoorUnlock -> readUnknownMessage readBytes header
    PalaceMsgTypes.SpotState -> readUnknownMessage readBytes header
    PalaceMsgTypes.SpotMove -> readUnknownMessage readBytes header

    PalaceMsgTypes.Draw -> readUnknownMessage readBytes header
    PalaceMsgTypes.DrawCmd -> readUnknownMessage readBytes header
    
    PalaceMsgTypes.Pinged -> readUnknownMessage readBytes header
    PalaceMsgTypes.PingBack -> readUnknownMessage readBytes header
    PalaceMsgTypes.ServerDown -> readUnknownMessage readBytes header
    PalaceMsgTypes.ConnectionDied -> readUnknownMessage readBytes header

    PalaceMsgTypes.UnknownMessage -> readUnknownMessage readBytes header
readMessage :: Net.PalaceConnection -> Net.PalaceMessageConverters -> Inbound.Header -> IO Inbound.InboundMessage
readMessage connection messageConverters header =
  let messageType = Inbound.messageType header
      byteSource = Net.palaceByteSource connection
      readByte = Receive.readByteFromNetwork byteSource
      readBytes = Receive.readBytesFromNetwork byteSource
      readShort = Receive.readShortFromNetwork (Net.palaceShortReader messageConverters) byteSource
      readInt = Receive.readIntFromNetwork (Net.palaceIntReader messageConverters) byteSource
      readText = Receive.readTextFromNetwork byteSource
      readNullTerminatedText = Receive.readNullTerminatedTextFromNetwork byteSource
      
  in case messageType of
    PalaceMsgTypes.BigEndianServer    -> readHandshake PalaceMsgTypes.BigEndianServer connection header
    PalaceMsgTypes.LittleEndianServer -> readHandshake PalaceMsgTypes.LittleEndianServer connection header
    PalaceMsgTypes.UnknownServer      -> readHandshake PalaceMsgTypes.UnknownServer connection header
    PalaceMsgTypes.AlternateLogonReply -> readAlternateLogonReply readByte readShort readInt readText
    PalaceMsgTypes.ServerVersion -> readServerVersion header
    PalaceMsgTypes.ServerInfo -> readServerInfo readByte readInt readText
    PalaceMsgTypes.UserStatus -> readUserStatus readBytes readShort header
    PalaceMsgTypes.UserLoggedOnAndMax -> readUserLogonNotification readInt header
    PalaceMsgTypes.GotHttpServerLocation -> readMediaServerInfo readNullTerminatedText header
    PalaceMsgTypes.GotRoomDescription -> readRoomDescription readBytes readShort readInt header
    PalaceMsgTypes.GotUserList -> readUserList readByte readBytes readShort readInt readText header
    PalaceMsgTypes.RoomDescend -> return $ Inbound.NoOpMessage (Inbound.NoOp $ show messageType)
    -- RoomDescend message just means we're done receiving the room description & user list
    PalaceMsgTypes.UserNew -> readUserEnteredRoomNotification readByte readBytes readShort readInt readText
    -- End logon sequence

    PalaceMsgTypes.Talk -> readTalk readNullTerminatedText header Inbound.PublicChat
    PalaceMsgTypes.CrossRoomWhisper -> readTalk readNullTerminatedText header Inbound.PrivateChat
    PalaceMsgTypes.Say -> readEncodedTalk readBytes readShort header Inbound.PublicChat
    PalaceMsgTypes.Whisper -> readEncodedTalk readBytes readShort header Inbound.PrivateChat
    PalaceMsgTypes.Move -> readMovement readShort header

    PalaceMsgTypes.UserExitRoom -> readUserExitedRoomNotification header
    PalaceMsgTypes.UserLeaving -> readUserDisconnectedNotification readInt header

    PalaceMsgTypes.Superuser -> readUnknownMessage readBytes header
    PalaceMsgTypes.SusrMsg -> readUnknownMessage readBytes header
    PalaceMsgTypes.GlobalMsg -> readUnknownMessage readBytes header
    PalaceMsgTypes.RoomMsg -> readUnknownMessage readBytes header

    PalaceMsgTypes.GotRoomDescriptionAlt -> readUnknownMessage readBytes header
    PalaceMsgTypes.RequestRoomList -> readUnknownMessage readBytes header
    PalaceMsgTypes.GotRoomList -> readUnknownMessage readBytes header
    PalaceMsgTypes.GotReplyOfAllRooms -> readUnknownMessage readBytes header
    PalaceMsgTypes.RequestUserList -> readUnknownMessage readBytes header
    PalaceMsgTypes.GotReplyOfAllUsers -> readUnknownMessage readBytes header

    PalaceMsgTypes.Logon -> readUnknownMessage readBytes header
    PalaceMsgTypes.Authenticate -> readUnknownMessage readBytes header
    PalaceMsgTypes.Authresponse -> readUnknownMessage readBytes header
    PalaceMsgTypes.Bye -> readUnknownMessage readBytes header

    PalaceMsgTypes.ChangeName -> readUnknownMessage readBytes header
    PalaceMsgTypes.UserRename -> readUnknownMessage readBytes header
    PalaceMsgTypes.UserDescription -> readUnknownMessage readBytes header
    PalaceMsgTypes.UserColor -> readUnknownMessage readBytes header
    PalaceMsgTypes.UserFace -> readUnknownMessage readBytes header
    PalaceMsgTypes.UserProp -> readUnknownMessage readBytes header
    PalaceMsgTypes.GotoRoom -> readUnknownMessage readBytes header
    PalaceMsgTypes.Blowthru -> readUnknownMessage readBytes header
    PalaceMsgTypes.NavError -> readUnknownMessage readBytes header

    PalaceMsgTypes.PropNew -> readUnknownMessage readBytes header
    PalaceMsgTypes.PropMove -> readUnknownMessage readBytes header
    PalaceMsgTypes.PropDelete -> readUnknownMessage readBytes header
    PalaceMsgTypes.PictMove -> readUnknownMessage readBytes header

    PalaceMsgTypes.IncomingFile -> readUnknownMessage readBytes header
    PalaceMsgTypes.RequestAsset -> readUnknownMessage readBytes header
    PalaceMsgTypes.AssetQuery -> readUnknownMessage readBytes header
    PalaceMsgTypes.AssetIncoming -> readUnknownMessage readBytes header
    PalaceMsgTypes.AssetRegi -> readUnknownMessage readBytes header

    PalaceMsgTypes.DoorLock -> readUnknownMessage readBytes header
    PalaceMsgTypes.DoorUnlock -> readUnknownMessage readBytes header
    PalaceMsgTypes.SpotState -> readUnknownMessage readBytes header
    PalaceMsgTypes.SpotMove -> readUnknownMessage readBytes header

    PalaceMsgTypes.Draw -> readUnknownMessage readBytes header
    PalaceMsgTypes.DrawCmd -> readUnknownMessage readBytes header
    
    PalaceMsgTypes.Pinged -> readUnknownMessage readBytes header
    PalaceMsgTypes.PingBack -> readUnknownMessage readBytes header
    PalaceMsgTypes.ServerDown -> readUnknownMessage readBytes header
    PalaceMsgTypes.ConnectionDied -> readUnknownMessage readBytes header

    PalaceMsgTypes.UnknownMessage -> readUnknownMessage readBytes header
readMessage connection messageConverters header =
  let messageType = Inbound.messageType header
      byteSource = Net.palaceByteSource connection
      readByte = Receive.readByteFromNetwork byteSource
      readBytes = Receive.readBytesFromNetwork byteSource
      readShort = Receive.readShortFromNetwork (Net.palaceShortReader messageConverters) byteSource
      readInt = Receive.readIntFromNetwork (Net.palaceIntReader messageConverters) byteSource
      readText = Receive.readTextFromNetwork byteSource
      readNullTerminatedText = Receive.readNullTerminatedTextFromNetwork byteSource
      
  in case messageType of
    PalaceMsgTypes.BigEndianServer    -> readHandshake PalaceMsgTypes.BigEndianServer connection header
    PalaceMsgTypes.LittleEndianServer -> readHandshake PalaceMsgTypes.LittleEndianServer connection header
    PalaceMsgTypes.UnknownServer      -> readHandshake PalaceMsgTypes.UnknownServer connection header
    PalaceMsgTypes.AlternateLogonReply -> readAlternateLogonReply readByte readShort readInt readText
    PalaceMsgTypes.ServerVersion -> readServerVersion header
    PalaceMsgTypes.ServerInfo -> readServerInfo readByte readInt readText
    PalaceMsgTypes.UserStatus -> readUserStatus readBytes readShort header
    PalaceMsgTypes.UserLoggedOnAndMax -> readUserLogonNotification readInt header
    PalaceMsgTypes.GotHttpServerLocation -> readMediaServerInfo readNullTerminatedText header
    PalaceMsgTypes.GotRoomDescription -> readRoomDescription readBytes readShort readInt header
    PalaceMsgTypes.GotUserList -> readUserList readByte readBytes readShort readInt readText header
    PalaceMsgTypes.RoomDescend -> return $ Inbound.NoOpMessage (Inbound.NoOp $ show messageType)
    -- RoomDescend message just means we're done receiving the room description & user list
    PalaceMsgTypes.UserNew -> readUserEnteredRoomNotification readByte readBytes readShort readInt readText
    -- End logon sequence

    PalaceMsgTypes.Talk -> readTalk readNullTerminatedText header Inbound.PublicChat
    PalaceMsgTypes.CrossRoomWhisper -> readTalk readNullTerminatedText header Inbound.PrivateChat
    PalaceMsgTypes.Say -> readEncodedTalk readBytes readShort header Inbound.PublicChat
    PalaceMsgTypes.Whisper -> readEncodedTalk readBytes readShort header Inbound.PrivateChat
    PalaceMsgTypes.Move -> readMovement readShort header

    PalaceMsgTypes.UserExitRoom -> readUserExitedRoomNotification header
    PalaceMsgTypes.UserLeaving -> readUserDisconnectedNotification readInt header

    PalaceMsgTypes.Superuser -> readUnknownMessage readBytes header
    PalaceMsgTypes.SusrMsg -> readUnknownMessage readBytes header
    PalaceMsgTypes.GlobalMsg -> readUnknownMessage readBytes header
    PalaceMsgTypes.RoomMsg -> readUnknownMessage readBytes header

    PalaceMsgTypes.GotRoomDescriptionAlt -> readUnknownMessage readBytes header
    PalaceMsgTypes.RequestRoomList -> readUnknownMessage readBytes header
    PalaceMsgTypes.GotRoomList -> readUnknownMessage readBytes header
    PalaceMsgTypes.GotReplyOfAllRooms -> readUnknownMessage readBytes header
    PalaceMsgTypes.RequestUserList -> readUnknownMessage readBytes header
    PalaceMsgTypes.GotReplyOfAllUsers -> readUnknownMessage readBytes header

    PalaceMsgTypes.Logon -> readUnknownMessage readBytes header
    PalaceMsgTypes.Authenticate -> readUnknownMessage readBytes header
    PalaceMsgTypes.Authresponse -> readUnknownMessage readBytes header
    PalaceMsgTypes.Bye -> readUnknownMessage readBytes header

    PalaceMsgTypes.ChangeName -> readUnknownMessage readBytes header
    PalaceMsgTypes.UserRename -> readUnknownMessage readBytes header
    PalaceMsgTypes.UserDescription -> readUnknownMessage readBytes header
    PalaceMsgTypes.UserColor -> readUnknownMessage readBytes header
    PalaceMsgTypes.UserFace -> readUnknownMessage readBytes header
    PalaceMsgTypes.UserProp -> readUnknownMessage readBytes header
    PalaceMsgTypes.GotoRoom -> readUnknownMessage readBytes header
    PalaceMsgTypes.Blowthru -> readUnknownMessage readBytes header
    PalaceMsgTypes.NavError -> readUnknownMessage readBytes header

    PalaceMsgTypes.PropNew -> readUnknownMessage readBytes header
    PalaceMsgTypes.PropMove -> readUnknownMessage readBytes header
    PalaceMsgTypes.PropDelete -> readUnknownMessage readBytes header
    PalaceMsgTypes.PictMove -> readUnknownMessage readBytes header

    PalaceMsgTypes.IncomingFile -> readUnknownMessage readBytes header
    PalaceMsgTypes.RequestAsset -> readUnknownMessage readBytes header
    PalaceMsgTypes.AssetQuery -> readUnknownMessage readBytes header
    PalaceMsgTypes.AssetIncoming -> readUnknownMessage readBytes header
    PalaceMsgTypes.AssetRegi -> readUnknownMessage readBytes header

    PalaceMsgTypes.DoorLock -> readUnknownMessage readBytes header
    PalaceMsgTypes.DoorUnlock -> readUnknownMessage readBytes header
    PalaceMsgTypes.SpotState -> readUnknownMessage readBytes header
    PalaceMsgTypes.SpotMove -> readUnknownMessage readBytes header

    PalaceMsgTypes.Draw -> readUnknownMessage readBytes header
    PalaceMsgTypes.DrawCmd -> readUnknownMessage readBytes header
    
    PalaceMsgTypes.Pinged -> readUnknownMessage readBytes header
    PalaceMsgTypes.PingBack -> readUnknownMessage readBytes header
    PalaceMsgTypes.ServerDown -> readUnknownMessage readBytes header
    PalaceMsgTypes.ConnectionDied -> readUnknownMessage readBytes header

    PalaceMsgTypes.UnknownMessage -> readUnknownMessage readBytes header