Imports System.Threading

Namespace Threading

    ''' <summary>
    ''' A lightweight process that runs on a dedicated thread.
    ''' </summary>
    ''' <remarks></remarks>
    Public MustInherit Class ThreadProcess

        ''' <summary>
        ''' Initializes a default instance of the ThreadProcess class.
        ''' </summary>
        ''' <remarks></remarks>
        Protected Sub New()
            Me.New(Nothing)
        End Sub

        ''' <summary>
        ''' Initializes a new instance of the ThreadProcess class with the specified context.
        ''' </summary>
        ''' <param name="withContext">A <see cref="ISynchronizationContext"/> 
        ''' object that represents a consumer thread's synchronization context.</param>
        ''' <remarks></remarks>
        Protected Sub New(ByVal withContext As ISynchronizationContext)
            Me._internalThread = New Thread(New ThreadStart(AddressOf ThreadStartInternal))
            Me._internalThread.IsBackground = True
            Me._consumerContext = withContext
        End Sub

        Private _processLock As Object = New Object()
        Private _threadDisposed As Boolean = False
        Private _internalThread As Thread

        ''' <summary>
        ''' Gets the identifier of the internal thread.  A value of 0 
        ''' indicates that an internal thread has not been set.
        ''' </summary>
        ''' <returns>The identifier of the internal thread or 0 if not set.</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property ThreadId() As Integer
            Get
                If (Me._internalThread IsNot Nothing) Then _
                    Return Me._internalThread.ManagedThreadId
                Return 0
            End Get
        End Property

        ''' <summary>
        ''' Gets or sets a value indicating whether the 
        ''' internal thread is a background thread.
        ''' </summary>
        ''' <returns>True if the internal thread is a background thread; otherwise, false.</returns>
        ''' <remarks></remarks>
        Public Property IsBackground() As Boolean
            Get
                If (Me._internalThread IsNot Nothing) Then _
                    Return Me._internalThread.IsBackground
                Return True
            End Get
            Set(ByVal value As Boolean)
                If (Me._internalThread IsNot Nothing) Then
                    Me._internalThread.IsBackground = True
                End If
            End Set
        End Property

        Private _isStarted As Boolean

        ''' <summary>
        ''' Gets a value indicating whether this process has started.
        ''' </summary>
        ''' <returns>True if the process has started; otherwise, false.</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property IsStarted() As Boolean
            Get
                Return Me._isStarted
            End Get
        End Property

        Private _consumerContext As ISynchronizationContext

        ''' <summary>
        ''' Gets the synchronization context for a consumer thread.
        ''' </summary>
        ''' <value></value>
        ''' <returns>The <see cref="ISynchronizationContext" /> for the consumer thread.</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property ConsumerContext() As ISynchronizationContext
            Get
                Return Me._consumerContext
            End Get
        End Property

        ''' <summary>
        ''' Starts the process on the internal thread.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub Start()
            If Not (Me.IsStarted) AndAlso Me._internalThread IsNot Nothing Then
                ' If internal thread has been disposed, throw
                If (Me._threadDisposed) Then _
                    Throw New ObjectDisposedException("_internalThread")

                Try
                    Me._isStarted = True
                    Me._internalThread.Start()
                Catch ex As Exception
                    Me._isStarted = False
                    Throw
                End Try
            End If
        End Sub

        ''' <summary>
        ''' Stops the process and disposes of the internal thread.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub [Stop]()
            If Not (Me._threadDisposed) Then
                Me._isStarted = False
                Me._threadDisposed = True
                SyncLock Me._processLock
                    StopInternal()
                    If (Me._internalThread IsNot Nothing) Then
                        Me._internalThread.Join()
                        Me._internalThread = Nothing
                    End If
                End SyncLock
            End If
        End Sub

        ''' <summary>
        ''' Starts the process.
        ''' </summary>
        ''' <remarks></remarks>
        Protected MustOverride Sub ThreadStartInternal()

        ''' <summary>
        ''' Stops the process.
        ''' </summary>
        ''' <remarks></remarks>
        Protected MustOverride Sub StopInternal()

        ''' <summary>
        ''' Determines whether the specified exception should be considered a critical exception.
        ''' </summary>
        ''' <param name="ex">The <see cref="Exception"/> to test.</param>
        ''' <returns>True if the exception is critical; otherwise, false.</returns>
        ''' <remarks></remarks>
        Public Shared Function IsCriticalException(ByVal ex As Exception) As Boolean
            Return (TypeOf ex Is OutOfMemoryException OrElse IsThreadAbortException(ex))
        End Function

        ''' <summary>
        ''' Determines whether the specified exception is a System.Threading.ThreadAbortException.
        ''' </summary>
        ''' <param name="ex">The <see cref="Exception"/> to test.</param>
        ''' <returns>True if the exception is a System.Threading.ThreadAbortException; otherwise, false.</returns>
        ''' <remarks></remarks>
        Public Shared Function IsThreadAbortException(ByVal ex As Exception) As Boolean
            Return (TypeOf ex Is ThreadAbortException)
        End Function

    End Class

End Namespace