'  
'   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.Xml
Imports System.IO
Imports Rebex.Net
Imports System.Text

''' <summary>
''' ConnectionEditor data extended for specific fields and operations used in file-transfer samples.
''' </summary>
Public Class ConnectionFormData
    Inherits ConnectionData
    Private ReadOnly _supportedComponents As FileTransferComponent

    Public ReadOnly Property SupportedComponents() As FileTransferComponent
        Get
            Return _supportedComponents
        End Get
    End Property

    Public Property LogLevel() As LogLevel
        Get
            Return _logLevel
        End Get
        Set
            _logLevel = value
        End Set
    End Property
    Private _logLevel As LogLevel

    ''' <summary>
    ''' Create a new instance and fill it with defaults.
    ''' </summary>
    Public Sub New(suppComponents As FileTransferComponent)
        _supportedComponents = suppComponents

        ' set defaults
        LogLevel = LogLevel.Info
        ServerHost = "test.rebex.net"

        If (SupportedComponents And FileTransferComponent.Ftp) <> 0 Then
            FileTransferMode = FileTransferMode.Ftp
            ServerPort = ConnectionEditorUtils.FtpDefaultPort
        Else
            FileTransferMode = FileTransferMode.Sftp
            ServerPort = ConnectionEditorUtils.SftpDefaultPort
        End If

        ServerUser = "demo"
        ServerPassword = "password"
        PassiveMode = True
        ProxyType = FileTransferProxyType.None

        ServerCertificateVerifyingMode = CertificateVerifyingMode.UseWindowsInfrastructure
        TlsProtocol = TlsVersion.TLS13 Or TlsVersion.TLS12

        ServerKeyVerifyingMode = KeyVerifyingMode.LocalyStoredFingerprint
    End Sub

    ''' <summary>
    ''' Load data from a component-specific config file 
    ''' </summary>
    Public Sub LoadConfig()
        Dim proxyTypeSet As Boolean = False

        Dim xml As New XmlDocument()
        If Not File.Exists(ConfigFile) Then
            Return
        End If

        xml.Load(ConfigFile)

        Dim config As XmlElement = xml("configuration")
        For Each key As XmlNode In config.ChildNodes
            Dim item As String = Nothing
            Dim name As String = Nothing
            If key.Attributes("value") IsNot Nothing Then
                item = key.Attributes("value").Value
            End If
            If key.Attributes("name") IsNot Nothing Then
                name = key.Attributes("name").Value
            End If
            If key("value") IsNot Nothing Then
                item = key("value").InnerText
            End If
            If key("name") IsNot Nothing Then
                name = key("name").InnerText
            End If

            If name Is Nothing Then
                Continue For
            End If
            If item Is Nothing Then
                item = ""
            End If

            Select Case name
                Case "loglevel"
                    LogLevel = ToEnum(item, LogLevel)
                    Exit Select
                Case "fileTransferMode"
                    FileTransferMode = ToEnum(item, FileTransferMode)
                    Exit Select
                Case "host"
                    ServerHost = item
                    Exit Select
                Case "login"
                    ServerUser = item
                    Exit Select
                Case "port"
                    ServerPort = ToInt(item, ServerPort)
                    Exit Select
                Case "gssApi"
                    If item.ToLower() = "false" Then
                        UseGssApi = False
                    Else
                        UseGssApi = True
                    End If
                    Exit Select
                Case "domain"
                    ServerDomain = item
                    Exit Select
                Case "password"
                    ServerPassword = item
                    StorePassword = Not String.IsNullOrEmpty(ServerPassword)
                    Exit Select
                Case "passive"
                    If item.ToLower() = "false" Then
                        PassiveMode = False
                    Else
                        PassiveMode = True
                    End If
                    Exit Select
                Case "proxytype"
                    If Not proxyTypeSet Then
                        ProxyType = ToEnum(item, ProxyType)
                    End If
                    Exit Select
                Case "proxy"
                    ProxyHost = item
                    Exit Select
                Case "proxyport"
                    ProxyPort = ToInt(item, ProxyPort)
                    Exit Select
                Case "proxylogin"
                    ProxyUser = item
                    Exit Select
                Case "proxypassword"
                    ProxyPassword = item
                    Exit Select
                Case "clearCommandChannel"
                    If item.ToLower() = "false" Then
                        ClearCommandChannel = False
                    Else
                        ClearCommandChannel = True
                    End If
                    Exit Select
                Case "certificatepath"
                    ClientCertificateFilename = item
                    Exit Select
                Case "privateKeyFilename"
                    PrivateKeyFilename = item
                    Exit Select
                Case "serverCertificateThumbprint"
                    ServerCertificateThumbprint = item
                    Exit Select
                Case "serverCertificateVerifyingMode"
                    ServerCertificateVerifyingMode = ToEnum(item, ServerCertificateVerifyingMode)
                    Exit Select
                Case "serverKeyFingerprint"
                    ServerKeyFingerprint = item
                    Exit Select
                Case "serverKeyAlgorithm"
                    ServerKeyAlgorithm = ToEnum(item, ServerKeyAlgorithm)
                    Exit Select
                Case "serverKeyHashAlgorithm"
                    ServerKeyHashAlgorithm = ToEnum(item, ServerKeyHashAlgorithm)
                    Exit Select
                Case "serverKeyVerifyingMode"
                    ServerKeyVerifyingMode = ToEnum(item, ServerKeyVerifyingMode)
                    Exit Select
                Case "tlsSslVersion"
                    TlsProtocol = ToEnum(item, TlsProtocol)
                    Exit Select
                Case "allowedSuite"
                    AllowedSuite = ToEnum(item, AllowedSuite)
                    Exit Select
                Case "allowWeakSuites"
                    AllowWeakSuites = (item.ToLower() = "true")
                    Exit Select
                Case "proxyenabled"
                    If item.ToLower() = "false" Then
                        ProxyType = FileTransferProxyType.None
                        proxyTypeSet = True
                    End If
                    Exit Select
            End Select
        Next
    End Sub

    ''' <summary>
    ''' Save values into config file
    ''' </summary>
    Public Sub SaveConfig()
        Dim xml As New XmlDocument()
        Dim config As XmlElement = xml.CreateElement("configuration")
        xml.AppendChild(config)

        AddKey(xml, config, "loglevel", LogLevel.ToString())
        AddKey(xml, config, "fileTransferMode", FileTransferMode.ToString())
        AddKey(xml, config, "host", ServerHost)
        AddKey(xml, config, "login", ServerUser)
        AddKey(xml, config, "gssApi", UseGssApi.ToString())
        AddKey(xml, config, "domain", ServerDomain)
        AddKey(xml, config, "port", ServerPort.ToString())
        Dim pwd As String = ""
        If StorePassword OrElse ServerPassword = "password" Then
            pwd = ServerPassword
        End If
        AddKey(xml, config, "password", pwd)
        AddKey(xml, config, "passive", PassiveMode.ToString())
        AddKey(xml, config, "proxy", ProxyHost)
        AddKey(xml, config, "proxyport", ProxyPort.ToString())
        AddKey(xml, config, "proxytype", ProxyType.ToString())
        AddKey(xml, config, "proxylogin", ProxyUser)
        AddKey(xml, config, "proxypassword", ProxyPassword)
        AddKey(xml, config, "clearCommandChannel", ClearCommandChannel.ToString())
        AddKey(xml, config, "certificatepath", ClientCertificateFilename)
        AddKey(xml, config, "privateKeyFilename", PrivateKeyFilename)
        AddKey(xml, config, "serverCertificateThumbprint", ServerCertificateThumbprint)
        AddKey(xml, config, "serverCertificateVerifyingMode", ServerCertificateVerifyingMode.ToString())
        AddKey(xml, config, "serverKeyFingerprint", ServerKeyFingerprint)
        AddKey(xml, config, "serverKeyAlgorithm", ServerKeyAlgorithm.ToString())
        AddKey(xml, config, "serverKeyHashAlgorithm", ServerKeyHashAlgorithm.ToString())
        AddKey(xml, config, "serverKeyVerifyingMode", ServerKeyVerifyingMode.ToString())

        AddKey(xml, config, "tlsSslVersion", VersionToString(TlsProtocol))
        AddKey(xml, config, "allowedSuite", AllowedSuite.ToString())
        AddKey(xml, config, "allowWeakSuites", AllowWeakSuites.ToString())

        Dim configPath As String = Path.GetDirectoryName(ConfigFile)
        If Not Directory.Exists(configPath) Then
            Directory.CreateDirectory(configPath)
        End If
        xml.Save(ConfigFile)
    End Sub

    #Region "Utility methods"

    Private ReadOnly Property ConfigFile() As String
        Get
            If CInt(_supportedComponents) <= 0 Then
                Throw New InvalidOperationException("SupportedComponents value has not been initialized - call the Initialize() method.")
            End If
            Dim filename As String = String.Format("Rebex{0}{1}{0}WinFormClient.xml", Path.DirectorySeparatorChar, ConnectionEditorUtils.GetEnumValueDescription(_supportedComponents))
            Return Path.Combine(Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData), filename)
        End Get
    End Property

    Private Shared Function ToInt(value As String, defaultValue As Integer) As Integer
        Try
            Return Int32.Parse(value)
        Catch
            Return defaultValue
        End Try
    End Function

    Private Shared Function ToEnum(Of T)(value As String, defaultValue As T) As T
        Try
            Return DirectCast([Enum].Parse(GetType(T), value), T)
        Catch
            Return defaultValue
        End Try
    End Function

    Private Shared Function VersionToString(tlsVer As TlsVersion) As String

        Dim sb As StringBuilder = New StringBuilder()
        Dim addSeparator As Boolean = False

        Dim convert As Action(Of TlsVersion) =
            Sub(tv As TlsVersion)
                If ((tlsVer And tv) <> 0) Then

                    If (addSeparator) Then
                        sb.Append(", ")
                    End If
                    sb.Append(tv.ToString())
                    addSeparator = True
                End If
            End Sub

        convert(TlsVersion.TLS13)
        convert(TlsVersion.TLS12)
        convert(TlsVersion.TLS11)
        convert(TlsVersion.TLS10)

        Return sb.ToString()
    End Function

    Private Shared Sub AddKey(xml As XmlDocument, config As XmlElement, name As String, val As String)
        Dim key As XmlElement = xml.CreateElement("key")
        config.AppendChild(key)
        Dim atrName As XmlAttribute = xml.CreateAttribute("name")
        atrName.Value = name
        Dim atrVal As XmlAttribute = xml.CreateAttribute("value")
        atrVal.Value = val
        key.Attributes.Append(atrName)
        key.Attributes.Append(atrVal)
    End Sub

    #End Region
End Class
