Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Specialized
Imports System.Diagnostics
Imports System.IO
Imports System.Windows.Forms
Imports Nexamas.UI.Controls
Imports Nexamas.UI.Composition
Imports Nexamas.UI.FileSystem
Imports Nexamas.UI.General
Imports Nexamas.UI.Rendering
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Values
Imports Nexamas.UI.Layout
Imports SkiaSharp

Namespace Nexamas.UI.Components


    Partial Public NotInheritable Class MASFilePickerControl
#Region "Controller and child lifecycle services"

        Private Sub ConfigureFooterLabel()
            _footerLabel.Name = "FilePickerFooterLabel"
            _footerLabel.TextStyle = MASTypography.MASTextStyle.Body
            _footerLabel.TextRole = MASLabelTextRole.Muted
            _footerLabel.HorizontalAlignment = MASHorizontalAlignment.Right
        End Sub

        Private ReadOnly Property CurrentOptions As MASFilePickerOptions
            Get
                If _controller Is Nothing OrElse _controller.Options Is Nothing Then
                    Return New MASFilePickerOptions()
                End If

                Return _controller.Options
            End Get
        End Property


        Private Function GetOptionsSnapshot() As MASFilePickerOptions
            Return MASFilePickerOptions.SafeClone(CurrentOptions)
        End Function


        Private Sub UpdateOptions(mutator As Action(Of MASFilePickerOptions),
                                  fullRebuild As Boolean,
                                  keepPath As Boolean)

            If mutator Is Nothing Then Return

            Dim snapshot As MASFilePickerOptions = GetOptionsSnapshot()
            mutator.Invoke(snapshot)
            snapshot.Normalize()

            RebuildWithOptions(snapshot, fullRebuild, keepPath)
        End Sub


        Private Sub CreateController(options As MASFilePickerOptions)
            CreateController(options, Nothing)
        End Sub


        Private Sub CreateController(options As MASFilePickerOptions, provider As IFileSystemProvider)
            _controller = New FilePickerController(MASFilePickerOptions.SafeClone(options), provider)
            _browser = _controller.Browser

            If _browser IsNot Nothing Then
                _browser.Name = "FilePickerBrowser"
                RegisterChild(_browser)
            End If

            CreateOrDestroyFileNameBox()
            BuildButtons()
            WireEvents()
            SyncNavigationBarState()

            SafeInvalidate()
        End Sub


        Private Sub RebuildWithOptions(options As MASFilePickerOptions,
                                       fullRebuild As Boolean,
                                       keepPath As Boolean)

            If _disposedLocal Then Return

            Dim oldPath As String = String.Empty
            Dim oldSelectedName As String = String.Empty

            If keepPath AndAlso _controller IsNot Nothing Then
                oldPath = _controller.CurrentPath

                If _controller.SelectedItem IsNot Nothing Then
                    oldSelectedName = _controller.SelectedItem.Name
                End If
            End If

            DestroyController()
            CreateController(options)

            If keepPath AndAlso _browser IsNot Nothing Then
                If Not String.IsNullOrWhiteSpace(oldPath) Then
                    _browser.CurrentPath = oldPath
                ElseIf Not String.IsNullOrWhiteSpace(options.InitialPath) Then
                    _browser.CurrentPath = options.InitialPath
                Else
                    _browser.LoadRoots()
                End If
            End If

            If fullRebuild Then BuildButtons()

            SyncFileNameBoxFromController()
            RestoreSelectionByName(oldSelectedName)
            SyncNavigationBarState()

            RaiseStateChanged()
            RequestSizeLayoutRefreshForSizeAffectingChange("MASFilePickerControl.RebuildWithOptions")
            SafeInvalidate()
        End Sub


        Private Sub RestoreSelectionByName(name As String)
            If String.IsNullOrWhiteSpace(name) Then Return
            If _browser Is Nothing Then Return

            For i As Integer = 0 To _browser.Items.Count - 1
                Dim it As FileSystemEntry = _browser.Items(i)

                If it IsNot Nothing AndAlso
                   String.Equals(it.Name, name, StringComparison.CurrentCultureIgnoreCase) Then

                    _browser.SelectIndex(i)
                    _browser.EnsureVisible(i)
                    Exit For
                End If
            Next
        End Sub


        Private Sub DestroyController()
            UnwireEvents()
            RemoveFileNameBox()

            If _browser IsNot Nothing Then
                Try
                    UnregisterChild(_browser)
                Catch masCaughtException2 As Exception
                    Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException2)
                End Try
            End If

            If _controller IsNot Nothing Then
                Try
                    _controller.Dispose()
                Catch masCaughtException3 As Exception
                    Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException3)
                End Try
            End If

            _controller = Nothing
            _browser = Nothing
        End Sub


        Private Sub ConfigureButtons()
            _primaryButton.Name = "FilePickerPrimaryButton"
            _primaryButton.Personality = MASButtonPersonality.MAS
            _primaryButton.Intent = MASButtonIntent.Default
            _primaryButton.IsDefaultButton = False

            _cancelButton.Name = "FilePickerCancelButton"
            _cancelButton.Personality = MASButtonPersonality.MAS
            _cancelButton.Intent = MASButtonIntent.Default
            _cancelButton.IsDefaultButton = False

            AddHandler _primaryButton.Click, AddressOf OnPrimaryButtonClick
            AddHandler _cancelButton.Click, AddressOf OnCancelButtonClick
        End Sub


        Private Sub ConfigureNavigationBar()
            _navigationBar.Name = "FilePickerNavigationBar"

            AddHandler _navigationBar.UpRequested, AddressOf OnNavigationUpRequested
            AddHandler _navigationBar.RefreshRequested, AddressOf OnNavigationRefreshRequested
            AddHandler _navigationBar.BackRequested, AddressOf OnNavigationBackRequested
            AddHandler _navigationBar.ForwardRequested, AddressOf OnNavigationForwardRequested

            SyncNavigationBarState()
        End Sub


        Private Sub RegisterPermanentChildren()
            RegisterChild(_navigationBar)
            RegisterChild(_primaryButton)
            RegisterChild(_cancelButton)
            RegisterChild(_footerLabel)
        End Sub


        Private Sub CreateOrDestroyFileNameBox()
            If _controller Is Nothing Then
                RemoveFileNameBox()
                Return
            End If

            If _controller.IsSaveMode Then
                If _fileNameBox Is Nothing Then
                    _fileNameBox = New MASTextBox() With {
                        .Name = "FilePickerFileNameTextBox",
                        .Placeholder = "File name"
                    }

                    RegisterChild(_fileNameBox)
                    RequestSizeLayoutRefreshForSizeAffectingChange("MASFilePickerControl.FileNameBoxCreated")
                End If

                _fileNameBox.Text = _controller.SaveFileName
                _fileNameBox.Visible = True
            Else
                RemoveFileNameBox()
            End If
        End Sub


        Private Sub RemoveFileNameBox()
            If _fileNameBox Is Nothing Then Return

            Try
                RemoveHandler _fileNameBox.TextChanged, AddressOf OnFileNameTextChanged
            Catch masCaughtException4 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowFileSystemBoundary(masCaughtException4)
            End Try
            Try
                UnregisterChild(_fileNameBox)
            Catch masCaughtException5 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowFileSystemBoundary(masCaughtException5)
            End Try
            Try
                _fileNameBox.Dispose()
            Catch masCaughtException6 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowFileSystemBoundary(masCaughtException6)
            End Try

            _fileNameBox = Nothing
            RequestSizeLayoutRefreshForSizeAffectingChange("MASFilePickerControl.FileNameBoxRemoved")
        End Sub


        Private Sub WireEvents()
            If _controller Is Nothing Then Return

            AddHandler _controller.Accepted, AddressOf OnPickerAccepted
            AddHandler _controller.Cancelled, AddressOf OnPickerCancelled
            AddHandler _controller.StateChanged, AddressOf OnPickerStateChanged

            If _browser IsNot Nothing Then
                AddHandler _browser.CurrentPathChanged, AddressOf OnBrowserCurrentPathChanged
                AddHandler _browser.SelectionChanged, AddressOf OnBrowserSelectionChanged
                AddHandler _browser.ItemsChanged, AddressOf OnBrowserItemsChanged
                AddHandler _browser.ItemContextMenuRequested, AddressOf OnBrowserItemContextMenuRequested
                AddHandler _browser.EmptySpaceContextMenuRequested, AddressOf OnBrowserEmptySpaceContextMenuRequested
                AddHandler _browser.InlineRenameCommitted, AddressOf OnBrowserInlineRenameCommitted
            End If

            If _fileNameBox IsNot Nothing Then
                AddHandler _fileNameBox.TextChanged, AddressOf OnFileNameTextChanged
            End If
        End Sub


        Private Sub UnwireEvents()
            If _controller IsNot Nothing Then
                Try
                    RemoveHandler _controller.Accepted, AddressOf OnPickerAccepted
                Catch masCaughtException7 As Exception
                    Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException7)
                End Try
                Try
                    RemoveHandler _controller.Cancelled, AddressOf OnPickerCancelled
                Catch masCaughtException8 As Exception
                    Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException8)
                End Try
                Try
                    RemoveHandler _controller.StateChanged, AddressOf OnPickerStateChanged
                Catch masCaughtException9 As Exception
                    Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException9)
                End Try
            End If

            If _browser IsNot Nothing Then
                Try
                    RemoveHandler _browser.CurrentPathChanged, AddressOf OnBrowserCurrentPathChanged
                Catch masCaughtException10 As Exception
                    Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException10)
                End Try
                Try
                    RemoveHandler _browser.SelectionChanged, AddressOf OnBrowserSelectionChanged
                Catch masCaughtException11 As Exception
                    Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException11)
                End Try
                Try
                    RemoveHandler _browser.ItemsChanged, AddressOf OnBrowserItemsChanged
                Catch masCaughtException12 As Exception
                    Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException12)
                End Try
                Try
                    RemoveHandler _browser.ItemContextMenuRequested, AddressOf OnBrowserItemContextMenuRequested
                Catch masCaughtException13 As Exception
                    Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException13)
                End Try
                Try
                    RemoveHandler _browser.EmptySpaceContextMenuRequested, AddressOf OnBrowserEmptySpaceContextMenuRequested
                Catch masCaughtException14 As Exception
                    Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException14)
                End Try
                Try
                    RemoveHandler _browser.InlineRenameCommitted, AddressOf OnBrowserInlineRenameCommitted
                Catch masCaughtException15 As Exception
                    Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException15)
                End Try
            End If

            If _fileNameBox IsNot Nothing Then
                Try
                    RemoveHandler _fileNameBox.TextChanged, AddressOf OnFileNameTextChanged
                Catch masCaughtException16 As Exception
                    Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException16)
                End Try
            End If
        End Sub



#End Region

    End Class

End Namespace
