''' <summary>
''' Classe de gestion d'un esclave
''' </summary>
''' <remarks></remarks>
Public NotInheritable Class SlaveManager

    ''' <summary>
    ''' Delegate de l'evenement FrameRecept
    ''' </summary>
    ''' <param name="pSender">Emmeteur de l'event</param>
    ''' <param name="pFrameReceived">Trame reçue</param>
    ''' <param name="pFrameSend">Trame à répondre</param>
    ''' <remarks></remarks>
    Public Delegate Sub DlgFrameRecept(ByVal pSender As SlaveManager, ByVal pFrameReceived As Frame.ClsFrameModbusBase, ByRef pFrameSend As Frame.ClsFrameModbusBase)

    ''' <summary>
    ''' Evenement géréré lors de la réception d'un trame concernant l'esclave et hors des tables définies
    ''' </summary>
    ''' <remarks></remarks>
    Public Event FrameRecept As DlgFrameRecept

    ''' <summary>
    ''' Récepteur Modbus
    ''' </summary>
    ''' <remarks></remarks>
    Private WithEvents mRecept As IRecepteur
    ''' <summary>
    ''' Table de lecture
    ''' </summary>
    ''' <remarks></remarks>
    Private mReadTable As DataTable()
    ''' <summary>
    ''' Table d'écriture
    ''' </summary>
    ''' <remarks></remarks>
    Private mWriteTable As DataTable()
    ''' <summary>
    ''' Liste des esclaves interceptés
    ''' </summary>
    ''' <remarks></remarks>
    Private mSlaveIds As Byte()

    ''' <summary>
    ''' Constructeur de la classe
    ''' </summary>
    ''' <param name="pRecepter">Recepteur Modbus</param>
    ''' <param name="pSlaveIds">ID d'esclave à écouter</param>
    ''' <param name="pReadTable">Tables de lecture</param>
    ''' <param name="pWriteTable">Tables d'écriture</param>
    ''' <remarks></remarks>
    Public Sub New(ByVal pRecepter As IRecepteur, ByVal pSlaveIds As Byte(), ByVal pReadTable As DataTable(), ByVal pWriteTable As DataTable())
        mRecept = pRecepter
        If pReadTable Is Nothing Then
            pReadTable = New DataTable() {}
        End If
        mReadTable = pReadTable
        If mWriteTable Is Nothing Then
            mWriteTable = New DataTable() {}
        End If
        mWriteTable = pWriteTable
        mSlaveIds = pSlaveIds
    End Sub

    ''' <summary>
    ''' Reception
    ''' </summary>
    ''' <param name="pSender"></param>
    ''' <param name="pFrameReceived"></param>
    ''' <param name="pFrameSend"></param>
    ''' <remarks></remarks>
    Private Sub mRecept_FrameRececpt(ByVal pSender As IRecepteur, ByVal pFrameReceived As Frame.ClsFrameModbusBase, ByRef pFrameSend As Frame.ClsFrameModbusBase) Handles mRecept.FrameRececpt
        If Array.IndexOf(mSlaveIds, pFrameReceived.SlaveId) = -1 Then
            Return
        End If

        If TypeOf pFrameReceived Is Frame.ClsFrameModbus04Req Then
            'Lecture
            Dim lFrame As Frame.ClsFrameModbus04Req = DirectCast(pFrameReceived, Frame.ClsFrameModbus04Req)


            For Each lTable As DataTable In mReadTable
                If lTable.Offset <= lFrame.Offset AndAlso (lTable.Offset + lTable.Length) >= (lFrame.Offset + lFrame.Length) Then
                    pFrameSend = New Frame.ClsFrameModbus04Rep(lFrame.SlaveId, lTable.GetArrayShort(lFrame.Offset, lFrame.Length))
                End If
            Next
            If pFrameSend Is Nothing Then
                RaiseEvt(pFrameReceived, pFrameSend)
            End If
        ElseIf TypeOf pFrameReceived Is Frame.ClsFrameModbus03Req Then
            'Lecture
            Dim lFrame As Frame.ClsFrameModbus03Req = DirectCast(pFrameReceived, Frame.ClsFrameModbus03Req)

            For Each lTable As DataTable In mReadTable
                If lTable.Offset <= lFrame.Offset AndAlso (lTable.Offset + lTable.Length) >= (lFrame.Offset + lFrame.Length) Then
                    pFrameSend = New Frame.ClsFrameModbus03Rep(lFrame.SlaveId, lTable.GetArrayShort(lFrame.Offset, lFrame.Length))
                End If
            Next
            If pFrameSend Is Nothing Then
                RaiseEvt(pFrameReceived, pFrameSend)
            End If
        ElseIf TypeOf pFrameReceived Is Frame.ClsFrameModbus16Req Then
                'Ecriture
                Dim lFrame As Frame.ClsFrameModbus16Req = DirectCast(pFrameReceived, Frame.ClsFrameModbus16Req)

            For Each lTable As DataTable In mWriteTable
                If lTable.Offset <= lFrame.Offset AndAlso (lTable.Offset + lTable.Length) >= (lFrame.Offset + lFrame.Count) Then
                    Dim lOffset As UShort = lFrame.Offset - lTable.Offset
                    For i As UShort = 0 To CUShort(lFrame.Count - 1)
                        lTable.UInt16(i + lOffset) = lFrame.UInt16(i)
                    Next
                    pFrameSend = New Frame.ClsFrameModbus16Rep(lFrame.SlaveId, lFrame.Offset, CByte(lFrame.Count))
                End If
            Next
            If pFrameSend Is Nothing Then
                RaiseEvt(pFrameReceived, pFrameSend)
            End If
        Else
                'Autre
                RaiseEvt(pFrameReceived, pFrameSend)
        End If
    End Sub
    ''' <summary>
    ''' Génère l'event
    ''' </summary>
    ''' <param name="pFrameReceived"></param>
    ''' <param name="pFrameSend"></param>
    ''' <remarks></remarks>
    Private Sub RaiseEvt(ByVal pFrameReceived As Frame.ClsFrameModbusBase, ByRef pFrameSend As Frame.ClsFrameModbusBase)
        Try
            RaiseEvent FrameRecept(Me, pFrameReceived, pFrameSend)
        Catch ex As Exception
#If DEBUG Then
            Stop
#End If
        End Try
    End Sub
    ''' <summary>
    ''' Arrête la gestion
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub Close()
        mRecept = Nothing
    End Sub

    ''' <summary>
    ''' Retourne la table de lecture
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property ReadTable() As DataTable()
        Get
            Return mReadTable
        End Get
    End Property
    ''' <summary>
    ''' Retourne la table d'écriture
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property WriteTable() As DataTable()
        Get
            Return mWriteTable
        End Get
    End Property
    ''' <summary>
    ''' Retourne la liste des esclaves à gérer
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property SlaveIds() As Byte()
        Get
            Return mSlaveIds
        End Get
    End Property
    ''' <summary>
    ''' Retourne le récepteur Modbus
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property Recept() As IRecepteur
        Get
            Return mRecept
        End Get
    End Property
End Class
