Imports System.ComponentModel
Imports System.ServiceProcess
Imports System.Configuration.Install
Imports System.Reflection
Imports UTS_Core.UTSModule

Public Class UtsService
    ''' <summary>
    ''' 描述服务的状态
    ''' </summary>
    Enum ServiceStatusEnum
        <Description("未知")>
        Unknown
        <Description("不存在")>
        Nonentity
        <Description("已存在")>
        Exists
        <Description("停止中")>
        StopPending
        <Description("已停止")>
        Stopped
        <Description("启动中")>
        StartPending
        <Description("已启动")>
        Started
    End Enum


    Private ReadOnly _rootDirPath As String

    Private _name As String

    Private _version As String

    Private _versionDirPath As String

    Private _serviceDirPath As String

    Private _fileName As String

    Private _filePath As String


    ''' <summary>
    ''' 服务名称,服务版本
    ''' </summary>
    ''' <param name="name">服务名称</param>
    ''' <param name="version">服务版本</param>
    Sub New(name As String, version As String)
        _rootDirPath = UtsRegistry.RootPath

        _name = name

        _version = version

        _serviceDirPath = $"{_rootDirPath}\{_name}"

        _versionDirPath = $"{_serviceDirPath}\{_version}"

        _fileName = $"{_name}.exe"

        _filePath = $"{_versionDirPath}\{_fileName}"

        If String.IsNullOrWhiteSpace(_name) Then
            Throw New Exception($"Service name is null or whitespace!")
        End If

        If String.IsNullOrWhiteSpace(_version) Then
            Throw New Exception($"Service version is null or whitespace!")
        End If

        If IO.Directory.Exists(_rootDirPath) = False Then
            Throw New Exception($"RootDirPath is not exists!")
        End If
    End Sub

    Sub New(name As String, version As String, rootDirPath As String)
        _name = name

        _version = version

        _rootDirPath = rootDirPath

        _serviceDirPath = $"{_rootDirPath}\{_name}"

        _versionDirPath = $"{_serviceDirPath}\{_version}"

        _fileName = $"{_name}.exe"

        _filePath = $"{_versionDirPath}\{_fileName}"

        If String.IsNullOrWhiteSpace(_name) Then
            Throw New Exception($"Service name is null or whitespace!")
        End If

        If String.IsNullOrWhiteSpace(_version) Then
            Throw New Exception($"Service version is null or whitespace!")
        End If

        If IO.Directory.Exists(_rootDirPath) = False Then
            Throw New Exception($"RootDirPath is not exists!")
        End If
    End Sub


    Property Name() As String
        Get
            Return _name
        End Get
        Set
            _name = Value
            _serviceDirPath = $"{_rootDirPath}\{_name}"
            _versionDirPath = $"{_serviceDirPath}\{_version}"
            _fileName = $"{_name}.exe"
            _filePath = $"{_versionDirPath}\{_fileName}"
        End Set
    End Property

    Property Version() As String
        Get
            Return _version
        End Get
        Set(value As String)
            _version = value
            _versionDirPath = $"{_serviceDirPath}\{_version}"
            _filePath = $"{_versionDirPath}\{_fileName}"
        End Set
    End Property

    ReadOnly Property VersionDirPath() As String
        Get
            Return _versionDirPath
        End Get
    End Property

    ReadOnly Property ServiceDirPath() As String
        Get
            Return _serviceDirPath
        End Get
    End Property

    ReadOnly Property FileName() As String
        Get
            Return _fileName
        End Get
    End Property

    ReadOnly Property FilePath() As String
        Get
            Return _filePath
        End Get
    End Property


    ''' <summary>
    ''' 获取枚举描述特性
    ''' </summary>
    ''' <param name="enumValue">需要获取特性的枚举值</param>
    ''' <returns>枚举描述特性</returns>
    Public Shared Function GetEnumDescription(enumValue As [Enum]) As String
        Dim fi As FieldInfo = enumValue.GetType().GetField(enumValue.ToString())
        Dim attr() As DescriptionAttribute =
                DirectCast(fi.GetCustomAttributes(GetType(DescriptionAttribute),
                                                  False), DescriptionAttribute())

        If attr.Length > 0 Then
            Return attr(0).Description
        Else
            Return enumValue.ToString()
        End If
    End Function


    ''' <summary>
    ''' 检测服务是否存在
    ''' </summary>
    ''' <returns>服务是否存在</returns>
    Public Function ServicesExists() As Boolean
        Dim services() As ServiceController = ServiceController.GetServices
        For Each service As ServiceController In services
            If service.ServiceName = _name Then
                Return True
            End If
        Next
        Return False
    End Function


    ''' <summary>
    ''' 获取服务的状态
    ''' </summary>
    ''' <returns></returns>
    Public Function ServicesStatus() As ServiceStatusEnum
        Dim status As ServiceStatusEnum
        Try
            If ServicesExists() Then
                status = ServiceStatusEnum.Exists

                Try
                    Dim service As New ServiceController(_name)
                    If service.Status = ServiceControllerStatus.Running Then
                        status = ServiceStatusEnum.Started
                    ElseIf service.Status = ServiceControllerStatus.StartPending OrElse
                           service.Status = ServiceControllerStatus.ContinuePending Then
                        status = ServiceStatusEnum.StartPending
                    ElseIf service.Status = ServiceControllerStatus.StopPending OrElse
                           service.Status = ServiceControllerStatus.PausePending Then
                        status = ServiceStatusEnum.StopPending
                    Else
                        status = ServiceStatusEnum.Stopped
                    End If
                Catch ex As Exception
                    Console.WriteLine($"ServicesStatus Error:{ex.Message}")
                End Try
            Else
                status = ServiceStatusEnum.Nonentity
            End If
        Catch ex As Exception
            status = ServiceStatusEnum.Unknown
            Console.WriteLine($"Check ServicesStatus Error:{ex.Message}")
        End Try
        Return status
    End Function

    ''' <summary>
    ''' 安装服务
    ''' </summary>
    ''' <param name="savedState">服务状态，未知字段</param>
    Public Sub InstallService(Optional savedState As IDictionary = Nothing)

        Dim app As AppDomain = AppDomain.CreateDomain("MyDomain")
        Dim assName As String = GetType(AssemblyInstaller).Assembly.FullName
        Dim fullName As String = GetType(AssemblyInstaller).FullName

        Using installer As AssemblyInstaller = CType(app.CreateInstanceAndUnwrap(assName, fullName), AssemblyInstaller)
            installer.UseNewContext = True
            installer.Path = _filePath
            installer.Install(savedState)
            installer.Commit(savedState)
            installer.Dispose()
        End Using

        AppDomain.Unload(app)
        GC.Collect()

    End Sub


    ''' <summary>
    ''' 卸载服务
    ''' </summary>
    ''' <param name="savedState">服务状态，未知字段</param>
    Public Sub UnInstallService(Optional savedState As IDictionary = Nothing)

        Dim app As AppDomain = AppDomain.CreateDomain("MyDomain")
        Dim assName As String = GetType(AssemblyInstaller).Assembly.FullName
        Dim fullName As String = GetType(AssemblyInstaller).FullName

        Using installer As AssemblyInstaller = CType(app.CreateInstanceAndUnwrap(assName, fullName), AssemblyInstaller)
            installer.UseNewContext = True
            installer.Path = _filePath
            installer.Uninstall(savedState)
        End Using

        AppDomain.Unload(app)
        GC.Collect()

    End Sub



    ''' <summary>
    ''' 开启服务
    ''' </summary>
    Public Sub StartService()
        Using service As ServiceController = New ServiceController(_name)
            If service.Status <> ServiceControllerStatus.Running OrElse
               service.Status <> ServiceControllerStatus.StartPending OrElse
               service.Status <> ServiceControllerStatus.ContinuePending Then
                service.Start()
            End If
        End Using
    End Sub


    ''' <summary>
    ''' 关闭服务
    ''' </summary>
    Public Sub StopService()
        Using service As ServiceController = New ServiceController(_name)
            If service.Status = ServiceControllerStatus.Running OrElse
               service.Status = ServiceControllerStatus.StartPending OrElse
               service.Status = ServiceControllerStatus.ContinuePending Then
                service.Stop()
            End If
        End Using
    End Sub

    ''' <summary>
    ''' 重启服务
    ''' </summary>
    Public Sub RestartService()
        Using service As ServiceController = New ServiceController(_name)
            If service.Status = ServiceControllerStatus.Running OrElse
               service.Status = ServiceControllerStatus.StartPending OrElse
               service.Status = ServiceControllerStatus.ContinuePending Then
                service.Stop()

                While service.Status = ServiceControllerStatus.Running AndAlso
                      service.Status = ServiceControllerStatus.StopPending
                    service.Refresh()
                    Threading.Thread.Sleep(20)
                End While
            End If
            Threading.Thread.Sleep(100)
            service.Start()
        End Using
    End Sub

End Class
