Imports System.Threading
Imports System.Text.RegularExpressions

Imports Stax.UI

Public Class ProcessWrapper
    Implements IDisposable

    Private ThrowException As Boolean

    Private ProcessValue As New Process

    Public Property Process() As Process
        Get
            Return ProcessValue
        End Get
        Set(ByVal Value As Process)
            ProcessValue = Value
        End Set
    End Property

    Private WaitValue As Boolean

    Public Property Wait() As Boolean
        Get
            Return WaitValue
        End Get
        Set(ByVal value As Boolean)
            WaitValue = value
        End Set
    End Property

    Public WriteOnly Property Minimized() As Boolean
        Set(ByVal Value As Boolean)
            If Value Then
                Process.StartInfo.WindowStyle = ProcessWindowStyle.Minimized
            Else
                Process.StartInfo.WindowStyle = ProcessWindowStyle.Normal
            End If
        End Set
    End Property

    Private PriorityValue As ProcessPriorityClass = ProcessPriorityClass.Normal

    Public Property Priority() As ProcessPriorityClass
        Get
            Return PriorityValue
        End Get
        Set(ByVal value As ProcessPriorityClass)
            PriorityValue = value
        End Set
    End Property

    Public Property Directory() As String
        Get
            Return Process.StartInfo.WorkingDirectory
        End Get
        Set(ByVal Value As String)
            Process.StartInfo.WorkingDirectory = Value
        End Set
    End Property

    Public Property File() As String
        Get
            Return Process.StartInfo.FileName
        End Get
        Set(ByVal Value As String)
            If Value.Contains("%") Then
                Process.StartInfo.FileName = Environment.ExpandEnvironmentVariables(Value)
            Else
                Process.StartInfo.FileName = Value
            End If
        End Set
    End Property

    Public Property CommandLine() As String
        Get
            Return """" + File + """ " + Arguments
        End Get
        Set(ByVal Value As String)
            Try
                Dim m As Match = Regex.Match(Value, "((?<file>[^\s""]+)|""(?<file>.+?)"") *(?<args>[^\f\r]*)")
                File = m.Groups("file").Value
                Arguments = m.Groups("args").Value
            Catch
                Throw New Exception("Failed to parse command line: " + Value)
            End Try
        End Set
    End Property

    Public Property Arguments() As String
        Get
            Return Process.StartInfo.Arguments
        End Get
        Set(ByVal Value As String)
            Process.StartInfo.Arguments = Value

            If Process.StartInfo.Arguments.Contains("\""") Then
                Process.StartInfo.Arguments = Process.StartInfo.Arguments.Replace("\""", "\\""")
            End If

            If Process.StartInfo.Arguments.Contains("%") Then
                Process.StartInfo.Arguments = Environment.ExpandEnvironmentVariables(Process.StartInfo.Arguments)
            End If
        End Set
    End Property

    Public Sub KillAndThrow()
        ThrowException = True

        Try
            Process.Kill()
        Catch
        End Try
    End Sub

    <DebuggerNonUserCode()> _
    Public Sub Start()
        Try
            Process.Start()
        Catch ex As Exception
            Msg.Show(ToString() + vbCrLf + vbCrLf + ex.ToString, MsgIcon.Error)

            If ThrowException Then
                Throw New AbortException
            End If
        End Try

        Try
            If Priority <> ProcessPriorityClass.Normal Then
                Process.PriorityClass = Priority
            End If

            If Wait Then
                Process.WaitForExit()
                Process.Close()
            End If
        Catch
        End Try

        If ThrowException Then
            Throw New AbortException
        End If
    End Sub

    Public Overrides Function ToString() As String
        Return "File: " + File + vbCrLf + "Arguments: " + Arguments
    End Function

    Public Shared Sub StartFile(ByVal path As String)
        Dim pw As New ProcessWrapper
        pw.File = path
        pw.Start()
    End Sub

    Private DisposedValue As Boolean = False

    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not DisposedValue Then
            If disposing Then
                If Not Process Is Nothing Then
                    Process.Dispose()
                End If
            End If
        End If

        DisposedValue = True
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
End Class