''' <summary>
''' Classe de gestion des trames
''' </summary>
''' <remarks></remarks>
Public NotInheritable Class SendingFrame

    ''' <summary>
    ''' Enumération des verrous
    ''' </summary>
    ''' <remarks></remarks>
    <FlagsAttribute()> Public Enum ESlaveLock
        ''' <summary>
        ''' Pas de verrous
        ''' </summary>
        ''' <remarks></remarks>
        NoLock = 0
        ''' <summary>
        ''' Verrou sur les trames cycliques
        ''' </summary>
        ''' <remarks></remarks>
        LockCyclic = 1
        ''' <summary>
        ''' Verrou sur les trames non cycliques
        ''' </summary>
        ''' <remarks></remarks>
        LockNonCyclic = 2
        ''' <summary>
        ''' verrou sur toutes les trames
        ''' </summary>
        ''' <remarks></remarks>
        LockAll = 3
    End Enum

    ''' <summary>
    ''' Trame servant à supprimer une trame cyclique
    ''' </summary>
    ''' <remarks></remarks>
    Public Class DeleteCyclicFrame
        Inherits Frame.ClsFrameModbusBase

        Public Sub New()
            MyBase.New(0, 255)
        End Sub

        Public Overrides ReadOnly Property FrameType() As Frame.ClsFrameModbusBase.EFrameType
            Get
                Return EFrameType.Unknow
            End Get
        End Property

        Friend Overloads Overrides Function GetFrame() As Byte()
            Return New Byte() {}
        End Function
    End Class

    ''' <summary>
    ''' Delegate pour signaler l'arrivée d'une réponse
    ''' </summary>
    ''' <param name="pSender">Emmeteur de l'event</param>
    ''' <param name="pFrameSent">Trame envoyée</param>
    ''' <param name="pFrameReceived">Trame reçue (Nothing si aucune aucune réception)</param>
    ''' <param name="pID">ID (définit lors de la création de la trame)</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Delegate Function DgtSent(ByVal pSender As IAnimCom, ByVal pFrameSent As Modbus.Frame.ClsFrameModbusBase, ByVal pFrameReceived As Modbus.Frame.ClsFrameModbusBase, ByVal pID As Integer) As SendingFrame

#Region "Attributs privés"
    ''' <summary>
    ''' Trame envoyée
    ''' </summary>
    ''' <remarks></remarks>
    Private mFrameSend As Frame.ClsFrameModbusBase
    ''' <summary>
    ''' Trame reçue
    ''' </summary>
    ''' <remarks></remarks>
    Private mFrameReceive As Frame.ClsFrameModbusBase
    ''' <summary>
    ''' Verrous
    ''' </summary>
    ''' <remarks></remarks>
    Private mLock As ESlaveLock = ESlaveLock.NoLock
    ''' <summary>
    ''' Trame cyclique ?
    ''' </summary>
    ''' <remarks></remarks>
    Private mIsCyclic As Boolean
    ''' <summary>
    ''' Nombre de renvois
    ''' </summary>
    ''' <remarks></remarks>
    Private mNbResend As Integer
    ''' <summary>
    ''' Nombre de renvois restant
    ''' </summary>
    ''' <remarks></remarks>
    Private mLeftResend As Integer
    ''' <summary>
    ''' ID (code utilisateur)
    ''' </summary>
    ''' <remarks></remarks>
    Private mID As Integer
    ''' <summary>
    ''' Delegate de la procédure de réception
    ''' </summary>
    ''' <remarks></remarks>
    Private mDelegate As DgtSent
#End Region

#Region "Constructeurs"
    ''' <summary>
    ''' Constructeur de la classe
    ''' </summary>
    ''' <param name="pFrame">Trame à envoyer</param>
    ''' <param name="pSubReceive">Delegate signalant la réception</param>
    ''' <param name="pLock">Verrous</param>
    ''' <remarks></remarks>
    Public Sub New(ByVal pFrame As Frame.ClsFrameModbusBase, ByVal pSubReceive As DgtSent, ByVal pLock As ESlaveLock)
        MyClass.New(pFrame, pSubReceive, pLock, 1, 0)
    End Sub
    ''' <summary>
    ''' Constructeur de la classe
    ''' </summary>
    ''' <param name="pFrame">Trame à envoyer</param>
    ''' <param name="pSubReceive">Delegate signalant la réception</param>
    ''' <param name="pLock">Verrous</param>
    ''' <param name="pNbResend">Nombre de réémissions</param>
    ''' <remarks></remarks>
    Public Sub New(ByVal pFrame As Frame.ClsFrameModbusBase, ByVal pSubReceive As DgtSent, ByVal pLock As ESlaveLock, ByVal pNbResend As Integer)
        MyClass.New(pFrame, pSubReceive, pLock, pNbResend, 0)
    End Sub
    ''' <summary>
    ''' Constructeur de la classe
    ''' </summary>
    ''' <param name="pFrame">Trame à envoyer</param>
    ''' <param name="pSubReceive">Delegate signalant la réception</param>
    ''' <param name="pLock">Verrous</param>
    ''' <param name="pNbResend">Nombre de réémissions</param>
    ''' <param name="pID">ID (pour code utilisateur)</param>
    ''' <remarks></remarks>
    Public Sub New(ByVal pFrame As Frame.ClsFrameModbusBase, ByVal pSubReceive As DgtSent, ByVal pLock As ESlaveLock, ByVal pNbResend As Integer, ByVal pID As Integer)
        mFrameSend = pFrame
        mLock = pLock
        mIsCyclic = False
        mFrameReceive = Nothing
        mID = pID
        mNbResend = pNbResend
        mLeftResend = pNbResend
        mDelegate = pSubReceive
    End Sub
    ''' <summary>
    ''' Constructeur de copie
    ''' </summary>
    ''' <param name="pModel">Classe d'origine</param>
    ''' <param name="pReceived">Trame reçue</param>
    ''' <remarks></remarks>
    Public Sub New(ByVal pModel As SendingFrame, ByVal pReceived As Frame.ClsFrameModbusBase)
        mFrameReceive = pReceived
        mFrameSend = pModel.mFrameSend
        mLock = pModel.mLock
        mIsCyclic = pModel.mIsCyclic
        mID = pModel.mID
        mNbResend = pModel.mNbResend
        mLeftResend = pModel.mNbResend
        mDelegate = pModel.mDelegate
    End Sub
#End Region

#Region "Propriété publiques"
    ''' <summary>
    ''' Retourne les verrous
    ''' </summary>
    ''' <remarks></remarks>
    Public ReadOnly Property Lock() As ESlaveLock
        Get
            Return mLock
        End Get
    End Property
    ''' <summary>
    ''' Retourne l'ID (code utilisateur)
    ''' </summary>
    ''' <remarks></remarks>
    Public ReadOnly Property ID() As Integer
        Get
            Return mID
        End Get
    End Property
    ''' <summary>
    ''' Indique si il s'agit d'une trame cyclique ?
    ''' </summary>
    ''' <remarks></remarks>
    Public Property IsCyclic() As Boolean
        Get
            Return mIsCyclic
        End Get
        Friend Set(ByVal value As Boolean)
            mIsCyclic = value
        End Set
    End Property
    ''' <summary>
    ''' Retourne la trame à envoyée
    ''' </summary>
    ''' <remarks></remarks>
    Public ReadOnly Property FrameSend() As Frame.ClsFrameModbusBase
        Get
            Return mFrameSend
        End Get
    End Property
    ''' <summary>
    ''' Retourne la trame reçue
    ''' </summary>
    ''' <remarks></remarks>
    Public ReadOnly Property FrameReceive() As Frame.ClsFrameModbusBase
        Get
            Return mFrameReceive
        End Get
    End Property
    ''' <summary>
    ''' Retourne le nombre de réémission si échec
    ''' </summary>
    ''' <remarks></remarks>
    Public ReadOnly Property NbResend() As Integer
        Get
            Return mNbResend
        End Get
    End Property
    ''' <summary>
    ''' Nombre de renvois restant
    ''' </summary>
    ''' <remarks></remarks>
    Public ReadOnly Property LeftResend() As Integer
        Get
            Return mLeftResend
        End Get
    End Property
#End Region

    ''' <summary>
    ''' Décrémente le nombre de réémission restante
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub DecrementResend()
        mLeftResend -= 1
    End Sub
    ''' <summary>
    ''' Utilise le délégué et retourne la trame prioritaitre éventuelle
    ''' </summary>
    ''' <param name="pSender">Emmeteur de l'event</param>
    ''' <returns></returns>
    ''' <remarks>La fonction rajoute automatiquement les trames cycliques et gère les verrous</remarks>
    Public Function RaiseEvt(ByVal pSender As IAnimCom) As SendingFrame
        Dim lPrio As SendingFrame = Nothing
        Try
            lPrio = mDelegate.Invoke(pSender, mFrameSend, mFrameReceive, mID)
        Catch ex As Exception
#If DEBUG Then
            Stop
#End If
        End Try
        If mIsCyclic AndAlso (lPrio Is Nothing OrElse Not TypeOf lPrio.FrameSend Is DeleteCyclicFrame) Then
            pSender.CyclicAdd(New SendingFrame(Me, Nothing))
        ElseIf lPrio Is Nothing OrElse TypeOf lPrio.FrameSend Is DeleteCyclicFrame Then
            lPrio = Nothing
        End If
        If lPrio IsNot Nothing Then
            pSender.CheckLockAdd(lPrio)
        End If
        pSender.CheckLockRmv(Me)
        Return lPrio
    End Function
    ''' <summary>
    ''' Retourne une copie de la SendingFrame
    ''' </summary>
    ''' <param name="pRecvFrame">Trame reçue</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Clone(ByVal pRecvFrame As Frame.ClsFrameModbusBase) As SendingFrame
        Return New SendingFrame(Me, pRecvFrame)
    End Function
End Class
