'----------------------------------------------------------------------------
'  EgalTech 2015-2015
'----------------------------------------------------------------------------
' File : Camera.vb       Data : 08.10.15          Versione : 1.6j1
' Contenuto : Classe Camera (gestione della macchina fotografica).
'
'
'
' Modifiche : 08.10.15 DS Creazione modulo.
'
'
'----------------------------------------------------------------------------

Imports System.Threading
Imports System.IO
Imports EgtUILib
Imports System.Reflection

Public Class Camera

   ' Riferimento alla MainWindow
   Private m_MainWindow As MainWindow = DirectCast(Application.Current.MainWindow, MainWindow)

   ' Dati
   Private m_bCameraLink As Boolean = False
   Private m_bCalcContour As Boolean = False
   Private m_nCameraCount As Integer = 0
   Private m_sCameraPath As String = String.Empty
   Private m_sCameraProcName As String = String.Empty
   Private m_sImage As String = String.Empty
   Private m_sInfo As String = String.Empty
   Private m_sResult As String = String.Empty
   Private m_sContour As String = String.Empty
   Private m_nThreshold As Integer = 60
   Private m_dTolerance As Double = 5
   Private m_nTimeout As Integer = 30
   Private m_sImageDir As String = String.Empty

   Private Const N_LOOP As Integer = 20

   ' Lista dei processi Cmg associati ad ogni tavola
   Public m_ProcessCmgList As New List(Of Process)
   ' restituisce lo stato che il processo associato alla tavola corrente (PrepareCamera)
   Private m_bIsRunnigProc As Boolean = False
   ' restituisce l'esito dello scatto di una foto 
   Private m_bClickOk As Boolean = False
   Private m_dClickOk As Double = 10
   ' restituisce l'esito dello scatto di una foto 
   Private m_bCorrectedImgOk As Boolean = False
   Private m_dCorrectedImgOk As Double = 10
   ' restituisce l'esito di salvataggio BackImage
   Private m_bSavedBackImage As Boolean = False
   Private m_dSavedBackImage As Double = 90
   '
   Private m_bDowloadedPicFromCamera As Boolean = False
   Private m_dDowloadedPicFromCamera As Double = 10
   '
   Private m_bReadOCV As Boolean = False
   Private m_dReadOCV As Double = 10
   '
   Private m_bStartDistCorrect As Boolean = False
   Private m_dStartDistCorrect As Double = 30
   '
   Private m_bStartProspCorrect As Boolean = False
   Private m_dStartProspCorrect As Double = 20

   Private DeltaCameraTab As Integer = 0

   ' Flag per foto in esecuzione
   Friend m_bBusy As Boolean = False

   Public Function Init() As Boolean
      ' Lettura dati di configurazione da file Ini
      m_bCameraLink = (GetPrivateProfileInt(S_GENERAL, K_CAMERALINK, 0, m_MainWindow.GetIniFile()) <> 0) And
                      Not m_MainWindow.GetKeyOption(MainWindow.KEY_OPT.OFFICE_TYPE)
      GetPrivateProfileString(S_CAMERA, K_CAM_EXEPATH, "", m_sCameraPath, m_MainWindow.GetIniFile())
      GetPrivateProfileString(S_CAMERA, K_CAM_IMAGE, "", m_sImage, m_MainWindow.GetIniFile())
      GetPrivateProfileString(S_CAMERA, K_CAM_INFO, "", m_sInfo, m_MainWindow.GetIniFile())
      GetPrivateProfileString(S_CAMERA, K_CAM_RESULT, "", m_sResult, m_MainWindow.GetIniFile())
      GetPrivateProfileString(S_CAMERA, K_CAM_CONTOUR, "", m_sContour, m_MainWindow.GetIniFile())
      m_nThreshold = GetPrivateProfileInt(S_CAMERA, K_CAM_THRESHOLD, 60, m_MainWindow.GetIniFile())
      m_dTolerance = GetPrivateProfileDouble(S_CAMERA, K_CAM_TOLERANCE, 5, m_MainWindow.GetIniFile())
      m_nTimeout = GetPrivateProfileInt(S_CAMERA, K_CAM_TIMEOUT, 30, m_MainWindow.GetIniFile())
      GetPrivateProfileString(S_GENERAL, K_IMAGEDIR, "", m_sImageDir, m_MainWindow.GetIniFile())
      ' Verifico abilitazione riconoscimento contorno automatico del grezzo
      m_bCalcContour = m_MainWindow.GetKeyOption(MainWindow.KEY_OPT.AUTO_PHOTO) AndAlso
                      (GetPrivateProfileInt(S_GENERAL, K_CONTOURFROMCAMERA, 1, m_MainWindow.GetIniFile()) <> 0)
      ' Ricavo il nome del processo associato
      m_sCameraProcName = Path.GetFileNameWithoutExtension(m_sCameraPath)
      ' Terminazione di eventuali processi omonimi in esecuzione
      KillPreviousProcesses()
      ' Avvio processi del camera manager per ogni tavola
      CamerasHide()
      Return True
   End Function

   Public Function Close() As Boolean
      If m_bBusy Then Return False
      If m_bCameraLink Then
         KillProcesses()
      End If
      Return True
   End Function

   Public Function GetCalcContour() As Boolean
      Return m_bCalcContour
   End Function

   Public Function GetCameraLink() As Boolean
      Return m_bCameraLink
   End Function

   Friend Property Threshold As Integer
      Get
         Return m_nThreshold
      End Get
      Set(value As Integer)
         ' Porto il valore nel range valido
         If value < 10 Then
            value = 10
         ElseIf value > 90 Then
            value = 90
         End If
         ' Se cambiato, aggiorno file INI
         If value <> m_nThreshold And
            WritePrivateProfileString(S_CAMERA, K_CAM_THRESHOLD, DoubleToString(value, 3), m_MainWindow.GetIniFile()) Then
            ' Aggiorno il valore corrente
            m_nThreshold = value
         End If
      End Set
   End Property

   Friend Property Tolerance As Double
      Get
         Return m_dTolerance
      End Get
      Set(value As Double)
         ' Porto il valore nel range valido
         If value < 100 * EPS_SMALL Then
            value = 100 * EPS_SMALL
         End If
         ' Se cambiato, aggiorno file INI
         If value <> m_dTolerance And
            WritePrivateProfileString(S_CAMERA, K_CAM_TOLERANCE, DoubleToString(value, 3), m_MainWindow.GetIniFile()) Then
            ' Aggiorno il valore corrente
            m_dTolerance = value
         End If
      End Set
   End Property

   ' OK: Restituisce la tavola a cui è associato il processo
   Private Function GetCurrentTableFromCameraProcess(nIndProc As Integer) As Integer
      Dim nIndTab As Integer = 1
      Select Case DeltaCameraTab
         Case 0
            nIndTab = nIndProc
         Case 1
            ' La cameraHq è sempre associata all'ultimo processo e sempre alla prima tavola
            nIndTab = 1
         Case -1
            nIndTab = GetCurrentTable()
      End Select

      Return nIndTab
   End Function

   ' OK: Restituisce il processo a cui è associata la tavola
   Private Function GetProcessFromCurrentTable(nIndTab As Integer) As Integer
      Dim nIndProc As Integer = 1
      Select Case DeltaCameraTab
         Case 0
            ' Indice di processo uguale all'indice della tavola
            nIndProc = nIndTab
         Case 1
            ' Alla tavola 1 possono essere associati 2 processi (solo se camera Hq abilitata e attiva)
            If nIndTab = 1 And
               (GetPrivateProfileInt(S_CAMERAHQ, K_CAMERAHQ_ENABLE, 0, m_MainWindow.GetMachIniFile()) <> 0) AndAlso
               (GetPrivateProfileInt(S_CAMERAHQ, K_CAMERAHQ_ACTIVATE, 0, m_MainWindow.GetMachIniFile()) <> 0) Then
               ' forzo l'utilizzo della seconda Hq (sopra alla tavola 1 di lavoro)
               nIndProc = nIndTab + 1
            Else
               nIndProc = 1
            End If
         Case -1
            nIndProc = 1
      End Select

      Return nIndProc
   End Function

   ' OK: Avvio un processo per ogni tavola presente in macchina
   Public Function CamerasHide() As Boolean
      If Not m_bCameraLink Then Return False

      ' Lancio il programma in cieco, se già attivo lo nascondo
      m_nCameraCount = GetTableCount()

      ' Se esiste una configurazione, ne verifico la sua valità
      If m_MainWindow.m_CurrentMachine.CameraCounter > -1 Then
         DeltaCameraTab = m_MainWindow.m_CurrentMachine.CameraCounter - GetTableCount()
         Select Case DeltaCameraTab
            Case 0
               ' ad ogni tavola associo una camera/configurazione
            Case 1
               ' Gestisco correttamente solo il caso: 1 tavola e 2 camere
               If GetPrivateProfileInt(S_CAMERAHQ, K_CAMERAHQ_ENABLE, 0, m_MainWindow.GetMachIniFile()) = 1 Then
                  m_nCameraCount = m_nCameraCount + 1
               End If
            Case -1
               ' Gestisco correttamente solo il caso: 2 tavole e 1 camera
               m_nCameraCount = m_nCameraCount - 1
            Case Else
               EgtOutLog(" --> CAUTION : Differenza tra numero di camere e numero di tavole: " & DeltaCameraTab.ToString &
                         ", sarà attivata solo la prima camera.")
               DeltaCameraTab = 0
         End Select
      Else
         ' 🚨 CAUTION: 
         EgtOutLog(" --> CAUTION : In file *.ini machine '[Photo]' there is not param 'CameraCounter'.")
         ' Aggiungo un altro processo se camera Hq abilitata (non esite una vera tavola associata)
         If GetPrivateProfileInt(S_CAMERAHQ, K_CAMERAHQ_ENABLE, 0, m_MainWindow.GetMachIniFile()) = 1 Then
            m_nCameraCount = m_nCameraCount + 1
            DeltaCameraTab = 1
         End If
      End If

      Try
         For Index As Integer = 1 To m_nCameraCount
            Dim m_ProcessCmg As New Process()
            m_ProcessCmg.StartInfo.FileName = m_sCameraPath
            m_ProcessCmg.StartInfo.RedirectStandardInput = True
            m_ProcessCmg.StartInfo.RedirectStandardOutput = True
            ' Assegno argomento 0 per avvio in cieco, index per specificare il numero di processo
            m_ProcessCmg.StartInfo.Arguments = "0" & " " & Index.ToString()
            m_ProcessCmg.StartInfo.UseShellExecute = False
            m_ProcessCmg.StartInfo.CreateNoWindow = True
            AddHandler m_ProcessCmg.OutputDataReceived, AddressOf Thread_OutputDataReceived
            If m_ProcessCmg.Start() Then
               m_ProcessCmg.BeginOutputReadLine()
               ' Richiesta lettura configurazione corrente
               m_ProcessCmg.StandardInput.WriteLine("0")
               m_ProcessCmgList.Add(m_ProcessCmg)
            Else
               Return False
            End If
         Next
         Return True
      Catch ex As Exception
         EgtOutLog(ex.Message)
         Return False
      End Try
   End Function

   ' OK: Creo un nuovo processo associato alla tavola indicata
   Public Function ReloadCameraHide(nInd As Integer) As Boolean
      Dim m_ProcessCmg As New Process()
      m_ProcessCmg.StartInfo.FileName = m_sCameraPath
      m_ProcessCmg.StartInfo.RedirectStandardInput = True
      m_ProcessCmg.StartInfo.RedirectStandardOutput = True
      ' Assegno argomento 0 per avvio in cieco, index per specificare il numero di processo
      m_ProcessCmg.StartInfo.Arguments = "0" & " " & nInd.ToString()
      m_ProcessCmg.StartInfo.UseShellExecute = False
      m_ProcessCmg.StartInfo.CreateNoWindow = True
      AddHandler m_ProcessCmg.OutputDataReceived, AddressOf Thread_OutputDataReceived
      If m_ProcessCmg.Start() Then
         m_ProcessCmg.BeginOutputReadLine()
         m_ProcessCmgList(nInd) = m_ProcessCmg
         Return True
      End If
      Return False
   End Function

   ' OK: Ogni processo cameramanager che restituisce un messaggio passa di qua
   Private Sub Thread_OutputDataReceived(sender As Object, e As DataReceivedEventArgs)
      ' Il formato del messaggio è 'esempio messaggio: #IndProc'
      If Not IsNothing(e.Data) Then
         Dim sMsg As String() = e.Data.Split(":"c)
         ' reinserisco eventuali ":" che sono stati rimossi  
         If sMsg.Length > 2 Then
            For Index As Integer = 2 To sMsg.Length - 1
               sMsg(1) &= ":" & sMsg(Index)
            Next
         End If
         If sMsg.Length > 1 Then
            Select Case sMsg(0)
            ' Metodo WaitingForInstruction
            ' Se richiesto comando 7 stampo questo messaggio
               Case "PROCESSO ATTIVO"
                  m_bIsRunnigProc = True
            ' Metodo TakeFoto
               Case "SCATTO FOTO AVVENUTO"
                  m_bClickOk = True
            ' Metodo Camera_DownloadedCompleted
               Case "DOWNLOAD DA CAMERA COMPLETATO"
                  m_bDowloadedPicFromCamera = True
            ' Metodo LeggiFileCalibrazioneLenteOCV
               Case "LETTURA OCV"
                  m_bReadOCV = True
            ' Metodo CorrezioneCompleta
               Case "RICHIESTA CORREZIONE DISTORSIONE"
                  m_bStartDistCorrect = True
               Case "RICHIESTA CORREZIONE PROSPETTICA"
                  m_bStartProspCorrect = True
            ' Metodo CorreggiProspettivaDaMatriceOCV
               Case "FINE CREAZIONE IMMAGINE CON CORREZIONE OCV"
                  m_bCorrectedImgOk = True
            ' Metodo SalvaNuovoBackGround
               Case "BACKIMAGE PRONTA"
                  m_bSavedBackImage = True
            End Select
            If m_MainWindow.GetDebug > 3 Then
               EgtOutLog(" § " & sMsg(0) & " Process_" & sMsg(1))
            End If
         End If
      End If
   End Sub

   ' OK : Accendo fari e vado in Home
   Private Sub PrepareMachine(nInd As Integer)
      ' ------------------------------------ accensione riflettori ------------------------------------
      Dim sPLCVarSpotLightList As New List(Of String)
      For IndexSpot As Integer = 1 To GetTableCount()
         Dim sPLCVarSpotLight As String = String.Empty
         GetPrivateProfileString(S_NCDATA, K_SPOTLIGHT & IndexSpot.ToString(), "", sPLCVarSpotLight, m_MainWindow.GetMachIniFile())
         ' eventualmente rimuovo inizio stringa: "PLC, ___"
         Dim sItemString() As String = Split(sPLCVarSpotLight, ","c)
         If sItemString.Count > 1 Then
            sPLCVarSpotLight = sItemString(1).Trim
         End If
         sPLCVarSpotLightList.Add(sPLCVarSpotLight)
      Next
      Dim nPhotoDeley As Integer = GetPrivateProfileInt(S_NCNUM, K_PHOTODELEY, "100", m_MainWindow.GetMachIniFile())

      Select Case m_MainWindow.m_CNCommunication.m_nNCType
         Case 1, 2
            If m_MainWindow.m_CNCommunication.m_nNCType = 2 Then
               ' solo per Flexium
               m_MainWindow.m_CNCommunication.m_CN.DPlcVariables_WriteVariables(sPLCVarSpotLightList(nInd - 1), "1")
               ' altrimenti scrittura delle variabili E
            Else
               m_MainWindow.m_CNCommunication.m_CN.DVariables_WriteVariables2(sPLCVarSpotLightList(nInd - 1), "1")
            End If
            System.Threading.Thread.Sleep(nPhotoDeley)
         Case 3
            ' SIEMENS
      End Select

      ' ------------------------------------ accensione riflettori ------------------------------------

      ' ------------------------------------ mando la testa in home ------------------------------------
      If Not GoHomeForPhoto() Then
         EgtOutLog("Error in positioning")
      End If
      ' ------------------------------------ mando la testa in home ------------------------------------
   End Sub

   Private Function GoHomeForPhoto() As Boolean
      Dim bGoHome As Boolean = GetPrivateProfileInt(S_PHOTO, K_ENABELE_GOHOME_FOR_PHOTO, 0, m_MainWindow.GetMachIniFile()) <> 0
      ' Se non configurato esco senza generare errore
      If Not bGoHome Then Return True
      ' Costruisco il bottone per potere eseguire il comando MDI
      Dim GoHome As MachineButton = Nothing
      Dim sDirectCmdFile As String = String.Empty
      GetPrivateProfileString(S_PHOTO, K_CAMERA_DIRECT_CMD, "", sDirectCmdFile, m_MainWindow.GetMachIniFile())
      If String.IsNullOrEmpty(sDirectCmdFile) Then
         Return False
      Else
         EgtOutLog("Direct command for positionig head: " & sDirectCmdFile)
      End If
      GoHome = New TwoStateButton("", sDirectCmdFile, "", "", "")
      ' eseguo lo script lua associato
      GoHome.ExecuteMDICommand(GoHome.TLuaScriptName)
      ' Leggo nome variabile posizione home raggiunta
      Dim CameraStateNameVar As String = String.Empty
      GetPrivateProfileString(S_PHOTO, K_CAMERA_STATE_VAR, "", CameraStateNameVar, m_MainWindow.GetMachIniFile())
      Dim nSteps As Integer = 20
      nSteps = GetPrivateProfileInt(S_PHOTO, K_PENDIG_TIME_FOR_PHOTO, nSteps, m_MainWindow.GetMachIniFile())
      If String.IsNullOrEmpty(CameraStateNameVar) Then
         'Return False
      Else
         EgtOutLog("Variable for read status of positioning head: " & CameraStateNameVar)
      End If
      ' 91144=Going home
      m_MainWindow.m_CurrentProjectPageUC.SetInfoMessage(EgtMsg(91144))
      UpdateUI()
      ' Eseguo reset variabile posizione home raggiunta
      m_MainWindow.m_CNCommunication.m_CN.DVariables_WriteVariables2(CameraStateNameVar, "0")
      System.Threading.Thread.Sleep(300)
      ' Definisco flag posizionamento completato
      Dim bPositionOk As Boolean = False
      For I As Integer = 0 To nSteps
         ' Devo rileggere la variabile ad ogni ciclo
         m_MainWindow.m_CNCommunication.m_CN.ReadEls_Add_Parameter(CameraStateNameVar, 3)
         System.Threading.Thread.Sleep(100)
         If m_MainWindow.m_CNCommunication.m_CN.n_DReadELS_handle = 3 Then
            Dim CameraStateVal As Integer = CInt(m_MainWindow.m_CNCommunication.m_CN.d_DReadELS_value)
            Select Case CameraStateVal
               Case 0
                  ' Non faccio alcunchè perchè si sta posizionando
               Case 1
                  ' Posizionamento completato
                  bPositionOk = True
                  Exit For
               Case 2
                  ' Errore
                  bPositionOk = False
                  Exit For
            End Select
         End If
         System.Threading.Thread.Sleep(900)
      Next
      m_MainWindow.m_CurrentProjectPageUC.ClearMessage()
      UpdateUI()
      Return bPositionOk
   End Function

   ' OK: Ottengo l'indice del processo associato alla tavola e la configurazione del processo
   Private Function PrepareCamera() As Integer
      ' Stati del processo
      m_bIsRunnigProc = False
      m_bClickOk = False
      m_bCorrectedImgOk = False
      m_bSavedBackImage = False
      ' Argomento utilizzato per verificare lo stato della comunicazione
      Dim sArgs As String = "7"
      Dim nIndTab As Integer = GetCurrentTable()
      Dim nIndProc As Integer = GetProcessFromCurrentTable(nIndTab)
      ' Invio richiesta al processo per vedere se la comunicazione è aperta
      Try
         If Not m_ProcessCmgList(nIndProc - 1).HasExited Then
            m_ProcessCmgList(nIndProc - 1).StandardInput.WriteLine(sArgs)
         Else
            Return -2
         End If
      Catch ex As Exception
         EgtOutLog(ex.Message())
      End Try
      ' Attendo massimo N_LOOP secondi per avere una risposta dal programma (la risposta arriva al metodo Thread_OutputDataReceived)
      For i As Integer = 0 To N_LOOP
         Thread.Sleep(1000)
         If m_bIsRunnigProc Then Exit For
      Next
      ' Se processo non attivo allora provo a rilanciarlo
      If Not m_bIsRunnigProc Then
         EgtOutLog(" ~ PROCESSO NON RISPONDE: Process_" & (nIndProc).ToString())
         ReloadCameraHide(nIndProc - 1)
         For i As Integer = 0 To N_LOOP
            Thread.Sleep(1000)
            ' Invio richiesta al processo per vedere se la comunicazione è aperta
            m_ProcessCmgList(nIndProc - 1).StandardInput.WriteLine(sArgs)
            If m_bIsRunnigProc Then Exit For
         Next
      End If

      ' -----------------------------------------------------------------
      '              ----- PREPARAZIONE PERCORSO FILE -----
      ' -----------------------------------------------------------------
      GetPrivateProfileString(S_CAMERA, K_CAM_IMAGE, "", m_sImage, m_MainWindow.GetIniFile())
      GetPrivateProfileString(S_CAMERA, K_CAM_INFO, "", m_sInfo, m_MainWindow.GetIniFile())
      GetPrivateProfileString(S_CAMERA, K_CAM_RESULT, "", m_sResult, m_MainWindow.GetIniFile())
      GetPrivateProfileString(S_CAMERA, K_CAM_CONTOUR, "", m_sContour, m_MainWindow.GetIniFile())

      If nIndProc <> 1 Then
         m_sImage = m_sImage.Replace(m_sCameraProcName, m_sCameraProcName & (nIndProc).ToString())
         m_sInfo = m_sInfo.Replace(m_sCameraProcName, m_sCameraProcName & (nIndProc).ToString())
         m_sResult = m_sResult.Replace(m_sCameraProcName, m_sCameraProcName & (nIndProc).ToString())
         m_sContour = m_sContour.Replace(m_sCameraProcName, m_sCameraProcName & (nIndProc).ToString())
      End If

      Return If(m_bIsRunnigProc, nIndProc, -1)
   End Function

   ' OK: Scatto foto e aspetto WaitBackImage
   Public Function CameraBackImage() As Boolean
      ' Verifiche preliminari
      Dim nIndProc As Integer = PrepareCamera()
      ' Se non è stato trovato il processo associato alla tavola allora esco
      Select Case nIndProc
         Case -2
            EgtOutLog("Direttorio di configurazione 'CamerMng" & GetCurrentTable().ToString() & "' non è stato trovato")
         Case -1
            EgtOutLog("Camera " & GetCurrentTable().ToString() & " spenta")
      End Select
      If nIndProc < 0 Then Return False
      ' Visualizzo progressbar
      m_bBusy = True
      m_MainWindow.m_CurrentProjectPageUC.ClearMessage()
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgressStackPanel.Visibility = Visibility.Visible
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = 0
      ' Cancellazione eventuali vecchi file rimasti
      Try
         If My.Computer.FileSystem.FileExists(m_sResult) Then
            My.Computer.FileSystem.DeleteFile(m_sResult)
         End If
      Catch ex As Exception
      End Try

      ' Se richiesto: accendo fari ed eventualmente mando la testa in Home
      Dim nIndTab As Integer = GetCurrentTableFromCameraProcess(nIndProc)
      PrepareMachine(nIndTab)

      ' Scatto una foto come sfondo (il programma deve essere già attivo)
      Dim bOk As Boolean = False

      Dim sArgs As String = "4"
      Try
         m_ProcessCmgList(nIndProc - 1).StandardInput.WriteLine(sArgs)
         bOk = WaitBackImage(nIndProc)
      Catch ex As Exception
         bOk = False
      End Try
      ' Nascondo progressbar
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgressStackPanel.Visibility = Visibility.Hidden
      m_bBusy = False
      Return bOk
   End Function

   ' OK: cerco l'immagine nella confidurazione di indica nInd
   Private Function WaitBackImage(nInd As Integer) As Boolean
      Dim dProgVal As Double = 0
      ' verifico che abbia scattato la foto (dalla lettura degli eventi restituiti dal processo)
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgressText.Content = "CLICK"
      For i As Integer = 0 To N_LOOP
         Thread.Sleep(1000)
         If m_bClickOk Then
            m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = m_dClickOk
            ' Costringo ad aggiornare UI
            UpdateUI()
            Exit For
         End If
         m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = m_dClickOk / N_LOOP * (i + 1)
         ' Costringo ad aggiornare UI
         UpdateUI()
      Next
      dProgVal = m_dClickOk
      If Not m_bClickOk Then Return False
      ' verifico che sia stata scaricata l'immagine
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgressText.Content = "DOWNLOAD PIC"
      For i As Integer = 0 To N_LOOP
         Thread.Sleep(1000)
         If m_bDowloadedPicFromCamera Then
            m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = dProgVal + m_dDowloadedPicFromCamera
            ' Costringo ad aggiornare UI
            UpdateUI()
            Exit For
         End If
         m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = dProgVal + m_dDowloadedPicFromCamera / N_LOOP * (i + 1)
         ' Costringo ad aggiornare UI
         UpdateUI()
      Next
      dProgVal = dProgVal + m_dDowloadedPicFromCamera
      If Not m_bDowloadedPicFromCamera Then Return False

      ' verifico che sia stata scaricata l'immagine
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgressText.Content = "SAVE BACKIMG"
      For i As Integer = 0 To N_LOOP
         Thread.Sleep(1000)
         If m_bSavedBackImage Then
            m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = dProgVal + m_dSavedBackImage
            ' Costringo ad aggiornare UI
            UpdateUI()
            Exit For
         End If
         m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = dProgVal + m_dSavedBackImage / N_LOOP * (i + 1)
         ' Costringo ad aggiornare UI
         UpdateUI()
      Next
      dProgVal = dProgVal + m_dSavedBackImage
      If Not m_bSavedBackImage Then Return False

      ' Se esiste il file di risultato (NON ho modo di vedere se il risultato è andato a buon fine)
      Dim nErr = 999
      If VerifyResult(nInd, nErr) Then
         If nErr = 0 Then
            Return True
         Else
            EgtOutLog("Camera err=" & nErr.ToString())
            Return False
         End If
         ' Altrimenti aspetto
      End If

      EgtOutLog("Camera generic error")
      Return False
   End Function

   ' OK: Scatto foto e aspetto WaitPhoto
   Public Function CameraClick() As Boolean
      ' Verifiche preliminari
      Dim nIndProc As Integer = PrepareCamera()
      ' Se non è stato trovato il processo associato alla tavola allora esco
      Select Case nIndProc
         Case -2
            EgtOutLog("Direttorio di configurazione 'CamerMng" & GetCurrentTable().ToString() & "' non è stato trovato")
         Case -1
            EgtOutLog("Camera " & GetCurrentTable().ToString() & " spenta")
      End Select
      If nIndProc < 0 Then Return False
      ' Visualizzo progressbar
      m_bBusy = True
      m_MainWindow.m_CurrentProjectPageUC.ClearMessage()
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgressStackPanel.Visibility = Visibility.Visible
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = 0
      ' Costringo ad aggiornare UI
      UpdateUI()
      ' Cancellazione eventuali vecchi file rimasti
      Try
         If My.Computer.FileSystem.FileExists(m_sResult) Then
            My.Computer.FileSystem.DeleteFile(m_sResult)
         End If
         If My.Computer.FileSystem.FileExists(m_sImage) Then
            My.Computer.FileSystem.DeleteFile(m_sImage)
         End If
         If My.Computer.FileSystem.FileExists(m_sContour) Then
            My.Computer.FileSystem.DeleteFile(m_sContour)
         End If
         If My.Computer.FileSystem.FileExists(m_sInfo) Then
            My.Computer.FileSystem.DeleteFile(m_sInfo)
         End If
      Catch ex As Exception
      End Try

      ' Se richiesto: accendo fari ed eventualmente mando la testa in Home
      Dim nIndTab As Integer = GetCurrentTableFromCameraProcess(nIndProc)
      PrepareMachine(nIndTab)

      ' Scatto una foto con eventuale riconoscimento del contorno (il programma deve essere già attivo)
      Dim bOk As Boolean = False
      Dim sArgs As String = "2"
      ' Per ricavare il contorno bisogna passare i segunti valori: 5,Valore_Soglia
      If m_bCalcContour Then sArgs = "5" & "," & m_nThreshold.ToString()
      Try
         ' invio la richiesta di scattare una foto
         m_ProcessCmgList(nIndProc - 1).StandardInput.WriteLine(sArgs)
         bOk = WaitPhoto()
      Catch ex As Exception
         EgtOutLog(ex.Message())
         bOk = False
      End Try
      ' Nascondo progressbar
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgressStackPanel.Visibility = Visibility.Hidden
      m_bBusy = False
      Return bOk
   End Function

   ' OK: attendo che sia pronta l'immagine
   Private Function WaitPhoto() As Boolean
      Dim dProgVal As Double = 0
      ' verifico che abbia scattato la foto (dalla lettura degli eventi restituiti dal processo)
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgressText.Content = "CLICK"
      For i As Integer = 0 To N_LOOP
         Thread.Sleep(1000)
         If m_bClickOk Then
            m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = m_dClickOk
            ' Costringo ad aggiornare UI
            UpdateUI()
            Exit For
         End If
         m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = m_dClickOk / N_LOOP * (i + 1)
         ' Costringo ad aggiornare UI
         UpdateUI()
      Next
      dProgVal = m_dClickOk
      If Not m_bClickOk Then Return False
      '
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgressText.Content = "DOWNLOAD PIC"
      For i As Integer = 0 To N_LOOP
         Thread.Sleep(1000)
         If m_bDowloadedPicFromCamera Then
            m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = dProgVal + m_dDowloadedPicFromCamera
            ' Costringo ad aggiornare UI
            UpdateUI()
            Exit For
         End If
         m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = dProgVal + m_dDowloadedPicFromCamera / N_LOOP * (i + 1)
         ' Costringo ad aggiornare UI
         UpdateUI()
      Next
      dProgVal = dProgVal + m_dDowloadedPicFromCamera
      If Not m_bDowloadedPicFromCamera Then Return False
      '
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgressText.Content = "READ OCV"
      For i As Integer = 0 To N_LOOP
         Thread.Sleep(1000)
         If m_bReadOCV Then
            m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = dProgVal + m_dReadOCV
            ' Costringo ad aggiornare UI
            UpdateUI()
            Exit For
         End If
         m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = dProgVal + m_dReadOCV / N_LOOP * (i + 1)
         ' Costringo ad aggiornare UI
         UpdateUI()
      Next
      dProgVal = dProgVal + m_dReadOCV
      If Not m_bReadOCV Then Return False
      '
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgressText.Content = "START DIST"
      For i As Integer = 0 To N_LOOP
         Thread.Sleep(1000)
         If m_bStartDistCorrect Then
            m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = dProgVal + m_dStartDistCorrect
            ' Costringo ad aggiornare UI
            UpdateUI()
            Exit For
         End If
         m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = dProgVal + m_dStartDistCorrect / N_LOOP * (i + 1)
         ' Costringo ad aggiornare UI
         UpdateUI()
      Next
      dProgVal = dProgVal + m_dStartDistCorrect
      If Not m_bStartDistCorrect Then Return False
      '
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgressText.Content = "START PROSP"
      For i As Integer = 0 To N_LOOP
         Thread.Sleep(1000)
         If m_bStartProspCorrect Then
            m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = dProgVal + m_dStartProspCorrect
            ' Costringo ad aggiornare UI
            UpdateUI()
            Exit For
         End If
         m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = dProgVal + m_dStartProspCorrect / N_LOOP * (i + 1)
         ' Costringo ad aggiornare UI
         UpdateUI()
      Next
      dProgVal = dProgVal + m_dStartProspCorrect
      If Not m_bStartProspCorrect Then Return False
      ' verifico che il processo di correzione della foto sia terminato correttamente
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgressText.Content = "CORRECT IMG"
      For i As Integer = 0 To N_LOOP
         Thread.Sleep(1000)
         If m_bCorrectedImgOk Then
            m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = dProgVal + m_dCorrectedImgOk
            ' Costringo ad aggiornare UI
            UpdateUI()
            Exit For
         End If
         m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = dProgVal + m_dCorrectedImgOk / N_LOOP * (i + 1)
         ' Costringo ad aggiornare UI
         UpdateUI()
      Next
      dProgVal = dProgVal + m_dCorrectedImgOk
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgressText.Content = "IMPORT IMG"
      ' Copio i file
      Dim sImageDest As String = m_sImageDir & "\" & Path.GetFileName(m_sImage)
      Dim sInfoDest As String = Path.ChangeExtension(sImageDest, "txt")
      File.Copy(m_sImage, sImageDest, True)
      File.Copy(m_sInfo, sInfoDest, True)
      ' Se richiesto il riconoscimento del contorno
      Dim sContourDest As String = String.Empty
      If m_bCalcContour Then
         sContourDest = Path.ChangeExtension(sImageDest, "dxf")
         File.Copy(m_sContour, sContourDest, True)
         ' altrimenti cancello eventuale contorno presente
      Else
         m_MainWindow.m_CurrentProjectPageUC.RemoveContour()
      End If
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = 95
      ' Costringo ad aggiornare UI
      UpdateUI()
      ' Lancio caricamento della foto e del contorno
      m_MainWindow.m_CadCutPageUC.PostPhoto(sImageDest, sContourDest)
      Return True

   End Function

   ' OK: verifica che la backimage sia stata scaricata correttamente nel direttorio CameraMng#n
   Private Function VerifyResult(nInd As Integer, ByRef nErr As Integer) As Boolean
      ' Se non esiste il file con il risultato
      If Not My.Computer.FileSystem.FileExists(m_sResult) Then
         Return False
      End If
      ' Leggo il file
      Dim bOk As Boolean = False
      Try
         ' Controllo errori nel file di info
         Dim sLine As String = String.Empty
         Dim sr As StreamReader = New StreamReader(m_sResult)
         Do While sr.Peek() > -1
            sLine = sr.ReadLine()
            sLine = sLine.Replace(" ", "")
            If sLine.StartsWith("Err=") Then
               If Int32.TryParse(sLine.Substring(4), nErr) Then
                  bOk = True
                  Exit Do
               End If
            End If
         Loop
         sr.Close()
      Catch ex As Exception
         bOk = False
      End Try
      Return bOk
   End Function

   ' OK: chiudo tutti i processi di CameraMng in esecuzione prima dell'avvio
   Private Sub KillPreviousProcesses()
      If Not m_bCameraLink Then Return
      Dim Procs() As Process
      Procs = Process.GetProcessesByName(m_sCameraProcName)
      For i As Integer = 0 To Procs.Count() - 1
         Try
            Procs(i).Kill()
            Procs(i).WaitForExit( 50)
         Catch Ex As Exception
            EgtOutLog(ex.Message())
         End Try
      Next
   End Sub

   ' OK: chiudo tutti i processi di CameraMng lanciati
   Private Sub KillProcesses()
      For i As Integer = 0 To m_ProcessCmgList.Count() - 1
         Try
            m_ProcessCmgList(i).Kill()
         Catch Ex As Exception
            EgtOutLog(ex.Message())
         End Try
      Next
   End Sub

End Class
