'****************************************************************************
'* 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
'****************************************************************************
Public Class BasicButton
    Inherits System.Windows.Forms.Button


#Region "Basic Properties"
    '***************************************************************
    '* Property - Highlight Color
    '***************************************************************
    Private _Highlightcolor As Drawing.Color = Drawing.Color.Green
    Public Property HighlightColor() As Drawing.Color
        Get
            Return _Highlightcolor
        End Get
        Set(ByVal value As Drawing.Color)
            _Highlightcolor = value
        End Set
    End Property

    '***************************************************************
    '* Property - If value from PLC is true, then highlight button
    '***************************************************************
    Private OriginalBackcolor As Drawing.Color
    Private _Highlight As Boolean
    Public Property Highlight() As Boolean
        Get
            Return _Highlight
        End Get
        Set(ByVal value As Boolean)
            If OriginalBackcolor.R = 0 And OriginalBackcolor.G = 0 And OriginalBackcolor.B = 0 Then OriginalBackcolor = MyBase.BackColor
            If value Then
                MyBase.BackColor = _Highlightcolor
            Else
                MyBase.BackColor = OriginalBackcolor
            End If

            _Highlight = value
        End Set
    End Property
#End Region

#Region "PLC Related Properties"
    '*****************************************************
    '* Property - Component to communicate to PLC through
    '*****************************************************
    Private _CommComponent As ICommComponent
    <System.ComponentModel.Category("PLC Properties")> _
    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 for click event
    '********************************************
    Private _PLCaddressClick As String = ""
    <System.ComponentModel.Category("PLC Properties")> _
    Public Property PLCaddressClick() As String
        Get
            Return _PLCaddressClick
        End Get
        Set(ByVal value As String)
            _PLCaddressClick = value
        End Set
    End Property

    '*****************************************
    '* Property - Address in PLC to Link to
    '*****************************************
    Private NotificationIDHighlight As Integer
    Private _PLCaddressHighlight As String = ""
    <System.ComponentModel.Category("PLC Properties")> _
    Public Property PLCaddressHighlight() As String
        Get
            Return _PLCaddressHighlight
        End Get
        Set(ByVal value As String)
            If _PLCaddressHighlight <> value Then
                _PLCaddressHighlight = 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 _PLCaddressVisibility As String = ""
    <System.ComponentModel.Category("PLC Properties")> _
    Public Property PLCaddressVisibility() As String
        Get
            Return _PLCaddressVisibility
        End Get
        Set(ByVal value As String)
            _PLCaddressVisibility = value
        End Set
    End Property

    '*****************************************
    '* Property - What to do to bit in PLC
    '*****************************************
    Private _OutputType As MfgControl.AdvancedHMI.Controls.OutputType = MfgControl.AdvancedHMI.Controls.OutputType.MomentarySet
    <System.ComponentModel.Category("PLC Properties")> _
    Public Property OutputType() As MfgControl.AdvancedHMI.Controls.OutputType
        Get
            Return _OutputType
        End Get
        Set(ByVal value As MfgControl.AdvancedHMI.Controls.OutputType)
            _OutputType = value
        End Set
    End Property
#End Region

#Region "Events"
    '****************************
    '* Event - Mouse Down
    '****************************
    Private Sub MomentaryButton_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
        If _PLCaddressClick <> "" Then
            Try
                Select Case _OutputType
                    Case MfgControl.AdvancedHMI.Controls.OutputType.MomentarySet : _CommComponent.WriteData(_PLCaddressClick, 1, "Bit", 0)
                        'Case MfgControl.AdvancedHMI.Controls.OutputType.MomentarySet : _CommComponent.WriteData(_PLCaddressClick, 1)
                    Case MfgControl.AdvancedHMI.Controls.OutputType.MomentaryReset : _CommComponent.WriteData(_PLCaddressClick, 0, "Bit", 0)
                        'Case MfgControl.AdvancedHMI.Controls.OutputType.MomentaryReset : _CommComponent.WriteData(_PLCaddressClick, 0)
                    Case MfgControl.AdvancedHMI.Controls.OutputType.SetTrue : _CommComponent.WriteData(_PLCaddressClick, 1, "Bit", 0)
                        'Case MfgControl.AdvancedHMI.Controls.OutputType.SetTrue : _CommComponent.WriteData(_PLCaddressClick, 1)
                    Case MfgControl.AdvancedHMI.Controls.OutputType.SetFalse : _CommComponent.WriteData(_PLCaddressClick, 0, "Bit", 0)
                        'Case MfgControl.AdvancedHMI.Controls.OutputType.SetFalse : _CommComponent.WriteData(_PLCaddressClick, 0)
                    Case MfgControl.AdvancedHMI.Controls.OutputType.Toggle
                        Dim CurrentValue As Boolean
                        CurrentValue = _CommComponent.ReadAny(_PLCaddressClick)
                        If CurrentValue Then
                            _CommComponent.WriteData(_PLCaddressClick, 0, "Bit", 0)
                            '_CommComponent.WriteData(_PLCaddressClick, 0)
                        Else
                            _CommComponent.WriteData(_PLCaddressClick, 1, "Bit", 0)
                            '_CommComponent.WriteData(_PLCaddressClick, 1)
                        End If
                End Select
            Catch ex As MfgControl.AdvancedHMI.Drivers.PLCDriverException
                If ex.ErrorCode = 1808 Then
                    DisplayError("""" & _PLCaddressClick & """ PLC Address not found")
                Else
                    DisplayError(ex.Message)
                End If
            End Try
        End If
    End Sub


    '****************************
    '* Event - Mouse Up
    '****************************
    Private Sub MomentaryButton_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
        If _PLCaddressClick <> "" Then
            Try
                Select Case _OutputType
                    Case MfgControl.AdvancedHMI.Controls.OutputType.MomentarySet : _CommComponent.WriteData(_PLCaddressClick, 0, "Bit", 0)
                        'Case MfgControl.AdvancedHMI.Controls.OutputType.MomentarySet : _CommComponent.WriteData(_PLCaddressClick, 0)
                    Case MfgControl.AdvancedHMI.Controls.OutputType.MomentaryReset : _CommComponent.WriteData(_PLCaddressClick, 1, "Bit", 0)
                        'Case MfgControl.AdvancedHMI.Controls.OutputType.MomentaryReset : _CommComponent.WriteData(_PLCaddressClick, 1)
                End Select
            Catch ex As MfgControl.AdvancedHMI.Drivers.PLCDriverException
                If ex.ErrorCode = 1808 Then
                    DisplayError("""" & _PLCaddressClick & """ PLC Address not found")
                Else
                    DisplayError(ex.Message)
                End If
            End Try
        End If
    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
#End Region

#Region "Subscribing and PLC data receiving"
    '**************************************************
    '* Subscribe to addresses in the Comm(PLC) Driver
    '**************************************************
    Private SubscribedPLCAddressHighlight As String
    Private SubscribedPLCAddressVisibility As String
    Private Sub SubscribeToCommDriver()
        If Not DesignMode And IsHandleCreated Then
            '*************************
            '* Highlight Subscription
            '*************************
            '* If already subscribed, but address is changed, then unsubscribe first
            If NotificationIDHighlight > 0 And SubscribedPLCAddressHighlight <> _PLCaddressHighlight Then
                _CommComponent.UnSubscribe(NotificationIDHighlight)
            End If
            '* Is there an address to subscribe to?
            If _PLCaddressHighlight <> "" Then
                Try
                    If _CommComponent IsNot Nothing Then
                        'NotificationIDHighlight = _CommComponent.Subscribe(_PLCaddressHighlight, 250, AddressOf PolledDataReturnedHighlight)
                        NotificationIDHighlight = _CommComponent.Subscribe(_PLCaddressHighlight, 250, AddressOf PolledDataReturnedHighlight, "Bit", 0)
                        SubscribedPLCAddressHighlight = _PLCaddressHighlight
                    Else
                        DisplayError("CommComponent Property not set")
                    End If
                Catch ex As MfgControl.AdvancedHMI.Drivers.PLCDriverException
                    '* If subscribe fails, set up for retry
                    InitializeSubscribeRetry(ex, _PLCaddressHighlight)
                End Try
            End If


            '*************************
            '* Visbility Subscription
            '*************************
            '* If already subscribed, but address is changed, then unsubscribe first
            If NotificationIDVisibility > 0 And SubscribedPLCAddressVisibility <> _PLCaddressVisibility Then
                _CommComponent.UnSubscribe(NotificationIDVisibility)
            End If

            '* Is there an address to subscribe to?
            If _PLCaddressVisibility <> "" Then
                Try
                    If _CommComponent IsNot Nothing Then
                        'NotificationIDVisibility = _CommComponent.Subscribe(_PLCaddressVisibility, 250, AddressOf PolledDataReturnedVisibility)
                        NotificationIDVisibility = _CommComponent.Subscribe(_PLCaddressVisibility, 250, AddressOf PolledDataReturnedVisibility, "Bit", 0)

                        SubscribedPLCAddressVisibility = _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, _PLCaddressVisibility)
                End Try
            End If
        End If
    End Sub



    Private SubscribeRetryTimer As Windows.Forms.Timer
    Private Sub Retry_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs)
        SubscribeToCommDriver()
    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


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

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

#Region "Error Display"
    '********************************************************
    '* 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

        MyBase.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) Handles ErrorDisplayTime.Tick
        Text = OriginalText

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

End Class

