'****************************************************************************
'* Archie Jacobs
'* Manufacturing Automation, LLC
'* ajacobs@mfgcontrol.com
'* 12-JUN-11
'*
'* Copyright 2011 Archie Jacobs
'*
'* Distributed under the GNU General Public License (www.gnu.org)
'*
'* This program is free software; you can redistribute it and/or
'* as published by the Free Software Foundation; either version 2
'* of the License, or (at your option) any later version.
'*
'* This program is distributed in the hope that it will be useful,
'* but WITHOUT ANY WARRANTY; without even the implied warranty of
'* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
'* GNU General Public License for more details.

'* You should have received a copy of the GNU General Public License
'* along with this program; if not, write to the Free Software
'* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
'*
'* 12-JUN-11 Created
'****************************************************************************
'<System.ComponentModel.Designer(GetType(MyLabelDesigner))> _
Public Class Gauge
    Inherits MfgControl.AdvancedHMI.Controls.Gauge


#Region "Properties"
    Private SavedBackColor As System.Drawing.Color
    Private NotificationIDText As Integer

    '******************************************************************************************
    '* Use the base control's text property and make it visible as a property on the designer
    '******************************************************************************************
    <System.ComponentModel.Browsable(True)> _
<System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Visible)> _
Public Overrides Property Text() As String
        Get
            Return MyBase.Text
        End Get
        Set(ByVal value As String)
            If m_Format <> "" And (Not DesignMode) Then
                Try
                    MyBase.Text = Format(CSng(value) * _ScaleFactor, m_Format)
                Catch ex As Exception
                    MyBase.Text = "Check NumbericFormat and variable type"
                End Try
            Else
                '* Highlight in red if an exclamation mark is in text
                If InStr(value, "!") > 0 Then
                    If MyBase.BackColor <> _Highlightcolor Then SavedBackColor = MyBase.BackColor
                    MyBase.BackColor = _Highlightcolor
                Else
                    If SavedBackColor <> Nothing Then MyBase.BackColor = SavedBackColor
                End If

                If _ScaleFactor = 1 Then
                    MyBase.Text = value
                Else
                    MyBase.Text = value * _ScaleFactor
                End If
            End If
        End Set
    End Property

    '***************************************************************
    '* Property - Highlight Color
    '***************************************************************
    Private _Highlightcolor As Drawing.Color = Drawing.Color.Red
    Public Property HighlightColor() As Drawing.Color
        Get
            Return _Highlightcolor
        End Get
        Set(ByVal value As Drawing.Color)
            _Highlightcolor = value
        End Set
    End Property



    Private m_Format As String
    Public Property NumericFormat() As String
        Get
            Return m_Format
        End Get
        Set(ByVal value As String)
            m_Format = value
        End Set
    End Property

    Private _ScaleFactor As Decimal = 1
    Public Property ScaleFactor() As Decimal
        Get
            Return _ScaleFactor
        End Get
        Set(ByVal value As Decimal)
            _ScaleFactor = value
        End Set
    End Property

    '*****************************************************
    '* Property - Component to communicate to PLC through
    '*****************************************************
    Private _CommComponent As ICommComponent
    Public Property CommComponent() As ICommComponent
        Get
            Return _CommComponent
        End Get
        Set(ByVal value As ICommComponent)
            _CommComponent = value
        End Set
    End Property


    '*****************************************
    '* Property - Address in PLC to Link to
    '*****************************************
    Private m_PLCaddressText As String = ""
    Public Property PLCaddressText() As String
        Get
            Return m_PLCaddressText
        End Get
        Set(ByVal value As String)
            If m_PLCaddressText <> value Then
                m_PLCaddressText = value

                '* When address is changed, re-subscribe to new address
                SubscribeToCommDriver()
            End If
        End Set
    End Property

    '*****************************************
    '* Property - Address in PLC to Link to
    '*****************************************
    Private NotificationIDVisibility As Integer
    Private m_PLCaddressVisibility As String = ""
    Public Property PLCaddressVisibility() As String
        Get
            Return m_PLCaddressVisibility
        End Get
        Set(ByVal value As String)
            If m_PLCaddressVisibility <> value Then
                m_PLCaddressVisibility = value
                SubscribeToCommDriver()
            End If
        End Set
    End Property

    '*****************************************
    '* Property - Address in PLC to Link to
    '*****************************************
    Private NotificationIDValue As Integer
    Private m_PLCaddressValue As String = ""
    Public Property PLCaddressValue() As String
        Get
            Return m_PLCaddressValue
        End Get
        Set(ByVal value As String)
            If m_PLCaddressValue <> value Then
                m_PLCaddressValue = value
                SubscribeToCommDriver()
            End If
        End Set
    End Property

#End Region

#Region "Events"
    'Protected Overrides Sub OnHandleCreated(ByVal e As EventArgs)
    'End Sub

    '********************************************************************
    '* When an instance is added to the form, set the comm component
    '* property. If a comm component does not exist, add one to the form
    '********************************************************************
    Protected Overrides Sub OnCreateControl()
        MyBase.OnCreateControl()

        If Me.DesignMode Then
            '********************************************************
            '* Search for ICommComponent component in parent form
            '* If one exists, set the client of this component to it
            '********************************************************
            Dim i = 0
            Dim j As Integer = Me.Parent.Site.Container.Components.Count - 1
            While _CommComponent Is Nothing And i < j
                If Me.Parent.Site.Container.Components(i).GetType.GetInterface("ICommComponent") IsNot Nothing Then _CommComponent = Me.Parent.Site.Container.Components(i)
                i += 1
            End While

            '************************************************
            '* If no comm component was found, then add one and
            '* point the CommComponent property to it
            '*********************************************
            If _CommComponent Is Nothing Then
                Me.Parent.Site.Container.Add(New TwinCATComm)
                _CommComponent = Me.Parent.Site.Container.Components(Me.Parent.Site.Container.Components.Count - 1)
            End If
        Else
            SubscribeToCommDriver()
        End If
    End Sub

    '****************************************************************
    '* UserControl overrides dispose to clean up the component list.
    '****************************************************************
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing And _CommComponent IsNot Nothing Then
                _CommComponent.UnSubscribe(NotificationIDText)
                _CommComponent.UnSubscribe(NotificationIDVisibility)
                _CommComponent.UnSubscribe(NotificationIDValue)
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub
#End Region

    '**************************************************
    '* Subscribe to addresses in the Comm(PLC) Driver
    '**************************************************
    Private SubscribedPLCAddressText As String
    Private SubscribedPLCAddressVisibility As String
    Private SubscribedPLCAddressValue As String
    Private Sub SubscribeToCommDriver()
        If Not DesignMode And IsHandleCreated Then
            '*************************
            '* Text Subscription
            '*************************
            If SubscribedPLCAddressText <> m_PLCaddressText Then
                '* If already subscribed, but address is changed, then unsubscribe first
                If NotificationIDText > 0 Then
                    _CommComponent.UnSubscribe(NotificationIDText)
                End If
                '* Is there an address to subscribe to?
                If m_PLCaddressText <> "" Then
                    Try
                        If _CommComponent IsNot Nothing Then
                            'NotificationIDText = _CommComponent.Subscribe(m_PLCaddressText, 250, AddressOf PolledDataReturnedText)
                            NotificationIDText = _CommComponent.Subscribe(m_PLCaddressText, 250, AddressOf PolledDataReturnedText, " ", 0)

                            '* If subscription succeedded, save the address and dispose of the retry timer
                            SubscribedPLCAddressText = m_PLCaddressText
                        Else
                            DisplayError("CommComponent Property not set")
                        End If
                    Catch ex As MfgControl.AdvancedHMI.Drivers.PLCDriverException
                        '* If subscribe fails, set up for retry
                        InitializeSubscribeRetry(ex, m_PLCaddressText)
                    End Try
                End If
            End If

            '*************************
            '* Visbility Subscription
            '*************************
            If SubscribedPLCAddressVisibility <> m_PLCaddressVisibility Then
                '* If already subscribed, but address is changed, then unsubscribe first
                If NotificationIDVisibility > 0 Then
                    _CommComponent.UnSubscribe(NotificationIDVisibility)
                End If
                '* Is there an address to subscribe to?
                If m_PLCaddressVisibility <> "" Then
                    Try
                        If _CommComponent IsNot Nothing Then
                            'NotificationIDVisibility = _CommComponent.Subscribe(m_PLCaddressVisibility, 250, AddressOf PolledDataReturnedVisibility)
                            NotificationIDVisibility = _CommComponent.Subscribe(m_PLCaddressVisibility, 250, AddressOf PolledDataReturnedVisibility, " ", 0)

                            SubscribedPLCAddressVisibility = m_PLCaddressVisibility
                        Else
                            DisplayError("CommComponent Property not set")
                        End If
                    Catch ex As MfgControl.AdvancedHMI.Drivers.PLCDriverException
                        '* If subscribe fails, set up for retry
                        InitializeSubscribeRetry(ex, m_PLCaddressVisibility)
                    End Try
                End If
            End If

            '*************************
            '* Value Subscription
            '*************************
            If SubscribedPLCAddressValue <> m_PLCaddressValue Then
                '* If already subscribed, but address is changed, then unsubscribe first
                If NotificationIDValue > 0 Then
                    _CommComponent.UnSubscribe(NotificationIDValue)
                End If
                '* Is there an address to subscribe to?
                If m_PLCaddressValue <> "" Then
                    Try
                        If _CommComponent IsNot Nothing Then
                            'NotificationIDValue = _CommComponent.Subscribe(m_PLCaddressValue, 250, AddressOf PolledDataReturnedValue)
                            NotificationIDValue = _CommComponent.Subscribe(m_PLCaddressValue, 250, AddressOf PolledDataReturnedValue, " ", 0)

                            SubscribedPLCAddressValue = m_PLCaddressValue
                        Else
                            DisplayError("CommComponent Property not set")
                        End If
                    Catch ex As MfgControl.AdvancedHMI.Drivers.PLCDriverException
                        '* If subscribe fails, set up for retry
                        InitializeSubscribeRetry(ex, m_PLCaddressValue)
                    End Try
                End If
            End If
        End If
    End Sub

    '********************************************
    '* Show the error and start the retry time
    '********************************************
    Private Sub InitializeSubscribeRetry(ByVal ex As MfgControl.AdvancedHMI.Drivers.PLCDriverException, ByVal PLCAddress As String)
        If ex.ErrorCode = 1808 Then
            DisplayError("""" & PLCAddress & """ PLC Address not found")
        Else
            DisplayError(ex.Message)
        End If

        If SubscribeRetryTimer Is Nothing Then
            SubscribeRetryTimer = New Windows.Forms.Timer
            SubscribeRetryTimer.Interval = 10000
            AddHandler SubscribeRetryTimer.Tick, AddressOf Retry_Tick
        End If

        SubscribeRetryTimer.Enabled = True
    End Sub


    '********************************************
    '* Keep retrying to subscribe if it failed
    '********************************************
    Private SubscribeRetryTimer As Windows.Forms.Timer
    Private Sub Retry_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs)
        SubscribeRetryTimer.Enabled = False
        SubscribeRetryTimer.Dispose()
        SubscribeRetryTimer = Nothing

        SubscribeToCommDriver()
    End Sub

    '***************************************
    '* Call backs for returned data
    '***************************************
    Private OriginalText As String
    Private Sub PolledDataReturnedText(ByVal Values() As String)
        Try
            Text = Values(0)
        Catch
            DisplayError(Values(0) & "-INVALID Text VALUE RETURNED!")
        End Try
    End Sub


    Private Sub PolledDataReturnedVisibility(ByVal Values() As String)
        Try
            MyBase.Visible = Values(0)
        Catch
            DisplayError(Values(0) & "-INVALID Visibilty VALUE RETURNED!")
        End Try
    End Sub


    Private Sub PolledDataReturnedValue(ByVal Values() As String)
        Try
            MyBase.Value = Values(0)
        Catch
            DisplayError(Values(0) & "-INVALID VALUE RETURNED!")
        End Try
    End Sub

    '********************************************************
    '* Show an error via the text property for a short time
    '********************************************************
    Private WithEvents ErrorDisplayTime As System.Windows.Forms.Timer
    Private Sub DisplayError(ByVal ErrorMessage As String)
        If ErrorDisplayTime Is Nothing Then
            ErrorDisplayTime = New System.Windows.Forms.Timer
            AddHandler ErrorDisplayTime.Tick, AddressOf ErrorDisplay_Tick
            ErrorDisplayTime.Interval = 5000
        End If

        '* Save the text to return to
        If Not ErrorDisplayTime.Enabled Then
            OriginalText = Me.Text
        End If

        ErrorDisplayTime.Enabled = True

        Me.Text = ErrorMessage
    End Sub


    '**************************************************************************************
    '* Return the text back to its original after displaying the error for a few seconds.
    '**************************************************************************************
    Private Sub ErrorDisplay_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs)
        Text = OriginalText

        If ErrorDisplayTime IsNot Nothing Then
            ErrorDisplayTime.Enabled = False
            ErrorDisplayTime.Dispose()
            ErrorDisplayTime = Nothing
        End If
    End Sub

End Class
