Imports System.IO
Imports System.Threading
Imports MS.Internal
Imports Effector.Plugin.StoneCut.ThreadData
Imports System.Windows.Threading

Public Class ExecProcessManager

   Public Event m_AllArgsProcessed()

   Public Enum ExecutionThreadStatuses As Integer
      RUNNING = 1
      STOPPED = 2
   End Enum

   Private Enum ProcessManagerStates
      NULL = 0
      OPEN = 1
      CLOSE = 2
   End Enum

   Private m_ProcessManagerTimer As New DispatcherTimer
   Private m_ProcessManagerState As ProcessManagerStates
   Private m_ProcessManagerV As ProcessManagerV
   Public ReadOnly Property ProcessManagerV As ProcessManagerV
      Get
         Return m_ProcessManagerV
      End Get
   End Property

   ' riferimento al thread principale
   Private m_ExecutionThread As Thread
   Private m_ExecutionThreadStatus As ExecutionThreadStatuses = ExecutionThreadStatuses.STOPPED
   Public ReadOnly Property ExecutionThreadStatus As ExecutionThreadStatuses
      Get
         Return m_ExecutionThreadStatus
      End Get
   End Property
   ' array dei thread
   Private m_ThreadList As Thread()
   ' array dei dati dei thread
   Private m_ThreadDataList As ThreadData()
   Friend ReadOnly Property ThreadDataList As ThreadData()
      Get
         Return m_ThreadDataList
      End Get
   End Property
   ' variabile che ferma i processi
   Private m_bStopProcess As Boolean = False
   ' variabile che conferma chiusura dei processi
   Private m_bExecutionThreadStoped As Boolean = False
   ' numero massimo di istanze del cam
   Private m_MaxCamInstances As Integer = 1
   ' nome dell'eseguibile da lanciare
   Private m_sProcessFileName As String = ""
   ' stringa di argomenti dell'eseguibile da lanciare
   Private m_sProcessArguments As String = ""
   ' coda delle cose da eseguire
   Private ArgumentsQueueLock As New Object
   Private m_ArgumentsQueue As New Queue(Of ProcessArgs)
   Public ReadOnly Property ArgumentsQueue As Queue(Of ProcessArgs)
      Get
         Return m_ArgumentsQueue
      End Get
   End Property
   ' coda dei risultati
   Private ArgumentsResultQueueLock As New Object
   Private m_ArgumentsResultQueue As New Queue(Of ProcessArgsResult)
   Public ReadOnly Property ArgumentsResultQueue As Queue(Of ProcessArgsResult)
      Get
         Return m_ArgumentsResultQueue
      End Get
   End Property

   ' funzione che richiede prossimo elemento da processare
   Private m_delGetNextProcessArgs As Func(Of ProcessArgs)
   Public Sub SetGetNextProcessArgs(GetNextProcessArgs As Func(Of ProcessArgs))
      m_delGetNextProcessArgs = GetNextProcessArgs
   End Sub
   ' funzione di pre processing dell'elemento
   Private m_delPreProcess As Func(Of ProcessArgs, ProcessArgs)
   Public Sub SetPreProcess(PreProcess As Func(Of ProcessArgs, ProcessArgs))
      m_delPreProcess = PreProcess
   End Sub
   ' funzione di post processing dell'elemento
   Private m_delPostProcess As Action(Of ProcessArgsResult)
   Public Sub SetPostProcess(PostProcess As Action(Of ProcessArgsResult))
      m_delPostProcess = PostProcess
   End Sub

   Sub New(sProcessFileName As String, sProcessArguments As String)
      m_sProcessFileName = sProcessFileName
      m_sProcessArguments = sProcessArguments
      m_ProcessManagerTimer.Interval = New TimeSpan(0, 0, 1)
      AddHandler m_ProcessManagerTimer.Tick, AddressOf ProcessManagerTimer_Tick
      m_ProcessManagerTimer.Start()
   End Sub

   Private Sub ProcessManagerTimer_Tick(sender As Object, e As EventArgs)
      Select Case m_ProcessManagerState
         Case ProcessManagerStates.OPEN
            ' creo finestra statistiche processi
            m_ProcessManagerV = New ProcessManagerV(Application.Current.MainWindow, New ProcessManagerVM(Me))
            ProcessManagerV.Show()
            m_ProcessManagerState = ProcessManagerStates.NULL
         Case ProcessManagerStates.CLOSE
            ' chiudo finestra statistiche processi
            If Not IsNothing(m_ProcessManagerV) Then
               ProcessManagerV.Close()
               m_ProcessManagerV = Nothing
            End If
            m_ProcessManagerState = ProcessManagerStates.NULL
      End Select
   End Sub

   Public Function ArgumentsEnqueue(ProcessArgs As ProcessArgs) As Boolean
      If ProcessArgs.nId <= 0 OrElse String.IsNullOrWhiteSpace(ProcessArgs.sArgs) Then Return False
      SyncLock ArgumentsQueueLock
         m_ArgumentsQueue.Enqueue(ProcessArgs)
      End SyncLock
      Return True
   End Function

   Public Function ArgumentsDequeue() As ProcessArgs
      Dim DequeueProcessArgs As ProcessArgs = Nothing
      SyncLock ArgumentsQueueLock
         If m_ArgumentsQueue.Count > 0 Then
            DequeueProcessArgs = m_ArgumentsQueue.Dequeue()
         End If
      End SyncLock
      Return DequeueProcessArgs
   End Function

   Public Function ArgumentsQueueCount() As Integer
      Dim nCount As Integer = 0
      SyncLock ArgumentsQueueLock
         nCount = m_ArgumentsQueue.Count
      End SyncLock
      Return nCount
   End Function

   Public Function ArgumentsResultEnqueue(ProcessArgsResult As ProcessArgsResult) As Boolean
      SyncLock ArgumentsResultQueueLock
         m_ArgumentsResultQueue.Enqueue(ProcessArgsResult)
      End SyncLock
      Return True
   End Function

   Public Function ArgumentsResultDequeue() As ProcessArgsResult
      Dim DequeueProcessArgsResult As ProcessArgsResult = Nothing
      SyncLock ArgumentsResultQueueLock
         If m_ArgumentsResultQueue.Count > 0 Then
            DequeueProcessArgsResult = m_ArgumentsResultQueue.Dequeue()
         End If
      End SyncLock
      Return DequeueProcessArgsResult
   End Function

   Public Function ArgumentsResultQueueCount() As Integer
      Dim nCount As Integer = 0
      SyncLock ArgumentsResultQueueLock
         nCount = m_ArgumentsResultQueue.Count
      End SyncLock
      Return nCount
   End Function

   Public Sub SetMaxCamInstances(nValue As Integer)
      ' Numero di core logici da utilizzare (minimo tra presenti sul PC e imposti da INI)
      Dim nMaxThread As Integer = Math.Min(Environment.ProcessorCount, nValue)
      m_MaxCamInstances = nMaxThread
   End Sub

   ' funzione che avvia thread principale
   Public Sub StartExecutionThread()
      If m_ExecutionThreadStatus = ExecutionThreadStatuses.RUNNING Then Return
      m_bStopProcess = False
      m_bExecutionThreadStoped = False
      m_ExecutionThread = New Thread(Sub()
                                        ExecutionProcess()
                                     End Sub)

      m_ExecutionThread.SetApartmentState(ApartmentState.STA)
      ' avvio thread di gestione della macchina che avvia la connessione
      m_ExecutionThread.Start()

      m_ExecutionThreadStatus = ExecutionThreadStatuses.RUNNING
      ' lancio apertura finestra statistiche processi
      m_ProcessManagerState = ProcessManagerStates.OPEN
   End Sub

   Public Sub StopExecutionThread()
      If m_ExecutionThreadStatus = ExecutionThreadStatuses.STOPPED Then Return
      m_bStopProcess = True
      While Not m_bExecutionThreadStoped
         Thread.Sleep(100)
      End While
      If Not IsNothing(m_ExecutionThread) Then
         m_ExecutionThread.Abort()
         While Not m_ExecutionThread.ThreadState = ThreadState.Aborted
            Thread.Sleep(100)
         End While
         m_ExecutionThread = Nothing
      End If
      m_ThreadList = Nothing
      m_ExecutionThreadStatus = ExecutionThreadStatuses.STOPPED
      ' lancio chiusura finestra statistiche processi
      m_ProcessManagerState = ProcessManagerStates.CLOSE
   End Sub

   ' funzione di esecuzione del thread principale che gestice i processi
   Private Sub ExecutionProcess()
      Dim bStopMainProcess As Boolean = False
      Dim nStartingProc As Integer = 0
      While Not bStopMainProcess
         bStopMainProcess = m_bStopProcess
         ' se processo fermato, fermo i thread
         If bStopMainProcess Then
            If Not IsNothing(m_ThreadList) AndAlso m_ThreadList.Count > 0 AndAlso Not IsNothing(m_ThreadList(0)) Then
               ' li fermo
               m_bStopProcess = True
               ' verifico siano terminati
               Dim bOneNotEnded As Boolean = True
               While bOneNotEnded
                  bOneNotEnded = False
                  For Each Thread In m_ThreadList
                     If Not IsNothing(Thread) Then
                        If Thread.IsAlive Then
                           bOneNotEnded = True
                        End If
                     End If
                  Next
               End While
               ' pulisco la lista
               For ThreadIndex = 0 To m_ThreadList.Count - 1
                  m_ThreadList(ThreadIndex) = Nothing
               Next
               m_bStopProcess = False
            End If
            m_bExecutionThreadStoped = True
            Return
         End If
         ' se lista processi nulla o vuota, li faccio partire
         If (IsNothing(m_ThreadList) OrElse m_ThreadList.Count = 0) Then
            m_ThreadList = New Thread(m_MaxCamInstances - 1) {}
            m_ThreadDataList = New ThreadData(m_MaxCamInstances - 1) {}
            For nThreadIndex = 0 To m_MaxCamInstances - 1
               Dim ThreadId As Integer = nThreadIndex
               m_ThreadList(nThreadIndex) = New Thread(Sub()
                                                          ThreadFunction(ThreadId)
                                                       End Sub)
               m_ThreadList(nThreadIndex).SetApartmentState(ApartmentState.STA)
               ' avvio thread di gestione della macchina che avvia la connessione
               m_ThreadList(nThreadIndex).Start()
               Thread.Sleep(100)
            Next
         End If
         ' se qualche processo in stop, lo faccio ripartire
         For ThreadIndex = 0 To m_ThreadList.Count - 1
            If ThreadIndex < m_ThreadList.Count Then
               Dim Thread = m_ThreadList(ThreadIndex)
               If Not IsNothing(Thread) Then
                  If Thread.ThreadState = ThreadState.Stopped OrElse
                     Thread.ThreadState = ThreadState.Aborted OrElse
                     Thread.ThreadState = ThreadState.Suspended OrElse
                     (Not m_ThreadDataList(ThreadIndex).ProcessStatus = ProcessStatuses.TOBESTARTED AndAlso
                     (IsNothing(m_ThreadDataList(ThreadIndex).Process) OrElse
                     (Not IsNothing(m_ThreadDataList(ThreadIndex).Process) AndAlso m_ThreadDataList(ThreadIndex).Process.HasExited))) Then
                     ' inserire un ritardo di rilancio?
                     ' lo chiudo e rilancio
                     'Thread.Sleep(500)
                     Thread.Abort()
                     Thread.Sleep(100)
                     While Not Thread.ThreadState = ThreadState.Aborted
                        Thread.Sleep(100)
                     End While
                     Thread = Nothing
                     Dim ThreadId As Integer = ThreadIndex
                     m_ThreadList(ThreadIndex) = New Thread(Sub()
                                                               ThreadFunction(ThreadId)
                                                            End Sub)
                     m_ThreadList(ThreadIndex).SetApartmentState(ApartmentState.STA)
                     ' avvio thread di gestione della macchina che avvia la connessione
                     m_ThreadList(ThreadIndex).Start()
                  End If
               Else
                  Dim ThreadId As Integer = ThreadIndex
                  If ThreadIndex < m_ThreadList.Count Then
                     m_ThreadList(ThreadIndex) = New Thread(Sub()
                                                               ThreadFunction(ThreadId)
                                                            End Sub)
                     m_ThreadList(ThreadIndex).SetApartmentState(ApartmentState.STA)
                     ' avvio thread di gestione della macchina che avvia la connessione
                     m_ThreadList(ThreadIndex).Start()
                  End If
               End If
            End If
         Next
         ' verifico se coda vuota e tutti i processi hanno finito
         Dim nQueueArgs As Integer = 0
         SyncLock ArgumentsQueueLock
            nQueueArgs = m_ArgumentsQueue.Count
         End SyncLock
         If nQueueArgs = 0 Then
            Dim bProcessWaiting As Boolean = False
            For Each ThreadData In m_ThreadDataList
               If ThreadData.ProcessStatus = ProcessStatuses.WAITINGANSWER OrElse ThreadData.ProcessStatus = ProcessStatuses.ANSWERRECEIVED Then
                  bProcessWaiting = True
                  Exit For
               End If
            Next
            If Not bProcessWaiting Then
               ' creo thread per lanciare evento asincrono di fine calcolo
               Dim AllArgsProcessedThread = New Thread(Sub()
                                                          RaiseEvent m_AllArgsProcessed()
                                                       End Sub)
               AllArgsProcessedThread.SetApartmentState(ApartmentState.STA)
               AllArgsProcessedThread.Start()
            End If
         End If
         Thread.Sleep(1000)
      End While
   End Sub

   ' funzione di esecuzione del singolo processo che comunica con il programma
   Private Sub ThreadFunction(ThreadIndex As Integer)
      Dim MyThreadData As New ThreadData
      m_ThreadDataList(ThreadIndex) = MyThreadData
      'Dim CurrThreadStat As New ThreadStat(ThreadIndex, DateTime.Now)
      'HistoryThreadDataList.Add(CurrThreadStat)
      'MyThreadData.SetThreadStat(CurrThreadStat)
      'Dim sDrive As String = "c" ' If(ThreadIndex Mod 2 = 0, "A", "B")
      'Dim sCurrDdfDir As String = sDrive & ":\EgtData\WebDoor\Ddf"
      'Dim stopWatch As New Stopwatch()
      'Dim lExeTime As Long = 0
      'Dim lOtherTime As Long = 0

      ' avvio processo
      Dim Proc As Process = New Process()
      Proc.StartInfo.FileName = m_sProcessFileName
      Proc.StartInfo.RedirectStandardInput = True
      Proc.StartInfo.RedirectStandardOutput = True
      Proc.StartInfo.Arguments = ThreadIndex.ToString() & " " & m_sProcessArguments
      Proc.StartInfo.UseShellExecute = False
      Proc.StartInfo.CreateNoWindow = True
      AddHandler Proc.OutputDataReceived, AddressOf Thread_OutputDataReceived

      If Proc.Start() Then
         'Dim CurrPocStat As New ProcStat(DateTime.Now)
         'CurrThreadStat.ProcExecutionList.Add(CurrPocStat)
         Proc.BeginOutputReadLine()
         MyThreadData.SetProcess(Proc)
         MyThreadData.SetProcessStatus(ProcessStatuses.NULL)

         'Dim nProc0Wait As Integer = 0
         ' ciclo per leggere coda ed eseguire
         While Not m_bStopProcess AndAlso Not Proc.HasExited
            Select Case MyThreadData.ProcessStatus
               Case ThreadData.ProcessStatuses.NULL
                  'MyThreadData.SetThreadOperation(ThreadOperations.WaitingData)
                  ' se c'e' qualcosa da processare
                  'Dim nNumTaskToProcess As Integer = 0
                  'If ThreadIndex = 0 Then
                  '   nNumTaskToProcess = currWDC.numTask2proc
                  '   If nNumTaskToProcess > 0 Then
                  '      If Not m_bCheckOrder Then m_bCheckOrder = True
                  '   Else
                  '      If m_bCheckOrder Then m_bCheckOrder = False
                  '      Thread.Sleep(100)
                  '   End If
                  'ElseIf m_bCheckOrder Then
                  '   nNumTaskToProcess = currWDC.numTask2proc
                  '   If nNumTaskToProcess = 0 Then
                  '      m_bCheckOrder = False
                  '   End If
                  'End If
                  Dim NextProcessArgs As ProcessArgs = Nothing
                  If Not IsNothing(m_delGetNextProcessArgs) Then
                     NextProcessArgs = m_delGetNextProcessArgs()
                  Else
                     NextProcessArgs = ArgumentsDequeue()
                  End If

                  If Not IsNothing(NextProcessArgs) AndAlso NextProcessArgs.nId > 0 AndAlso Not String.IsNullOrWhiteSpace(NextProcessArgs.sArgs) Then
                     If Not IsNothing(m_delPreProcess) Then
                        NextProcessArgs = m_delPreProcess(NextProcessArgs)
                     End If
                     MyThreadData.SetCurrRequest(NextProcessArgs)
                     Proc.StandardInput.WriteLine(ThreadIndex & "," & NextProcessArgs.sArgs)
                     MyThreadData.SetProcessStatus(ThreadData.ProcessStatuses.WAITINGANSWER)
                  End If
                  'If m_bCheckOrder Then
                  '   Dim LastRequest As Dictionary(Of String, CalcReqtDTO) = currWDC.queueList(1)
                  '   If LastRequest.Count > 0 Then
                  '      MyThreadData.SetThreadOperation(ThreadOperations.FoundRequest)

                  '      Dim ConvItem As KeyValuePair(Of String, String)
                  '      ConvItem = New KeyValuePair(Of String, String)(LastRequest.First().Key, LastRequest.First().Value.DDF)
                  '      MyThreadData.SetCurrRequest(ConvItem)

                  '      ' vecchia versione
                  '      'MyThreadData.SetCurrRequest(LastRequest.First())

                  '      Dim Item As KeyValuePair(Of String, String) = MyThreadData.CurrRequest
                  '      Dim bOk As Boolean = Not IsNothing(Item)
                  '      If bOk Then

                  '         ' avvio cronometro
                  '         'stopWatch.Reset()
                  '         stopWatch.Restart()
                  '         ' svuoto vecchio set file della porta richiesta
                  '         Dim fileList As String() = Directory.GetFiles(sCurrDdfDir, Item.Key + ".*")
                  '         ' elimino vecchi
                  '         If Not IsNothing(fileList) Then
                  '            For Each sFile In fileList
                  '               Try
                  '                  File.Delete(sFile)
                  '               Catch ex As Exception
                  '               End Try
                  '            Next
                  '         End If

                  '         ' scrivo ddf
                  '         MyThreadData.SetThreadOperation(ThreadOperations.WritingDdf)
                  '         MyThreadData.SetDdfPath(sCurrDdfDir & "\" & Item.Key & ".ddf")
                  '         Dim sDdfPath As String = MyThreadData.sDdfPath
                  '         Try
                  '            File.WriteAllText(sDdfPath, Item.Value)
                  '         Catch ex As Exception
                  '            bOk = False
                  '         End Try

                  '         If bOk Then
                  '            MyThreadData.SetThreadOperation(ThreadOperations.ProcessingDdf)

                  '            Proc.StandardInput.WriteLine(ThreadIndex & "," & sDdfPath)

                  '            MyThreadData.SetWaitProcAnswer(ThreadData.ProcComm.WaitingAnswer)
                  '         End If
                  '      End If
                  '   Else
                  '      Thread.Sleep(100)
                  '   End If
                  'Else
                  '   Thread.Sleep(100)
                  'End If
               Case ThreadData.ProcessStatuses.WAITINGANSWER
                  Thread.Sleep(10)
               Case ThreadData.ProcessStatuses.ANSWERRECEIVED
                  Dim NewProcessArgsResult As New ProcessArgsResult(MyThreadData.CurrRequest, MyThreadData.nProcResult)
                  If Not IsNothing(m_delPostProcess) Then
                     m_delPostProcess(NewProcessArgsResult)
                  End If
                  ArgumentsResultEnqueue(NewProcessArgsResult)
                  'Dim Item As ProcessArgs = MyThreadData.CurrRequest
                  'Dim sDdfPath As String = MyThreadData.sDdfPath
                  'Dim bOk As Boolean = True
                  '' salvo exe time...
                  'stopWatch.Stop()
                  'lExeTime = stopWatch.ElapsedMilliseconds
                  'stopWatch.Restart()
                  'Dim procResults As New List(Of CalcResultDTO)
                  'Dim currRes As New CalcResultDTO
                  'Dim fContent As String = ""
                  'MyThreadData.SetThreadOperation(ThreadOperations.ReadingSvg)
                  '' verifico esistenza file svg e lo carico
                  'bOk = GetFileContent(Path.ChangeExtension(sDdfPath, "svg"), fContent)
                  '' !!! ToDo: inserire TIPO di richiesta secondo quanto ricevuto....
                  '' invio risposta
                  'currRes.Validated = MyThreadData.nProcResult = 0 AndAlso bOk
                  'currRes.DoorIdVers = Item.Key
                  '' per ora cablato a svg, prendere da MimeType richiesta...
                  'currRes.MimeType = "svg"

                  '' se NON fosse validato --> messo il messaggio...
                  'If (currRes.Validated) Then
                  '   currRes.RawContent = fContent
                  'Else
                  '   bOk = GetFileContent(Path.ChangeExtension(sDdfPath, "txt"), fContent)
                  '   currRes.ErrorMsg = fContent
                  'End If
                  'MyThreadData.SetThreadOperation(ThreadOperations.SendResult)

                  'procResults.Add(currRes)
                  'Dim respPut As String = currWDC.SendProcResults(procResults)

                  'stopWatch.Stop()
                  'lOtherTime = stopWatch.ElapsedMilliseconds
                  'CurrPocStat.IncrementDoneRequest()
                  '' aggiorno thread display...
                  'UpdateThreadList(Item.Key, lExeTime, lOtherTime)
                  '' cambio nomi file generati in old
                  'Dim OldSvg As String = Path.ChangeExtension(sDdfPath, "svg")
                  'Dim NewSvg As String = Path.GetDirectoryName(sDdfPath) & "\" & Path.GetFileNameWithoutExtension(sDdfPath) & "_old.svg"
                  'Try
                  '   File.Delete(NewSvg)
                  'Catch ex As Exception
                  'End Try
                  'Try
                  '   File.Delete(Path.ChangeExtension(NewSvg, "txt"))
                  'Catch ex As Exception
                  'End Try
                  'Try
                  '   File.Delete(Path.ChangeExtension(NewSvg, "log"))
                  'Catch ex As Exception
                  'End Try
                  'Try
                  '   File.Delete(Path.ChangeExtension(NewSvg, "nge"))
                  'Catch ex As Exception
                  'End Try
                  'Try
                  '   File.Delete(Path.ChangeExtension(NewSvg, "ddf"))
                  'Catch ex As Exception
                  'End Try
                  'Try
                  '   File.Move(OldSvg, NewSvg)
                  'Catch ex As Exception
                  'End Try
                  'Try
                  '   File.Move(Path.ChangeExtension(OldSvg, "txt"), Path.ChangeExtension(NewSvg, "txt"))
                  'Catch ex As Exception
                  'End Try
                  'Try
                  '   File.Move(Path.ChangeExtension(OldSvg, "log"), Path.ChangeExtension(NewSvg, "log"))
                  'Catch ex As Exception
                  'End Try
                  'Try
                  '   File.Move(Path.ChangeExtension(OldSvg, "nge"), Path.ChangeExtension(NewSvg, "nge"))
                  'Catch ex As Exception
                  'End Try
                  'Try
                  '   File.Move(Path.ChangeExtension(OldSvg, "ddf"), Path.ChangeExtension(NewSvg, "ddf"))
                  'Catch ex As Exception
                  'End Try
                  MyThreadData.SetProcessStatus(ThreadData.ProcessStatuses.NULL)
            End Select

         End While
         '   CurrPocStat.SetStopProc(DateTime.Now)
         If m_bStopProcess Then
            Proc.StandardInput.WriteLine("quit")
         End If
      End If

      ' CurrThreadStat.SetStopThread(DateTime.Now)
      MyThreadData.SetProcess(Nothing)
      ' MyThreadData.SetThreadOperation(ThreadOperations.Closed)

   End Sub

   Private Sub Thread_OutputDataReceived(sender As Object, e As DataReceivedEventArgs)
      Dim sResult As String = e.Data
      If Not String.IsNullOrWhiteSpace(sResult) AndAlso sResult.StartsWith("#42315#,") Then
         Dim Results() As String = sResult.Split(","c)
         If Results.Count >= 2 Then
            Dim nIndex As Integer = -1
            Dim nResult As Integer = -1
            Dim dResult As Integer = -1
            If Integer.TryParse(Results(1), nIndex) AndAlso nIndex >= 0 Then
               If Integer.TryParse(Results(2), nResult) AndAlso nResult >= 0 Then
                  m_ThreadDataList(nIndex).SetProcResult(nResult)
               ElseIf StringToDouble(Results(2), dResult) AndAlso dResult >= 0 Then
                  nResult = Math.Floor(dResult)
                  m_ThreadDataList(nIndex).SetProcResult(nResult)
               End If
               m_ThreadDataList(nIndex).SetProcessStatus(ThreadData.ProcessStatuses.ANSWERRECEIVED)
            End If
         End If
      End If
   End Sub

End Class

Public Class ThreadData

   'Enum ThreadOperations As Integer
   '   WaitingData = 1
   '   FoundRequest = 2
   '   WritingDdf = 3
   '   ProcessingDdf = 4
   '   ReadingSvg = 5
   '   SendResult = 6
   '   Closed = 10
   'End Enum

   Public Enum ProcessStatuses As Integer
      NULL = 0
      WAITINGANSWER = 1
      ANSWERRECEIVED = 2
      TOBESTARTED = 10
   End Enum

   Private m_ProcessStatus As ProcessStatuses = ProcessStatuses.TOBESTARTED
   Public ReadOnly Property ProcessStatus As ProcessStatuses
      Get
         Return m_ProcessStatus
      End Get
   End Property
   Friend Sub SetProcessStatus(value As ProcessStatuses)
      m_ProcessStatus = value
   End Sub

   Private m_CurrRequest As ProcessArgs
   Public ReadOnly Property CurrRequest As ProcessArgs
      Get
         Return m_CurrRequest
      End Get
   End Property
   Friend Sub SetCurrRequest(value As ProcessArgs)
      m_CurrRequest = value
   End Sub

   'Private m_sDdfPath As String
   'Public ReadOnly Property sDdfPath As String
   '   Get
   '      Return m_sDdfPath
   '   End Get
   'End Property
   'Friend Sub SetDdfPath(value As String)
   '   m_sDdfPath = value
   'End Sub

   Private m_nProcResult As Integer
   Public ReadOnly Property nProcResult As Integer
      Get
         Return m_nProcResult
      End Get
   End Property
   Friend Sub SetProcResult(value As Integer)
      m_nProcResult = value
   End Sub

   'Private m_ThreadOperation As ThreadOperations
   'Public ReadOnly Property ThreadOperation As ThreadOperations
   '   Get
   '      Return m_ThreadOperation
   '   End Get
   'End Property
   'Friend Sub SetThreadOperation(value As ThreadOperations)
   '   m_ThreadOperation = value
   'End Sub

   Private m_Process As Process
   Public ReadOnly Property Process As Process
      Get
         Return m_Process
      End Get
   End Property
   Friend Sub SetProcess(value As Process)
      m_Process = value
   End Sub

   'Private m_ThreadStat As ThreadStat
   'Public ReadOnly Property ThreadStat As ThreadStat
   '   Get
   '      Return m_ThreadStat
   '   End Get
   'End Property
   'Friend Sub SetThreadStat(value As ThreadStat)
   '   m_ThreadStat = value
   'End Sub

End Class

Public Class ProcessArgs

   Private m_nId As Integer
   Public ReadOnly Property nId As Integer
      Get
         Return m_nId
      End Get
   End Property

   Private m_sArgs As String
   Public ReadOnly Property sArgs As String
      Get
         Return m_sArgs
      End Get
   End Property

   Sub New(nId As Integer, sArgs As String)
      m_nId = nId
      m_sArgs = sArgs
   End Sub

End Class

Public Class ProcessArgsResult

   Private m_ProcessArgs As ProcessArgs
   Public ReadOnly Property ProcessArgs As ProcessArgs
      Get
         Return m_ProcessArgs
      End Get
   End Property

   Private m_nResult As Integer
   Public ReadOnly Property nResult As Integer
      Get
         Return m_nResult
      End Get
   End Property
   Public Sub SetResult(nResult As Integer)
      m_nResult = nResult
   End Sub

   Sub New(ProcessArgs As ProcessArgs, nResult As Integer)
      m_ProcessArgs = ProcessArgs
      m_nResult = nResult
   End Sub

End Class