'
' Copyright (c) 2010 Apple Inc. All rights reserved.
'
' Licensed under the Apache License, Version 2.0 (the "License");
' you may not use this file except in compliance with the License.
' You may obtain a copy of the License at
' 
'     http://www.apache.org/licenses/LICENSE-2.0
' 
' Unless required by applicable law or agreed to in writing, software
' distributed under the License is distributed on an "AS IS" BASIS,
' WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
' See the License for the specific language governing permissions and
' limitations under the License.
'

Imports System.Net
Imports System.Net.Sockets
Imports System.Data
Imports System.Text

Public Class SimpleChat
    Public WithEvents MyEventManager As New Bonjour.DNSSDEventManager
    Private m_service As New Bonjour.DNSSDService
    Private m_registrar As Bonjour.DNSSDService
    Private m_browser As Bonjour.DNSSDService
    Private m_resolver As Bonjour.DNSSDService
    Private m_socket As New Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
    Private m_port As Integer
    Private m_buffer(1024 * 32) As Byte
    Private m_async As IAsyncResult
    Public Delegate Sub SocketDelegate(ByVal msg As String)
    Private m_socketDelegate As SocketDelegate
    Private m_name As String

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        Button1.Enabled = False

        m_socketDelegate = New SocketDelegate(AddressOf MessageReceived)

        Dim endPoint As New IPEndPoint(IPAddress.Any, 0)
        m_socket.Bind(endPoint)
        endPoint = m_socket.LocalEndPoint
        m_port = endPoint.Port

        Dim txtRecord As Bonjour.TXTRecord
        m_async = m_socket.BeginReceive(m_buffer, 0, m_buffer.Length, SocketFlags.Partial, New AsyncCallback(AddressOf OnReceive), Me)
        m_registrar = m_service.Register(0, 0, Environment.UserName, "_p2pchat._udp", vbNullString, vbNullString, m_port, txtRecord, MyEventManager)
    End Sub
    Public Sub MyEventManager_ServiceRegistered(ByVal registrar As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal name As String, ByVal regType As String, ByVal domain As String) Handles MyEventManager.ServiceRegistered
        m_name = name
        m_browser = m_service.Browse(0, 0, regType, vbNullString, MyEventManager)
    End Sub
    Public Sub MyEventManager_ServiceFound(ByVal browser As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal ifIndex As UInteger, ByVal serviceName As String, ByVal regtype As String, ByVal domain As String) Handles MyEventManager.ServiceFound
        If (serviceName <> m_name) Then
            Dim peer As PeerData = New PeerData
            peer.InterfaceIndex = ifIndex
            peer.Name = serviceName
            peer.Type = regtype
            peer.Domain = domain
            ComboBox1.Items.Add(peer)
            ComboBox1.SelectedIndex = 0
        End If
    End Sub
    Public Sub MyEventManager_ServiceLost(ByVal browser As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal ifIndex As UInteger, ByVal serviceName As String, ByVal regtype As String, ByVal domain As String) Handles MyEventManager.ServiceLost
        ComboBox1.Items.Remove(serviceName)
    End Sub
    Public Sub MyEventManager_ServiceResolved(ByVal resolver As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal ifIndex As UInteger, ByVal fullname As String, ByVal hostname As String, ByVal port As UShort, ByVal record As Bonjour.TXTRecord) Handles MyEventManager.ServiceResolved
        m_resolver.Stop()
        Dim peer As PeerData = ComboBox1.SelectedItem
        peer.Port = port
        m_resolver = m_service.QueryRecord(0, ifIndex, hostname, Bonjour.DNSSDRRType.kDNSSDType_A, Bonjour.DNSSDRRClass.kDNSSDClass_IN, MyEventManager)
    End Sub
    Public Sub MyEventManager_QueryAnswered(ByVal resolver As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal ifIndex As UInteger, ByVal fullName As String, ByVal rrtype As Bonjour.DNSSDRRType, ByVal rrclass As Bonjour.DNSSDRRClass, ByVal rdata As Object, ByVal ttl As UInteger) Handles MyEventManager.QueryRecordAnswered
        m_resolver.Stop()
        Dim peer As PeerData = ComboBox1.SelectedItem
        Dim bits As UInteger = BitConverter.ToUInt32(rdata, 0)
        Dim address As IPAddress = New System.Net.IPAddress(bits)
        peer.Address = address
    End Sub
    Public Sub MyEventManager_OperationFailed(ByVal registrar As Bonjour.DNSSDService, ByVal errorCode As Bonjour.DNSSDError) Handles MyEventManager.OperationFailed
        MessageBox.Show("Operation failed error code: " + errorCode)
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim peer As PeerData = ComboBox1.SelectedItem
        Dim message As String = m_name + ": " + TextBox2.Text
        Dim bytes As Byte() = Encoding.UTF8.GetBytes(message)
        Dim endPoint As IPEndPoint = New IPEndPoint(peer.Address, peer.Port)
        m_socket.SendTo(bytes, 0, bytes.Length, 0, endPoint)
        TextBox1.AppendText(TextBox2.Text + Environment.NewLine)
        TextBox2.Text = ""
    End Sub

    Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
        Dim peer As PeerData = ComboBox1.SelectedItem
        m_resolver = m_service.Resolve(0, peer.InterfaceIndex, peer.Name, peer.Type, peer.Domain, MyEventManager)
    End Sub
    Private Sub TextBox2_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox2.TextChanged
        Dim peer As PeerData = ComboBox1.SelectedItem
        If ((peer.Address IsNot Nothing) And TextBox2.Text.Length > 0) Then
            Button1.Enabled = True
        Else
            Button1.Enabled = False
        End If
    End Sub
    Public Sub MessageReceived(ByVal msg As System.String)
        TextBox1.AppendText(msg)
    End Sub
    Private Sub OnReceive(ByVal ar As IAsyncResult)
        Dim bytesReceived As Integer = m_socket.EndReceive(ar)
        If (bytesReceived > 0) Then
            Dim msg As String = Encoding.UTF8.GetString(m_buffer, 0, bytesReceived)
            Me.Invoke(m_socketDelegate, msg)
        End If
        m_async = m_socket.BeginReceive(m_buffer, 0, m_buffer.Length, SocketFlags.Partial, New AsyncCallback(AddressOf OnReceive), Me)
    End Sub
End Class

Public Class PeerData
    Public InterfaceIndex As UInteger
    Public Name As String
    Public Type As String
    Public Domain As String
    Public Address As IPAddress
    Public Port As UShort

    Overrides Function ToString() As String
        Return Name
    End Function
End Class
