'  
'   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.ComponentModel
Imports System.IO
Imports Microsoft.Win32
Imports Rebex.Security

''' <summary>
''' ViewModel for MainWindow class.
''' </summary>
''' <remarks>
''' Please note that using dialogs such as MessageBox and OpenFileDialog in this class
''' is not considered as clean MVVM pattern.
''' </remarks>
Public Class MainWindowViewModel
    Implements INotifyPropertyChanged
    ' encrypted file extension
    Private Const EncryptionExtension As String = ".enc"

    ' specifies operations to perform
    Private Enum Operation
        Encrypt
        Decrypt
    End Enum

    Private _sourceFilePath As String
    Private _destinationFilePath As String
    Private _password As String

    ''' <summary>
    ''' Gets or sets destination path.
    ''' </summary>
    Public Property DestinationFilePath() As String
        Get
            Return _destinationFilePath
        End Get
        Set
            If _destinationFilePath <> value Then
                _destinationFilePath = value

                ' make this property "observable" by binding engine of WPF
                OnPropertyChanged("DestinationFilePath")
            End If
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets source path.
    ''' </summary>
    Public Property SourceFilePath() As String
        Get
            Return _sourceFilePath
        End Get
        Set
            If _sourceFilePath <> value Then
                _sourceFilePath = value
                SetDestinationFilePath(value)

                ' make this property "observable" by binding engine of WPF
                EncryptCommand.RaiseCanExecuteChanged()
                DecryptCommand.RaiseCanExecuteChanged()
                OnPropertyChanged("SourceFilePath")
            End If
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the password.
    ''' </summary>
    Public Property Password() As String
        Get
            Return _password
        End Get
        Set
            _password = value

            ' notify the commands if this property changes
            EncryptCommand.RaiseCanExecuteChanged()
            DecryptCommand.RaiseCanExecuteChanged()
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets value indicating whether the destination file can be overwritten.
    ''' </summary>
    Public Property OverwriteExistingFiles() As Boolean
        Get
            Return m_OverwriteExistingFiles
        End Get
        Set
            m_OverwriteExistingFiles = Value
        End Set
    End Property
    Private m_OverwriteExistingFiles As Boolean

    ''' <summary>
    ''' This Command handles Encrypt button.
    ''' </summary>
    Public Property EncryptCommand() As SimpleCommand
        Get
            Return m_EncryptCommand
        End Get
        Private Set
            m_EncryptCommand = Value
        End Set
    End Property
    Private m_EncryptCommand As SimpleCommand

    Public Property DecryptCommand() As SimpleCommand
        Get
            Return m_DecryptCommand
        End Get
        Private Set
            m_DecryptCommand = Value
        End Set
    End Property
    Private m_DecryptCommand As SimpleCommand

    Public Property OpenCommand() As SimpleCommand
        Get
            Return m_OpenCommand
        End Get
        Private Set
            m_OpenCommand = Value
        End Set
    End Property
    Private m_OpenCommand As SimpleCommand

    Public Sub New()
        ' initialize commands for buttons
        EncryptCommand = New SimpleCommand(AddressOf Encrypt, AddressOf CanExecuteOperation)
        DecryptCommand = New SimpleCommand(AddressOf Decrypt, AddressOf CanExecuteOperation)
        OpenCommand = New SimpleCommand(AddressOf Open)
    End Sub

    Private Function CanExecuteOperation() As Boolean
        Return Not String.IsNullOrEmpty(SourceFilePath) AndAlso Not String.IsNullOrEmpty(Password)
    End Function

    ''' <summary>
    ''' EncryptCommand execute method.
    ''' </summary>
    Private Sub Encrypt()
        PerformOperation(Operation.Encrypt)
    End Sub

    ''' <summary>
    ''' DecryptCommand execute method.
    ''' </summary>
    Private Sub Decrypt()
        PerformOperation(Operation.Decrypt)
    End Sub

    ''' <summary>
    ''' Encrypts or decrypts specified file.
    ''' </summary>
    ''' <param name="operation">Operation to perform.</param>
    Private Sub PerformOperation(encryptionOperation As Operation)
        ' check destination file existence
        If Not OverwriteExistingFiles AndAlso File.Exists(DestinationFilePath) Then
            ShowError("Destination file already exists." & vbLf & "Check the 'Overwrite existing file' checkbox to overwrite it.", "Destination file exists")
            Return
        End If

        ' perform operation
        Dim encryptor As New FileEncryption()
        encryptor.OverwriteExistingFile = OverwriteExistingFiles
        encryptor.SetPassword(Password)

        Try
            If encryptionOperation = Operation.Encrypt Then
                encryptor.Encrypt(SourceFilePath, DestinationFilePath)
            Else
                encryptor.Decrypt(SourceFilePath, DestinationFilePath)
            End If

            ShowInfo("Operation finished successfully.", "Operation done")
        Catch ex As Exception
            ShowError(ex.ToString(), "Error occurred")
        End Try
    End Sub

    ''' <summary>
    ''' OpenCommand execute method.
    ''' </summary>
    Private Sub Open()
        Dim openDialog As New OpenFileDialog()
        openDialog.Filter = "Encrypted files|*.enc|All files|*.*"
        openDialog.FilterIndex = 2

        If openDialog.ShowDialog().GetValueOrDefault(False) Then
            SourceFilePath = openDialog.FileName
        End If
    End Sub

    Private Sub SetDestinationFilePath(fileName As String)
        If Path.GetExtension(fileName) = EncryptionExtension Then
            Dim dir As String = Path.GetDirectoryName(fileName)
            Dim destinationFileName As String = Path.GetFileNameWithoutExtension(fileName)
            DestinationFilePath = Path.Combine(dir, destinationFileName)
        Else
            DestinationFilePath = fileName & EncryptionExtension
        End If
    End Sub

    ''' <summary>
    ''' Shows error message.
    ''' </summary>
    ''' <param name="message">Message to show.</param>
    ''' <param name="caption">Window caption.</param>
    Private Sub ShowError(message As String, caption As String)
        System.Windows.MessageBox.Show(message, caption, System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Exclamation)
    End Sub

    ''' <summary>
    ''' Shows information message.
    ''' </summary>
    ''' <param name="message">Message to show.</param>
    ''' <param name="caption">Window caption.</param>
    Private Sub ShowInfo(message As String, caption As String)
        System.Windows.MessageBox.Show(message, caption, System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Information)
    End Sub

    #Region "property changed"

    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

    Private Sub OnPropertyChanged(propertyName As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub

    #End Region
End Class
