Imports System.Net
Imports System.Net.Sockets

Namespace Net

    ''' <summary>
    ''' A set of functions for working with the TCP protocol.
    ''' </summary>
    ''' <remarks></remarks>
    Public NotInheritable Class TcpHelper

        Private Shared _lastError As Exception

        ''' <summary>
        ''' Gets the last error value that occurred while using the <see cref="Mercury.Mobile.Net.TcpHelper"/> connection methods.
        ''' </summary>
        ''' <returns>The last error value that occurred while using the <see cref="Mercury.Mobile.Net.TcpHelper"/> connection methods.</returns>
        ''' <remarks></remarks>
        Public Shared ReadOnly Property LastError As Exception
            Get
                Return _lastError
            End Get
        End Property

        ''' <summary>
        ''' Returns a newly created socket that has been connected 
        ''' to the end point at the specified host and port.
        ''' </summary>
        ''' <param name="host">The name of the host server, or the string representation of its IP address.</param>
        ''' <param name="port">The port number on which to connect.</param>
        ''' <returns>A newly created socket that has been connected to the 
        ''' end point at the specified host and port or null.</returns>
        ''' <remarks></remarks>
        Public Shared Function Connect(ByVal host As String, ByVal port As Integer) As Socket
            Dim hostEntry = Dns.GetHostEntry(host)
            For Each address As IPAddress In hostEntry.AddressList
                Dim temp = TcpHelper.Connect(New IPEndPoint(address, port))
                If (temp IsNot Nothing) Then _
                    Return temp
            Next
            Return Nothing
        End Function

        ''' <summary>
        ''' Returns a newly created socket that has been connected 
        ''' to the end point at the specified IP address and port.
        ''' </summary>
        ''' <param name="ipAddress">The IP address represented as a 64-bit integer.</param>
        ''' <param name="port">The port number on which to connect.</param>
        ''' <returns>A newly created socket that has been connected to the 
        ''' end point at the specified IP address and port or null.</returns>
        ''' <remarks></remarks>
        Public Shared Function Connect(ByVal ipAddress As Long, ByVal port As Integer) As Socket
            Return TcpHelper.Connect(New IPEndPoint(ipAddress, port))
        End Function

        ''' <summary>
        ''' Returns a newly created socket that has been connected to the specified end point.
        ''' </summary>
        ''' <param name="endPoint">The IP end point on which to connect.</param>
        ''' <returns>A socket that has been created for and connected to the specified end point or null.</returns>
        ''' <remarks></remarks>
        Public Shared Function Connect(ByVal endPoint As IPEndPoint) As Socket
            If endPoint IsNot Nothing Then
                ' Generate socket
                Dim temp = TcpHelper.GetSocket(endPoint, SocketType.Stream)

                ' Attempt to connect
                Dim flag = TcpHelper.TryConnectSocket(temp, endPoint, Nothing)
                If (flag) Then _
                    Return temp
            End If
            Return Nothing
        End Function

        ''' <summary>
        ''' Returns a socket created from the specified IP address, port and socket type.
        ''' </summary>
        ''' <param name="ipAddress">The IP address represented as a 64-bit integer.</param>
        ''' <param name="port">The port number on which to connect.</param>
        ''' <param name="type">The type of socket to create.</param>
        ''' <returns>A socket created from the specified IP address, port and socket type.</returns>
        ''' <remarks></remarks>
        Public Shared Function GetSocket(ByVal ipAddress As Long, ByVal port As Integer, ByVal type As SocketType) As Socket
            Return TcpHelper.GetSocket(New IPEndPoint(ipAddress, port), type)
        End Function

        ''' <summary>
        ''' Returns a socket created from the specified end point and socket type.
        ''' </summary>
        ''' <param name="endPoint">The IP end point to use.</param>
        ''' <param name="type">The type of socket to create.</param>
        ''' <returns>A socket created from the specified end point and socket type.</returns>
        ''' <remarks></remarks>
        Public Shared Function GetSocket(ByVal endPoint As IPEndPoint, ByVal type As SocketType) As Socket
            Return New Socket(endPoint.AddressFamily, type, ProtocolType.Tcp)
        End Function

        ''' <summary>
        ''' Attempts to connect the specified socket to the specified end point.
        ''' </summary>
        ''' <param name="socket">The socket to connect.</param>
        ''' <param name="endPoint">The IP end point on which to connect.</param>
        ''' <param name="exception">Out. An exception that occurred during the connection process.</param>
        ''' <returns>True if the the socket was able to connect; otherwise, false.</returns>
        ''' <remarks></remarks>
        Public Shared Function TryConnectSocket(ByVal socket As Socket, ByVal endPoint As IPEndPoint, ByRef exception As Exception) As Boolean
            If socket Is Nothing Then _
                Throw New ArgumentNullException("socket")
            If endPoint Is Nothing Then _
                Throw New ArgumentNullException("endPoint")

            Try
                socket.Connect(endPoint)
            Catch ex As Exception
                exception = ex
                TcpHelper._lastError = ex
                Return False
            End Try

            Return socket.Connected
        End Function

    End Class

End Namespace