'----------------------------------------------------------------------------
'  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

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_sCameraPath2 As String = String.Empty
   Private m_sCameraProcName As String = String.Empty
   Private m_sCameraProcName2 As String = String.Empty
   Private m_sImage As String = String.Empty
   Private m_sImage2 As String = String.Empty
   Private m_sInfo As String = String.Empty
   Private m_sInfo2 As String = String.Empty
   Private m_sResult As String = String.Empty
   Private m_sResult2 As String = String.Empty
   Private m_sContour As String = String.Empty
   Private m_sContour2 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

   ' 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)
      m_nCameraCount = GetPrivateProfileInt(S_CAMERA, K_CAM_COUNT, 1, m_MainWindow.GetIniFile())
      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())
      GetPrivateProfileString(S_CAMERA, K_CAM_EXEPATH2, "", m_sCameraPath2, m_MainWindow.GetIniFile())
      GetPrivateProfileString(S_CAMERA, K_CAM_IMAGE2, "", m_sImage2, m_MainWindow.GetIniFile())
      GetPrivateProfileString(S_CAMERA, K_CAM_INFO2, "", m_sInfo2, m_MainWindow.GetIniFile())
      GetPrivateProfileString(S_CAMERA, K_CAM_RESULT2, "", m_sResult2, m_MainWindow.GetIniFile())
      GetPrivateProfileString(S_CAMERA, K_CAM_CONTOUR2, "", m_sContour2, 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)
      m_sCameraProcName2 = Path.GetFileNameWithoutExtension(m_sCameraPath2)
      ' Se camera abilitata, lancio l'esecuzione in cieco
      If m_bCameraLink Then
         If m_nCameraCount <> 2 Then
            Dim bOk As Boolean = True
            If Not CameraHide(1) Then
               bOk = False
               EgtOutLog("CameraMng not starting")
            End If
            Return bOk
         Else
            Dim bOk As Boolean = True
            If Not CameraHide(1) Then
               bOk = False
               EgtOutLog("CameraMng 1 not starting")
            End If
            If Not CameraHide(2) Then
               bOk = False
               EgtOutLog("CameraMng 2 not starting")
            End If
            Return bOk
         End If
      Else
         Return True
      End If
   End Function

   Public Function Close() As Boolean
      If m_bBusy Then Return False
      If m_bCameraLink Then
         If m_nCameraCount <> 2 Then
            KillProcess(1)
         Else
            KillProcess(1)
            KillProcess(2)
         End If
      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

   Public Function CameraHide(nInd As Integer) As Boolean
      ' Lancio il programma in cieco, se già attivo lo nascondo
      Try
         Process.Start(If(nInd <> 2, m_sCameraPath, m_sCameraPath2), "0")
         Return True
      Catch ex As Exception
         Return False
      End Try
   End Function

   Public Function CameraShow(nInd As Integer) As Boolean
      ' Lancio il programma in modo visibile, se già attivo lo rendo visibile
      Try
         Process.Start(If(nInd <> 2, m_sCameraPath, m_sCameraPath2), "1")
         Return True
      Catch ex As Exception
         Return False
      End Try
   End Function

   Public Function CameraTest(nInd As Integer) As Boolean
      ' Cancello il risultato
      If My.Computer.FileSystem.FileExists(If(nInd <> 2, m_sResult, m_sResult2)) Then
         My.Computer.FileSystem.DeleteFile(If(nInd <> 2, m_sResult, m_sResult2))
      End If
      ' Lancio il programma per sapere se macchina fotografica collegata
      Try
         ' Interrogo
         Process.Start(If(nInd <> 2, m_sCameraPath, m_sCameraPath2), "3")
         ' Ciclo di attesa risultato
         Dim nMaxThick = 10 * 4
         For nThick As Integer = 0 To nMaxThick
            ' Se esiste il file di risultato
            Dim nErr = 999
            If VerifyResult(nInd, nErr) Then
               Return (nErr = 0)
            End If
            ' Aspetto 100 ms
            Thread.Sleep(100)
         Next
      Catch ex As Exception
         '
      End Try
      Return False
   End Function

   Private Function PrepareCamera() As Integer
      ' Determino la camera da utilizzare, se più di una (max 2)
      Dim nInd As Integer = 1
      If m_nCameraCount = 2 Then
         nInd = GetCurrentTable()
         If nInd <> 1 And nInd <> 2 Then Return 0
      End If
      ' Se gestore macchina non attivo, lo lancio in modo cieco
      If Not ProcessIsRunning(nInd) Then
         If Not CameraHide(nInd) Then
            Return 0
         End If
         ' Aspetto 5000 ms
         Thread.Sleep(5000)
      ' Altrimenti richiedo verifica di camera connessa
      Else
         If Not CameraTest(nInd) Then
            Return 0
         End If
         ' Aspetto 100 ms
         Thread.Sleep(100)
      End If
      Return nInd
   End Function

   Public Function CameraBackImage() As Boolean
      ' Verifiche preliminari
      Dim nInd As Integer = PrepareCamera()
      If nInd = 0 Then Return False
      ' Visualizzo progressbar
      m_bBusy = True
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Visibility = Visibility.Visible
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = 1
      ' Cancellazione eventuali vecchi file rimasti
      Try
         If My.Computer.FileSystem.FileExists(If(nInd <> 2, m_sResult, m_sResult2)) Then
            My.Computer.FileSystem.DeleteFile(If(nInd <> 2, m_sResult, m_sResult2))
         End If
      Catch ex As Exception
      End Try
      ' Scatto una foto come sfondo (il programma deve essere già attivo)
      Dim bOk As Boolean = False
      Try
         Process.Start(If(nInd <> 2, m_sCameraPath, m_sCameraPath2), "4")
         bOk = WaitBackImage(nInd)
      Catch ex As Exception
         bOk = False
      End Try
      ' Nascondo progressbar
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Visibility = Visibility.Hidden
      m_bBusy = False
      Return bOk
   End Function

   Private Function WaitBackImage(nInd As Integer) As Boolean
      ' Ciclo di ricerca foto scattata
      Dim nMaxThick = 10 * m_nTimeout
      For nThick As Integer = 0 To nMaxThick
         ' Se esiste il file di risultato
         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
         Else
            ' Imposto ProgressBar
            Dim nProgress As Integer = CInt(nThick * 100 / nMaxThick)
            m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = nProgress
            ' Costringo ad aggiornare UI
            UpdateUI()
            ' Aspetto 100 ms
            Thread.Sleep(100)
         End If
      Next
      EgtOutLog("Camera generic error")
      ' Chiudo il gestore della macchina per resettarlo
      KillProcess(nInd)
      Return False
   End Function

   Public Function CameraClick() As Boolean
      ' Verifiche preliminari
      Dim nInd As Integer = PrepareCamera()
      ' Visualizzo progressbar
      m_bBusy = True
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Visibility = Visibility.Visible
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = 1
      ' Cancellazione eventuali vecchi file rimasti
      Try
         If My.Computer.FileSystem.FileExists(If(nInd <> 2, m_sResult, m_sResult2)) Then
            My.Computer.FileSystem.DeleteFile(If(nInd <> 2, m_sResult, m_sResult2))
         End If
         If My.Computer.FileSystem.FileExists(If(nInd <> 2, m_sImage, m_sImage2)) Then
            My.Computer.FileSystem.DeleteFile(If(nInd <> 2, m_sImage, m_sImage2))
         End If
         If My.Computer.FileSystem.FileExists(If(nInd <> 2, m_sContour, m_sContour2)) Then
            My.Computer.FileSystem.DeleteFile(If(nInd <> 2, m_sContour, m_sContour2))
         End If
         If My.Computer.FileSystem.FileExists(If(nInd <> 2, m_sInfo, m_sInfo2)) Then
            My.Computer.FileSystem.DeleteFile(If(nInd <> 2, m_sInfo, m_sInfo2))
         End If
      Catch ex As Exception
      End Try

      ' ------------------------------------ accensione riflettori ------------------------------------
      Dim sPLCVarSpotLight1 As String = String.Empty
      GetPrivateProfileString(S_NCDATA, K_SPOTLIGHT1, "", sPLCVarSpotLight1, m_MainWindow.GetMachIniFile())
      Dim sPLCVarSpotLight2 As String = String.Empty
      GetPrivateProfileString(S_NCDATA, K_SPOTLIGHT2, "", sPLCVarSpotLight2, m_MainWindow.GetMachIniFile())
      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(If(nInd <> 2, sPLCVarSpotLight1, sPLCVarSpotLight2), "1")
               ' altrimenti scrittura delle variabili E
            Else
               m_MainWindow.m_CNCommunication.m_CN.DVariables_WriteVariables2(If(nInd <> 2, sPLCVarSpotLight1, sPLCVarSpotLight2), "1")
            End If
            System.Threading.Thread.Sleep(nPhotoDeley)
         Case 3
            ' SIEMENS
      End Select

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

      ' Scatto una foto con eventuale riconoscimento del contorno (il programma deve essere già attivo)
      Dim bOk As Boolean = False
      Dim sArgs As String = "2 0"
      If m_bCalcContour Then sArgs = " 5 0 " & m_nThreshold.ToString() & " 0"
      Try
         Process.Start(If(nInd <> 2, m_sCameraPath, m_sCameraPath2), sArgs)
         bOk = WaitPhoto(nInd)
      Catch ex As Exception
         EgtOutLog(ex.Message())
         bOk = False
      End Try
      ' Nascondo progressbar
      m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Visibility = Visibility.Hidden
      m_bBusy = False
      Return bOk
   End Function

   Private Function WaitPhoto(nInd As Integer) As Boolean
      ' Ciclo di ricerca foto scattata
      Dim nMaxThick = 10 * m_nTimeout
      For nThick As Integer = 0 To nMaxThick
         ' Se esiste il file di risultato
         Dim nErr = 999
         If VerifyResult(nInd, nErr) Then
            If nErr = 0 Then
               ' Copio i file
               Dim sImageDest As String = m_sImageDir & "\" & Path.GetFileName(If(nInd <> 2, m_sImage, m_sImage2))
               Dim sInfoDest As String = Path.ChangeExtension(sImageDest, "txt")
               File.Copy(If(nInd <> 2, m_sImage, m_sImage2), sImageDest, True)
               File.Copy(If(nInd <> 2, m_sInfo, m_sInfo2), 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(If(nInd <> 2, m_sContour, m_sContour2), sContourDest, True)
               ' altrimenti cancello eventuale contorno presente
               Else
                  m_MainWindow.m_CurrentProjectPageUC.RemoveContour()
               End If
               ' Lancio caricamento della foto e del contorno
               m_MainWindow.m_CadCutPageUC.PostPhoto(sImageDest, sContourDest)
               Return True
            Else
               EgtOutLog("Camera err=" & nErr.ToString())
               Return False
            End If
         ' Altrimenti aspetto
         Else
            ' Imposto ProgressBar
            Dim nProgress As Integer = CInt(nThick * 100 / nMaxThick)
            m_MainWindow.m_CurrentProjectPageUC.PhotoProgress.Value = nProgress
            ' Costringo ad aggiornare UI
            UpdateUI()
            ' Aspetto 100 ms
            Thread.Sleep(100)
         End If
      Next
      EgtOutLog("Camera generic error")
      ' Chiudo il gestore della macchina per resettarlo
      KillProcess(nInd)
      Return False
   End Function

   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(If(nInd <> 2, m_sResult, m_sResult2)) 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(If(nInd <> 2, m_sResult, m_sResult2))
         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

   Private Function ProcessIsRunning(nInd As Integer) As Boolean
      Dim Procs() As Process
      Procs = Process.GetProcessesByName(If(nInd <> 2, m_sCameraProcName, m_sCameraProcName2))
      Return (Procs.Length() > 0)
   End Function

   Private Sub KillProcess(nInd As Integer)
      Dim Procs() As Process
      Procs = Process.GetProcessesByName(If(nInd <> 2, m_sCameraProcName, m_sCameraProcName2))
      For i As Integer = 0 To Procs.Length() - 1
         Procs(i).Kill()
         Procs(i).WaitForExit(2000)
      Next i
    End Sub

End Class
