'  
'   Rebex Sample Code License
' 
'   Copyright 2025, 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.Collections.Generic
Imports System.ComponentModel
Imports System.Reflection
Imports System.Windows.Forms
Imports Rebex.Net

Friend NotInheritable Class ConnectionEditorUtils
    Private Sub New()
    End Sub
    Public Const FtpDefaultPort As Integer = 21
    Public Const FtpDefaultImplicitSslPort As Integer = 990
    Public Const SftpDefaultPort As Integer = 22
    Public Const MinPort As Integer = 1
    Public Const MaxPort As Integer = &Hffff

    ''' <summary>
    ''' Binds list of given ComboBox to some values of given enum.<br/>
    ''' (DataMember uses enum VALUES, DisplayMember uses enum NAMES or DESCRIPTIONS (if available).
    ''' </summary>
    ''' <typeparam name="EnumType">Type of enum the values are taken from.</typeparam>
    ''' <param name="combo">Instance of ComboBox to bind into.</param>
    ''' <param name="excludeValues">Collection of enum values that will be excluded from the bound values.<br/>May be null or empty.</param>
    Public Shared Sub BindComboWithEnum(Of EnumType)(combo As ComboBox, excludeValues As ICollection(Of EnumType))
        If excludeValues Is Nothing Then
            excludeValues = New List(Of EnumType)()
        End If

        Dim lst As New List(Of Tuple(Of EnumType, String))()
        For Each value As EnumType In [Enum].GetValues(GetType(EnumType))
            If Not excludeValues.Contains(value) Then
                lst.Add(New Tuple(Of EnumType, String)(value, GetEnumValueDescription(value)))
            End If
        Next

        combo.ValueMember = "First"
        combo.DisplayMember = "Second"
        combo.DataSource = lst
    End Sub
    ''' <summary>
    ''' Returns value of <see cref="DescriptionAttribute"/> placed on given enum field.<br/>
    ''' If there is no <see cref="DescriptionAttribute"/> on that field, a field name is returned.
    ''' </summary>
    ''' <typeparam name="T">Enum type</typeparam>
    ''' <returns>Field name or field description, never null.</returns>
    Friend Shared Function GetEnumValueDescription(Of T)(value As T) As String
        Dim field As FieldInfo = value.[GetType]().GetField(value.ToString())
        Dim attrib As DescriptionAttribute = TryCast(Attribute.GetCustomAttribute(field, GetType(DescriptionAttribute)), DescriptionAttribute)
        Dim returnValue As String
        If attrib Is Nothing Then
            returnValue = value.ToString()
        Else
            returnValue = attrib.Description
        End If

        Return returnValue
    End Function

    ''' <summary>
    ''' Encapsluates side effects when setting the protocol.
    ''' </summary>
    ''' <param name="oldMode">Current protocol mode.</param>
    ''' <param name="newMode">New protocol mode to be set.</param>
    ''' <param name="setProtocolDelegate">Delegate that sets the protocol to the target property.</param>
    ''' <param name="serverPort">Current value of server port.</param>
    ''' <param name="setServerPortDelegate">Delegate that sets the port to the target property.</param>
    ''' <param name="proxyType">Current value of proxy type.</param>
    ''' <param name="setProxyTypeDelegate">Delegate that sets the proxy type to the target property.</param>
    Public Shared Sub SetProtocol(oldMode As FileTransferMode, newMode As FileTransferMode, setProtocolDelegate As Action(Of FileTransferMode), serverPort As Integer, setServerPortDelegate As Action(Of Integer), proxyType As FileTransferProxyType, _
        setProxyTypeDelegate As Action(Of FileTransferProxyType))
        Dim newServerPort As Integer = serverPort
        Dim newProxyType As FileTransferProxyType = proxyType
        ' if the previous protocol uses it's default port...
        If serverPort = 0 OrElse (oldMode = FileTransferMode.Ftp AndAlso serverPort = FtpDefaultPort) OrElse (oldMode = FileTransferMode.FtpSslExplicit AndAlso serverPort = FtpDefaultPort) OrElse (oldMode = FileTransferMode.FtpSslImplicit AndAlso serverPort = FtpDefaultImplicitSslPort) OrElse (oldMode = FileTransferMode.Sftp AndAlso serverPort = SftpDefaultPort) Then
            ' ...set the default port also for the new protocol
            Select Case newMode
                Case FileTransferMode.Ftp, FileTransferMode.FtpSslExplicit
                    newServerPort = FtpDefaultPort
                    Exit Select
                Case FileTransferMode.FtpSslImplicit
                    newServerPort = FtpDefaultImplicitSslPort
                    Exit Select
                Case FileTransferMode.Sftp
                    newServerPort = SftpDefaultPort
                    Exit Select
            End Select
        End If

        ' if the current proxy is not supported by the new protocol...
        If Not IsProxySupported(proxyType, newMode) Then
            ' ... reset the new proxy type to None
            newProxyType = FileTransferProxyType.None
        End If

        If newMode <> oldMode Then
            setProtocolDelegate(newMode)
        End If
        If newServerPort <> serverPort Then
            setServerPortDelegate(newServerPort)
        End If
        If newProxyType <> proxyType Then
            setProxyTypeDelegate(newProxyType)
        End If

    End Sub

    ''' <summary>
    ''' Decides whether given <paramref name="proxyType"/> is supported in used <paramref name="mode"/>.
    ''' </summary>
    Public Shared Function IsProxySupported(proxyType As FileTransferProxyType, mode As FileTransferMode) As Boolean
        Select Case mode
            Case FileTransferMode.Ftp
                Return True
            ' all proxy types are supported
            Case FileTransferMode.FtpSslExplicit, FileTransferMode.FtpSslImplicit
                Return (proxyType <> FileTransferProxyType.FtpUser)
            Case FileTransferMode.Sftp
                Return (proxyType <> FileTransferProxyType.FtpOpen AndAlso proxyType <> FileTransferProxyType.FtpSite AndAlso proxyType <> FileTransferProxyType.FtpUser)
            Case Else
                Throw New ArgumentException(String.Format("Unsupported enum value {0}.", mode), "protocol")
        End Select

    End Function

    Public Shared Sub ShowException(message As String, caption As String, ex As Exception)
        MessageBox.Show(String.Format("{0}" & vbCr & vbLf & "{1}" & vbCr & vbLf & "{2}", message, "Detailed description:", ex.Message), caption, MessageBoxButtons.OK, MessageBoxIcon.[Error])
    End Sub

    Public Shared Sub ShowWarning(message As String, caption As String)
        MessageBox.Show(message, caption, MessageBoxButtons.OK, MessageBoxIcon.Warning)
    End Sub

End Class

Friend Class Tuple(Of T1, T2)
    Public ReadOnly Property First() As T1
        Get
            Return _first
        End Get
    End Property
    Private ReadOnly _first As T1
    Public ReadOnly Property Second() As T2
        Get
            Return _second
        End Get
    End Property
    Private ReadOnly _second As T2
    Public Sub New(first As T1, second As T2)
        _first = first
        _second = second
    End Sub
End Class

