'  
'   Rebex Sample Code License
' 
'   Copyright 2026, REBEX CR s.r.o.
'   All rights reserved.
'   https://www.rebex.net/
' 
'   Permission to use, copy, modify, and/or distribute this software for any
'   purpose with or without fee is hereby granted.
' 
'   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
'   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
'   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
'   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
'   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
'   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
'   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
'   OTHER DEALINGS IN THE SOFTWARE.
' 

Imports System
Imports System.ComponentModel
Imports System.Threading.Tasks
Imports Rebex.Net
Imports Rebex.TerminalEmulation

''' <summary>
''' Telnet terminal emulator control.
''' </summary>
Partial Public Class TelnetTerminalControl
    Inherits TerminalControl

    Private _telnet As Telnet
    Private _serverName As String = ServerNameDefault
    Private _serverPort As Integer = ServerPortDefault
    Private _proxy As Proxy
    Private _logger As ILogWriter

    ' default values for both designer and properties
    Private Const ServerNameDefault As String = ""
    Private Const ServerPortDefault As Integer = Telnet.DefaultPort

    ''' <summary>
    ''' Gets or sets the server address - either a hostname or a dotted string IP address.
    ''' </summary>
    ''' <value>Server address.</value>
    <Description("Gets or sets the server address - either a hostname or a dotted string IP address.")>
    <DefaultValue(ServerNameDefault)>
    Public Property ServerName As String
        Get
            Return _serverName
        End Get
        Set(ByVal value As String)
            If Equals(value, Nothing) Then Throw New ArgumentNullException("value")
            _serverName = value
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the server port. Default value is 23.
    ''' </summary>
    ''' <value>Server port.</value>
    <DefaultValue(ServerPortDefault)>
    <Description("Gets or sets the server port. Default value is 23.")>
    Public Property ServerPort As Integer
        Get
            Return _serverPort
        End Get
        Set(ByVal value As Integer)
            _serverPort = value
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the network proxy to use to access a remote server.
    ''' </summary>
    ''' <value>The <see cref="Proxy"/> to use to access a remote server.</value>
    <Browsable(False)>
    <DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
    Public Property Proxy As Proxy
        Get
            Return _proxy
        End Get
        Set(ByVal value As Proxy)
            _proxy = value
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the text associated with this control.  
    ''' </summary>
    <Browsable(False)>
    <EditorBrowsable(EditorBrowsableState.Never)>
    <DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
    Public Overrides Property Text As String
        Get
            Return MyBase.Text
        End Get
        Set(ByVal value As String)
            MyBase.Text = value
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the logger used by this object.
    ''' </summary>
    ''' <value>Logger.</value>
    <DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
    Public Property LogWriter As ILogWriter
        Get
            Return _logger
        End Get
        Set(ByVal value As ILogWriter)
            _logger = value
            If _telnet IsNot Nothing Then _telnet.LogWriter = value
        End Set
    End Property

    ''' <summary>
    ''' Occurs when connected to the server.
    ''' </summary>
    Public Event Connected As EventHandler

    ''' <summary>
    ''' Raises the <see cref="Connected"/> event.
    ''' </summary>
    ''' <param name="e">An <see cref="EventArgs"/> that contains the event data.</param>
    Protected Overridable Sub OnConnected(ByVal e As EventArgs)
        Dim h As EventHandler = ConnectedEvent
        If h IsNot Nothing Then h(Me, e)
    End Sub

    ''' <summary>
    ''' Raises the <see cref="TerminalControl.Disconnected"/> event.
    ''' </summary>
    ''' <param name="e">An <see cref="EventArgs"/> that contains the event data.</param>
    Protected Overrides Sub OnDisconnected(ByVal e As EventArgs)
        MyBase.OnDisconnected(e)
        _telnet = Nothing
    End Sub

    ''' <summary>
    ''' Creates a new instance of Telnet terminal control.
    ''' </summary>
    Public Sub New()
        ' Set the default value to CRLF.
        ' The TerminalControl can be used not only for communicating
        ' with Telnet server, but also for connection to other server 
        ' types implementing text-based protocols such as FTP, SMTP, POP3,
        ' or IMAP. Some of those servers require CR LF line endings.
        Options.NewLineSequence = NewLineSequence.CRLF
    End Sub

    ''' <summary>
    ''' Connects to the Telnet server specified by <see cref="TelnetTerminalControl.ServerName"/> and <see cref="TelnetTerminalControl.ServerPort"/> properties.
    ''' </summary>
    Public Sub Connect()
        If _telnet IsNot Nothing Then Throw New TelnetException("Already connected to the server.")
        Dim serverName As String = _serverName.Trim()
        If serverName.Length = 0 Then Throw New TelnetException("Empty host name.")
        If _serverPort < 1 OrElse _serverPort > 65535 Then Throw New TelnetException("Port out of range.")
        ConnectSync(serverName, _serverPort)
    End Sub

    ''' <summary>
    ''' Begins asynchronous Connect operation.
    ''' Connects to the Telnet server specified by <see cref="TelnetTerminalControl.ServerName"/> and <see cref="TelnetTerminalControl.ServerPort"/> properties.
    ''' </summary>
    Public Function ConnectAsync() As Task
        If Not (_telnet Is Nothing) Then Throw New TelnetException("Already connected to the server.")

        Dim serverName As String = _serverName.Trim()
        If serverName.Length = 0 Then Throw New TelnetException("Empty host name.")
        If _serverPort < 1 Or _serverPort > 65535 Then Throw New TelnetException("Port out of range.")

        Return Task.Run(Sub() ConnectSync(serverName, _serverPort))
    End Function

    Private Sub ConnectSync(ByVal serverName As String, ByVal port As Integer)
        _telnet = New Telnet(serverName, port)
        _telnet.LogWriter = _logger
        _telnet.SetSocketFactory(_proxy)
        Dim ok As Boolean = False

        Try
            Bind(_telnet)
            ok = True
        Finally
            If Not ok Then _telnet = Nothing
        End Try

        If InvokeRequired Then
            Invoke(New Action(Of EventArgs)(AddressOf OnConnected), EventArgs.Empty)
        Else
            OnConnected(EventArgs.Empty)
        End If
    End Sub

    ''' <summary>
    ''' Disconnects from the Telnet server.
    ''' </summary>
    Public Sub Disconnect()
        Unbind()

        If _telnet IsNot Nothing Then
            _telnet = Nothing
            OnDisconnected(EventArgs.Empty)
        End If
    End Sub
End Class
