Imports System.Threading
Public MustInherit Class ClsBaseThread
    Implements IDisposable
    'TODOi : Gestion description des threads
    'Implements NHenry.Exception.IException
#Region "Attributs partagés"
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Attribut de classe, à tester pour le StopAllThread
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected Friend Shared msCanRun As Boolean
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Attribut de la classe, si true, arrêt rapide des thread préférable
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected Friend Shared msFinalize As Boolean
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Liste des threads en cours d'execution
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected Friend Shared msLstThreads As ArrayList
#End Region
#Region "Attributs protégés"
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Attribut d'objet à tester pour le StopThread
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected Friend mCanRun As Boolean = True
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Attribut d'objet true si le thread fonctionne (ne pas modifier, modification automatique)
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected Friend mThreadRun As Boolean = False
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Si ture, indique que l'arrêt du thread doit être rapide (génération d'un ThreadAbortException toutes les 2 secondes)
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected Friend mFinalize As Boolean = False

#Region "Attributs d'affichage des erreurs"
#If DEBUG Then
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Mémorise si on affiche ou non si une exception non gérée apparait dans un thread
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected Friend mShowException As Boolean = True
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Mémorise si on affiche une fenetre ou dans la sortie de débogage
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected Friend mFormException As Boolean = True
#Else
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Mémorise si on affiche ou non si une exception non gérée apparait dans un thread
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected Friend mShowException As Boolean = False
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Mémorise si on affiche une fenetre ou dans la sortie de débogage
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected Friend Const mFormException As Boolean = True
#End If
#End Region
#End Region
    Private mThread As Thread
#Region "Constructeurs"
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Initialise les attributs shared
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Shared Sub New()
        msFinalize = False
        msCanRun = True
        msLstThreads = New ArrayList
    End Sub
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Constructeur de la classe+execution immédiate du thread
    ''' </summary>
    ''' <param name="pName">Optionnel, nom du thread</param>
    ''' -----------------------------------------------------------------------------
    Protected Friend Sub New(Optional ByVal pName As String = "")
#If DEBUG Then
        Debug.WriteLine("Démarrage du thread : " + pName)
#End If
        mThread = New Thread(AddressOf SubThread)
        mThread.Name = pName
        mThread.Start()
    End Sub
#End Region
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Retourne le nom du thread actuel
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Public ReadOnly Property Name() As String
        Get
            Return mThread.Name
        End Get
    End Property
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Retourne ture si le thread est encode en fonctionnement.
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Public ReadOnly Property ThreadRun() As Boolean
        Get
            Return mThreadRun
        End Get
    End Property
#Region "Procédure concernants tous les threads"
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Arrête tous les threads actifs
    ''' </summary>
    ''' <param name="pWait">si true, attent que tous les threads soient arrêtés</param>
    ''' <param name="pHurry">Demande aux thread de s'arrêter rapidement</param>
    ''' -----------------------------------------------------------------------------
    Friend Shared Sub StopAllThread(Optional ByVal pWait As Boolean = False, Optional ByVal pHurry As Boolean = False)
        msCanRun = False
        If pHurry Then msFinalize = True
        Do While (pWait And msLstThreads.Count > 0) : Thread.Sleep(0) : Loop
    End Sub
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Retourne le nombre de thread actuellement en fonctionnement
    ''' </summary>
    ''' <returns></returns>
    ''' -----------------------------------------------------------------------------
    Friend Shared Function NbThreadRun() As Integer
        Return msLstThreads.Count
    End Function
#End Region
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Arrête le thread courant
    ''' </summary>
    ''' <param name="pWait">si true, attent que le thread soit arrêté</param>
    ''' -----------------------------------------------------------------------------
    Friend Sub StopThread(Optional ByVal pWait As Boolean = False)
        mCanRun = False
        Do While (pWait And mThreadRun) : Thread.Sleep(0) : Loop
    End Sub
#Region "méthodes à substituer"
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Méthode du thread
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected MustOverride Sub Run()
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Appelé en cas d'erreur dans le thread
    ''' </summary>
    ''' <param name="pEx">Exception interceptée</param>
    ''' -----------------------------------------------------------------------------
    Protected MustOverride Sub SubError(ByRef pEx As Exception)
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Appelé pour terminer le thread
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected MustOverride Sub EndThread()
#End Region
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Méthode de gestion du thread
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Private Sub SubThread()
        Dim lParams As NHenry.Exception.ColParams
        Try
            mThreadRun = True
            Me.msLstThreads.Add(Me)
            'msNbThread += 1
            Run()
        Catch ex As Exception
            Try
                SubError(ex)
            Catch ex1 As Exception
                If Me.mShowException Then
                    If Me.mFormException Then
                        lParams = GetErrParam(ex)
                        NHenry.Exception.Main.Show(ex1, "Erreur dans le thread", "Erreur dans le thread de gestion des erreurs", lParams)
                    Else
#If DEBUG Then
                        Debug.WriteLine("Erreur dans la procédure de gestion des erreurs du thread " + mThread.Name + Environment.NewLine + ex.ToString + Environment.NewLine + "Erreur générée :" + Environment.NewLine + ex1.ToString)
#End If
                    End If
                End If
            End Try
        Finally
            Try
                EndThread()
            Catch ex As Exception
                Try
                    SubError(ex)
                Catch ex1 As Exception
                    If Me.mShowException Then
                        If Me.mFormException Then
                            lParams = GetErrParam(ex)
                            NHenry.Exception.Main.Show(ex1, "Erreur dans le thread", "Erreur dans le thread de gestion des erreurs", lParams)
                        Else
#If DEBUG Then
                            Debug.WriteLine("Erreur dans la procédure de gestion des erreurs du thread " + mThread.Name + Environment.NewLine + ex.ToString + Environment.NewLine + "Erreur générée :" + Environment.NewLine + ex1.ToString)
#End If
                        End If
                    End If
                End Try
            End Try
            Me.msLstThreads.Remove(Me)
            mThreadRun = False
            System.GC.Collect()
            System.GC.WaitForPendingFinalizers()
        End Try
    End Sub
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Met le thread en pause pendant pMilisec millisecondes
    ''' </summary>
    ''' <param name="pMilisec">pause en ms</param>
    ''' -----------------------------------------------------------------------------
    Protected Friend Sub Sleep(ByVal pMilisec As Integer)
        mThread.Sleep(pMilisec)
    End Sub
#Region "Gestion de l'affichage des erreurs"
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Retourne ou définitsi les exceptions non gérées par un thread sont affichées
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Friend Property ShowException() As Boolean
        Get
            Return Me.mShowException
        End Get
        Set(ByVal Value As Boolean)
            Me.mShowException = Value
        End Set
    End Property
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Retourne si pour afficher le message d'erreur on utilise le NHenry.Exception (<c>true</c>) ou Debug (<c>false</c>)
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Friend Property FormException() As Boolean
        Get
            Return Me.mFormException
        End Get
        Set(ByVal Value As Boolean)
#If DEBUG Then
            Me.mFormException = Value
#End If
        End Set
    End Property
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Retourne un NHenry.Exceptio,.ColParams contenant les contenu de la classe ClsBaseThread
    ''' </summary>
    ''' <param name="pEx">Exception précédente</param>
    ''' <returns></returns>
    ''' -----------------------------------------------------------------------------
    Protected Friend Function GetErrParam(Optional ByVal pEx As System.Exception = Nothing) As NHenry.Exception.ColParams
        Dim lCol As New NHenry.Exception.ColParams
        With lCol
            .Add(New NHenry.Exception.SParam("msCanRun", msCanRun))
            .Add(New NHenry.Exception.SParam("msLstThreads", msLstThreads))
            .Add(New NHenry.Exception.SParam("msFinalize", msFinalize))
            .Add(New NHenry.Exception.SParam("mCanRun", mCanRun))
            .Add(New NHenry.Exception.SParam("mThreadRun", mThreadRun))
            .Add(New NHenry.Exception.SParam("mFinalize", mThreadRun))
            .Add(New NHenry.Exception.SParam("mThread", mThread))
            .Add(New NHenry.Exception.SParam("Ex", pEx))
            .Add(New NHenry.Exception.SParam("Me", Me))
#If DEBUG Then
            .Add(New NHenry.Exception.SParam("DebugMode", True))
#Else
            .Add(New NHenry.Exception.SParam("DebugMode", False))
#End If
        End With
        Return lCol
    End Function
#End Region
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Retourne une String représentant l'état de l'objet
    ''' </summary>
    ''' <returns></returns>
    ''' -----------------------------------------------------------------------------
    Public Overrides Function ToString() As String
        Dim lStr As String = "ClsBaseThread : "
        lStr += " Attributs shared {"
        lStr += "msCanRun=" + CStr(msCanRun)
        lStr += ",msLstThreads.Count=" + CStr(msLstThreads.Count)
        lStr += ",msFinalize=" + CStr(msFinalize)
        lStr += "} Attributs protected {"
        lStr += "mCanRun=" + CStr(mCanRun)
        lStr += ",mThreadRun=" + CStr(mThreadRun)
        lStr += ",msFinalize=" + CStr(msFinalize)
        lStr += "}"
#If DEBUG Then
        lStr += "Debug Mode"
#Else
        lStr += "Release Mode"
#End If
        Return lStr
    End Function
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Décharge l'objet immédiatement
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Friend Sub Dispose() Implements System.IDisposable.Dispose
        mCanRun = False
        mFinalize = True
    End Sub
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' destructeur
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Protected Overrides Sub Finalize()
        mCanRun = False
        mFinalize = True
        Do While mThreadRun
            If mThread.Join(2000) = False Then
                mThread.Abort()
            End If
        Loop
        MyBase.Finalize()
    End Sub
End Class
