Option Strict On
Option Explicit On

Imports System

Namespace Nexamas.UI.CommandActions

    ''' <summary>
    ''' Internal weak lease used to detach command-owned Button and Toolbar surface hooks without adding public API.
    ''' </summary>
    Friend NotInheritable Class MASCommandSurfaceBindingLease

        Private ReadOnly _target As WeakReference
        Private ReadOnly _releaseAction As Action(Of Object)
        Private _status As MASCommandBindingLifecycleStatus

        Friend Sub New(commandId As String,
                       surfaceKind As MASCommandBindingSurfaceKind,
                       sourceName As String,
                       target As Object,
                       releaseAction As Action(Of Object),
                       weakInvocationRoute As Boolean)
            If target Is Nothing Then Throw New ArgumentNullException(NameOf(target))

            Me.CommandId = MASCommandRegistry.NormalizeCommandId(commandId)
            Me.SurfaceKind = surfaceKind
            Me.SourceName = If(sourceName, String.Empty)
            Me.CanRelease = releaseAction IsNot Nothing
            Me.WeakInvocationRoute = weakInvocationRoute
            _target = New WeakReference(target)
            _releaseAction = releaseAction
            _status = MASCommandBindingLifecycleStatus.Active
        End Sub

        Friend ReadOnly Property CommandId As String
        Friend ReadOnly Property SurfaceKind As MASCommandBindingSurfaceKind
        Friend ReadOnly Property SourceName As String
        Friend ReadOnly Property CanRelease As Boolean
        Friend ReadOnly Property WeakInvocationRoute As Boolean

        Friend ReadOnly Property Status As MASCommandBindingLifecycleStatus
            Get
                Return _status
            End Get
        End Property

        Friend ReadOnly Property IsActive As Boolean
            Get
                Return _status = MASCommandBindingLifecycleStatus.Active
            End Get
        End Property

        Friend Function IsActiveForTarget(target As Object,
                                          surfaceKind As MASCommandBindingSurfaceKind) As Boolean
            If target Is Nothing OrElse Not IsActive OrElse Me.SurfaceKind <> surfaceKind Then Return False

            Dim current As Object = _target.Target
            Return current IsNot Nothing AndAlso Object.ReferenceEquals(current, target)
        End Function

        Friend Function Release() As MASCommandBindingLifecycleStatus
            If _status <> MASCommandBindingLifecycleStatus.Active Then Return _status

            Dim current As Object = _target.Target
            If current Is Nothing Then
                _status = MASCommandBindingLifecycleStatus.TargetUnavailable
                Return _status
            End If

            If _releaseAction IsNot Nothing Then
                _releaseAction.Invoke(current)
            End If

            _status = MASCommandBindingLifecycleStatus.Released
            Return _status
        End Function

        Friend Function ToRecord() As MASCommandBindingLifecycleRecord
            Return New MASCommandBindingLifecycleRecord(CommandId, SurfaceKind, SourceName, _status, CanRelease, WeakInvocationRoute)
        End Function

    End Class

End Namespace
