Imports System.ServiceProcess
Imports System.ServiceModel
Imports System.Configuration
Imports System.Reflection
Imports System.IO
Imports System.Net.Sockets
Imports GPSConnector.Common
Imports Spring.Context
Imports GPSConnector.Service.Core
Imports Spring.Context.Support
Imports System.Security.Cryptography.X509Certificates
Imports System.Threading

Public Class GPSConnectorService
    Inherits ServiceBase

    Private Shared _serviceHost As ServiceHost = Nothing
    Private Shared _gpsConnectorServiceSetting As GPSConnectorServiceSetting
    Private Shared ReadOnly _lockObjectTmr As New Object
    Private Shared tmrServiceMonitor As Timer
    Private Shared _database As IDatabase
    'Private Shared RestartCount As Integer
    Public Sub New()
        InitializeComponent()
        ' Name the Windows Service
        ServiceName = "GPSConnectorService"
    End Sub
    Protected Overrides Sub OnStart(ByVal args() As String)
        StartService()
    End Sub

    Private Shared Sub StartService()
        log4net.Config.XmlConfigurator.Configure()

        Dim ctx As IApplicationContext = ContextRegistry.GetContext()
        _gpsConnectorServiceSetting = CType(ctx.GetObject("GPSConnectorServiceSetting"), GPSConnectorServiceSetting)

        _database = CType(ctx.GetObject("IDatabase"), IDatabase)

        _gpsConnectorServiceSetting.Logger.LogInformation("Starting GpsConnector service in console mode, press any key to stop the service ", "GPSConnectorService")

        If ConfigurationManager.AppSettings("EnablePicoTrackDeployment") = "true" Then
            _database.ResetAllDeploymentState()
        End If

        If Not _gpsConnectorServiceSetting.Components Is Nothing AndAlso _gpsConnectorServiceSetting.Components.Count > 0 Then
            For Each component In _gpsConnectorServiceSetting.Components
                component.Start()
            Next
        End If
        If Not _gpsConnectorServiceSetting.CustomServices Is Nothing AndAlso _gpsConnectorServiceSetting.CustomServices.Count > 0 Then

            For Each customService In _gpsConnectorServiceSetting.CustomServices
                customService.Start()
            Next
        End If

        If ConfigurationManager.AppSettings("EnableWCF") = "true" Then
            StartServiceHost()
        End If

        tmrServiceMonitor = New Timer(AddressOf HeartBeatMonitor, Nothing, 90000, 90000)

    End Sub

    Private Shared Sub StartServiceHost()

        If _serviceHost IsNot Nothing Then
            Try
                _gpsConnectorServiceSetting.Logger.LogInformation("Stopping WCF Service ", "GPSConnectorService")

                _serviceHost.Abort()
                _serviceHost.Close(TimeSpan.FromMilliseconds(100))
                Thread.Sleep(2000)
            Catch ex As Exception

            End Try

        End If

        ' Create a ServiceHost for the CalculatorService type and 
        ' provide the base address.
        _serviceHost = New ServiceHost(GetType(GPSConnectorStatusService))

        'Set the servis certificates.

        Dim sCertFile As String = ConfigurationManager.AppSettings("ServiceCertFileName")
        Dim sCertPassword As String = ConfigurationManager.AppSettings("ServiceCertPassword")
        Dim fileInfo As FileInfo = New FileInfo(Assembly.GetExecutingAssembly().Location)
        Dim sCertFileFullPath As String = Path.Combine(fileInfo.DirectoryName, sCertFile)

        _serviceHost.Credentials.ServiceCertificate.Certificate = New X509Certificate2(sCertFileFullPath, sCertPassword)

        ' Open the ServiceHostBase to create listeners and start 
        ' listening for messages.
        _gpsConnectorServiceSetting.Logger.LogInformation("Starting WCF Service ", "GPSConnectorService")

        _serviceHost.Open()
    End Sub

    Private Shared Sub StopService()



        If _serviceHost IsNot Nothing Then
            Try

                _serviceHost.Abort()
                _serviceHost.Close(TimeSpan.FromMilliseconds(100))
                Thread.Sleep(2000)
            Catch ex As Exception

            End Try

        End If
        Try
            If Not _gpsConnectorServiceSetting.Components Is Nothing AndAlso _gpsConnectorServiceSetting.Components.Count > 0 Then
                For Each component In _gpsConnectorServiceSetting.Components
                    component.Stop()
                Next
            End If
            If Not _gpsConnectorServiceSetting.CustomServices Is Nothing AndAlso _gpsConnectorServiceSetting.CustomServices.Count > 0 Then

                For Each customService In _gpsConnectorServiceSetting.CustomServices
                    customService.Stop()
                Next
            End If
            tmrServiceMonitor.Dispose()
        Catch ex As Exception
        End Try
    End Sub
    Protected Overrides Sub OnStop()
        StopService()
    End Sub
    <MTAThread()> _
    Public Shared Sub Main(args() As String)
        AddHandler AppDomain.CurrentDomain.UnhandledException, AddressOf DomainUnhandledException

        If Not args Is Nothing AndAlso args.Length > 0 AndAlso args(0).ToLower = "/console" Then
            StartService()
            Console.ReadLine()
            StopService()
        Else
            Run(New GPSConnectorService())
        End If
    End Sub

    Private Shared Sub DomainUnhandledException(ByVal sender As Object, ByVal e As UnhandledExceptionEventArgs)
        Try
            _gpsConnectorServiceSetting.Logger.LogException(CType(e.ExceptionObject, Exception), "WindowsService", True, True)

        Catch ex As Exception
        Finally
            ExternalRestartService()
        End Try
       
    End Sub

    Private Shared Sub HeartBeatMonitor(sender As Object)
        Dim tcpclient As TcpClient
        Dim stream As NetworkStream
        If Monitor.TryEnter(_lockObjectTmr, 60000) Then
            '_gpsConnectorServiceSetting.Logger.LogInformation("HeartBeat Monitor - Checking Service availability", "HeartBeatMonitor")
            Try
                For Each component In _gpsConnectorServiceSetting.Components
                    Try
                        tcpclient = New TcpClient()
                        tcpclient.Connect("127.0.0.1", component.Port)
                        stream = tcpclient.GetStream()
                        stream.Write(New Byte() {0}, 0, 1)
                        stream.Close()
                        tcpclient.Close()
                        If component.ActiveConnectionCount > _gpsConnectorServiceSetting.Database.GetDeviceCount(component.DeviceTypeName) Then
                            _gpsConnectorServiceSetting.Logger.LogInformation(String.Format("Heartbeat monitor restarting Component : {0} because of reporting activecount of {1}", component.DeviceTypeName, component.ActiveConnectionCount), "HeartBeatMonitor")
                            component.Stop()
                            component.Start()
                        End If
                    Catch ex As Exception
                        _gpsConnectorServiceSetting.Logger.LogException(ex, "Heartbeat")
                        _gpsConnectorServiceSetting.Logger.LogInformation(String.Format("Heartbeat monitor restarting Component : {0} because of it is dead", component.DeviceTypeName), "HeartBeatMonitor")
                        component.Stop()
                        component.Start()
                    End Try
                Next

                If ConfigurationManager.AppSettings("EnableWCF") = "true" Then
                    If _serviceHost Is Nothing OrElse _serviceHost.State <> CommunicationState.Opened Then
                        ExternalRestartService()
                        Return
                    End If
                    Try
                        tcpclient = New TcpClient()
                        tcpclient.Connect(_serviceHost.BaseAddresses(0).Host, _serviceHost.BaseAddresses(0).Port)
                        tcpclient.Close()
                    Catch ex As Exception
                        ExternalRestartService()
                        Return
                    End Try
                End If

            Catch ex As Exception
                _gpsConnectorServiceSetting.Logger.LogException(ex, "HeartBeat Monitor")
            Finally
                Monitor.Exit(_lockObjectTmr)
            End Try
        Else
            _gpsConnectorServiceSetting.Logger.LogInformation("HeartBeat Monitor - failed to enter monitor, requesting restart service", "HeartBeatMonitor")
            ExternalRestartService()
        End If
    End Sub

    Private Shared Sub ExternalRestartService()
        _gpsConnectorServiceSetting.Logger.LogInformation(String.Format("Heartbeat monitor restarting GPSConnectorService using external application"), "HeartBeatMonitor")
        Process.Start(ConfigurationManager.AppSettings("RestartServiceApp"), ConfigurationManager.AppSettings("RestartServiceAppArgument"))
    End Sub
End Class
