' *
' * The project site is at: http://sourceforge.jp/projects/fishbornas/
' *
' * First author tiritomato 2012.
' *
' * Distributed under the FishbornArchiveShelf License (See
' *  file "Licenses/License.txt" contained in a project, or the following link.
' *  http://sourceforge.jp/projects/fishbornas/scm/svn/blobs/head/trunk/Licenses/License.txt)
' *
' * 2012.06.07 Initial Revision (tiritomato)
' *

Module MainModule

    Dim ReceiveOutputList As New System.Text.StringBuilder

    Public Sub ConsoleOutListner(ByVal o As Object, ByVal args As DataReceivedEventArgs)
        If Not String.IsNullOrWhiteSpace(args.Data) Then ReceiveOutputList.AppendLine(args.Data & ChrW(0))
        Console.Out.WriteLine(args.Data)
    End Sub

    <STAThread()> _
    Function Main(ByVal args() As String) As Integer

        Dim ex_log As Exception = Nothing
        Main = AppBase.RESULT.INVALID_BOOT_OPTION

        Try
            Dim SplitArgs As New Logic.CommandlineParser.Arguments.Parameter.Collection(AppBase.PipeStarter.ModeArgumentParameterSet, args)
            Dim Mode As AppBase.PipeStarter.Mode, ExistMax As Integer = 0
            For Each m As AppBase.PipeStarter.Mode In [Enum].GetValues(GetType(AppBase.PipeStarter.Mode))
                Dim n As Integer = SplitArgs(AppBase.PipeStarter.ModeArgumentParams(m).Code).Exists
                If ExistMax < n Then
                    ExistMax = n
                    Mode = m
                End If
            Next
            If ExistMax <= 0 Then Return AppBase.RESULT.INVALID_BOOT_OPTION

            Select Case Mode
                Case AppBase.PipeStarter.Mode.ExecCommandList, AppBase.PipeStarter.Mode.ScanCommandList
                    Return CmdListMode(Mode)
                Case AppBase.PipeStarter.Mode.SizedBinary, AppBase.PipeStarter.Mode.UnicodeTextList
                    Return PipeMode(Mode)
                Case Else
                    Return AppBase.RESULT.INVALID_BOOT_OPTION
            End Select

        Catch ex As Exception
            ex_log = ex
        End Try

        If ex_log IsNot Nothing Then

            Dim ExePath As String = Reflection.Assembly.GetEntryAssembly().Location
            Dim FileName As String = "Exception_" & IO.Path.GetFileNameWithoutExtension(ExePath) & Now.ToString("_yyyyMMdd_HHmmss") & ".txt"
            Dim LogFilePath As String = IO.Path.Combine(IO.Path.GetDirectoryName(ExePath), FileName)
            Dim LogMessage As String = String.Format("Exception happened. Check error log.{0}{1}", vbCrLf, LogFilePath)
            Dim LogException As String = Nothing

            Try
                LogException = Logic.String.FromException(ex_log)
                Using LogWriter As New System.IO.StreamWriter(LogFilePath, False)
                    LogWriter.Write(Logic.String.FromException(ex_log))
                End Using
            Catch ex As Exception
                LogMessage = "Log Create Error."
                If String.IsNullOrWhiteSpace(LogException) = False Then LogMessage &= vbCrLf & LogException
            End Try

            Console.WriteLine("Exception Happened.")
            Console.Write(LogMessage)
            Console.ReadLine()

        End If


    End Function

    Public Function PipeMode(ByVal Mode As AppBase.PipeStarter.Mode) As Integer

        Dim MMF As IO.MemoryMappedFiles.MemoryMappedFile = Nothing
        Dim ctEmpty As Integer = 0
        Dim CompleteFlag As System.Threading.Mutex = Nothing
        Dim CatchFlagRef As Threading.Mutex = Nothing

        Try
            Dim Buf() As Byte

            CompleteFlag = Logic.Threading.CreateOrWaitMutex(AppBase.PipeStarter.SharingMemoryMappedFile.ReadCompleteFlagName)

            Try
                MMF = IO.MemoryMappedFiles.MemoryMappedFile.OpenExisting(AppBase.PipeStarter.SharingMemoryMappedFile.MapName)

                ' Read Memory And Echo ConsoleOut
                Using Stream As IO.MemoryMappedFiles.MemoryMappedViewStream = MMF.CreateViewStream()

                    Select Case Mode
                        Case AppBase.PipeStarter.Mode.SizedBinary

                            Dim LenByte(3) As Byte
                            Stream.Read(LenByte, 0, LenByte.Length)

                            ReDim Buf(BitConverter.ToInt32(LenByte, 0) - 1) ' indexer must be integer
                            Stream.Read(Buf, 0, Buf.Length)

                            Using OutStream As IO.Stream = Console.OpenStandardOutput
                                Using Writer As New IO.BinaryWriter(OutStream)
                                    Writer.Write(Buf)
                                End Using
                            End Using

                        Case AppBase.PipeStarter.Mode.UnicodeTextList

                            Using Reader As New IO.StreamReader(Stream, System.Text.Encoding.Unicode)
                                Do
                                    Dim Line As String = Reader.ReadLine
                                    If Line Is Nothing Then Exit Do
                                    Line = Line.Split(New Char() {ChrW(0)})(0)
                                    If Not String.IsNullOrWhiteSpace(Line) Then Console.Out.WriteLine(Line)
                                Loop
                            End Using

                    End Select

                End Using

            Catch ex As Exception
            Finally
                If MMF IsNot Nothing Then MMF.Dispose()
            End Try

            CatchFlagRef = Logic.Threading.PallingWaitMutexExist(AppBase.PipeStarter.SharingMemoryMappedFile.ReadCompleteCatchFlagName, 10)
            If CatchFlagRef IsNot Nothing Then
                If CompleteFlag IsNot Nothing Then
                    CompleteFlag.ReleaseMutex()
                    CompleteFlag.Dispose()
                    CompleteFlag = Nothing
                End If
                CatchFlagRef.WaitOne()
                CatchFlagRef.ReleaseMutex()
                CatchFlagRef.Dispose()
                CatchFlagRef = Nothing
            End If

        Catch
        Finally
            If CompleteFlag IsNot Nothing Then CompleteFlag.Dispose()
            If CatchFlagRef IsNot Nothing Then CatchFlagRef.Dispose()
        End Try

        Return AppBase.RESULT.OK

    End Function

    Public Function CmdListMode(ByVal Mode As AppBase.PipeStarter.Mode) As Integer

        CmdListMode = AppBase.RESULT.OK

        Dim CompleteFlag As System.Threading.Mutex = Nothing
        Dim CatchFlagRef As Threading.Mutex = Nothing
        Dim MMF As IO.MemoryMappedFiles.MemoryMappedFile = Nothing
        Dim ReceiveCommandList As New Collections.Generic.List(Of String)

        Try
            MMF = IO.MemoryMappedFiles.MemoryMappedFile.OpenExisting(AppBase.PipeStarter.SharingMemoryMappedFile.CommandListMapName)
            Using Stream As IO.MemoryMappedFiles.MemoryMappedViewStream = MMF.CreateViewStream()
                Using Reader As New IO.StreamReader(Stream, System.Text.Encoding.Unicode)
                    Do
                        Dim Line As String = Reader.ReadLine
                        If Line Is Nothing Then Exit Do
                        Line = Line.Split(New Char() {ChrW(0)})(0)
                        If Not String.IsNullOrWhiteSpace(Line) Then ReceiveCommandList.Add(Line)
                    Loop
                End Using
            End Using
        Catch
            Throw
        Finally
            If MMF IsNot Nothing Then MMF.Dispose()
        End Try

        Try
            Dim CmdInf As New CommandInfo
            Dim Ret As Integer = 0
            Dim LastExitCode As Integer = 0
            For Each CmdLine As String In ReceiveCommandList

                Dim ParseCmd As CommandInfo.ParseResult = CmdInf.Parse(CmdLine)
                Dim p As New Process
                p.StartInfo.FileName = ParseCmd.Result.Process
                p.StartInfo.Arguments = ParseCmd.Result.Arguments
                p.StartInfo.UseShellExecute = False
                p.StartInfo.RedirectStandardOutput = True
                AddHandler p.OutputDataReceived, AddressOf ConsoleOutListner
                p.Start()
                p.BeginOutputReadLine()
                p.WaitForExit()

                If Mode = AppBase.PipeStarter.Mode.ScanCommandList Then
                    LastExitCode = p.ExitCode
                    CmdListMode = CmdListMode Or p.ExitCode
                End If

                p.Dispose()

                If Mode = AppBase.PipeStarter.Mode.ScanCommandList And LastExitCode = 0 Then
                    CmdListMode = 0
                    Exit For
                End If

            Next

        Catch ex As Exception
            If CmdListMode = AppBase.RESULT.OK Then CmdListMode = AppBase.RESULT.ARCHIVE_SCAN_PROCESS_ERR
        End Try

        Try
            Dim WriteBlock As String = ReceiveOutputList.ToString
            If String.IsNullOrWhiteSpace(WriteBlock) Then WriteBlock = New String(ChrW(0), 1)
            MMF = IO.MemoryMappedFiles.MemoryMappedFile.CreateNew(AppBase.PipeStarter.SharingMemoryMappedFile.CommandListConsoleBufferMapName, System.Text.Encoding.Unicode.GetBytes(WriteBlock).LongLength)
            Using Stream As IO.MemoryMappedFiles.MemoryMappedViewStream = MMF.CreateViewStream()
                Using Writer As New IO.StreamWriter(Stream, System.Text.Encoding.Unicode)
                    Writer.Write(WriteBlock)
                End Using
            End Using

            CompleteFlag = Logic.Threading.CreateOrWaitMutex(AppBase.PipeStarter.SharingMemoryMappedFile.CommandListConsoleBufferWriteCompleteFlagName)
            CatchFlagRef = Logic.Threading.PallingWaitMutexExist(AppBase.PipeStarter.SharingMemoryMappedFile.CommandListConsoleBufferWriteCompleteCatchFlagName, 10)
            If CatchFlagRef IsNot Nothing Then
                If CompleteFlag IsNot Nothing Then
                    CompleteFlag.ReleaseMutex()
                    CompleteFlag.Dispose()
                    CompleteFlag = Nothing
                End If
                CatchFlagRef.WaitOne()
                CatchFlagRef.ReleaseMutex()
                CatchFlagRef.Dispose()
                CatchFlagRef = Nothing
            End If
        Catch
            Throw
        Finally
            If CompleteFlag IsNot Nothing Then CompleteFlag.Dispose()
            If CatchFlagRef IsNot Nothing Then CatchFlagRef.Dispose()
            If MMF IsNot Nothing Then MMF.Dispose()
        End Try

    End Function

End Module
