Option Strict On

Imports RYENVLib
Imports System.Drawing
Imports System.Runtime.Remoting
Imports System.Threading
Imports System.Runtime.InteropServices
Imports System.Reflection
Imports System.IO

Imports Mbark.Sensors

Namespace Mbark
    Public Class OlympusFaceCam
        Inherits MarshalByRefObject
        Implements IFaceSensor


        Private mNineCameraMode As Boolean

        Private mRye As RyeNVControl = Nothing
        Private mCameraCount As Integer
        Private mIsConnected As Boolean
        Private mIsInitialized As Boolean
        Private mZoom As Double
        Private mLCDMode As Integer
        Private mFlashMode As Boolean

        Private mIsDownloadCancelled As Boolean = False
        Public Property IsDownloadCancelled() As Boolean Implements Sensors.IFaceSensor.IsDownloadCanceled
            Get
                Return mIsDownloadCancelled
            End Get
            Set(ByVal Value As Boolean)
                mIsDownloadCancelled = Value
            End Set
        End Property


        Private mIsRefresh As Boolean = False
        Private Property IsRefresh() As Boolean
            Get
                Return mIsRefresh
            End Get
            Set(ByVal Value As Boolean)
                mIsRefresh = Value
            End Set
        End Property

        Public Sub Trace(ByVal s As String)
            Debugging.WriteLine(Date.Now & ": " & s)
        End Sub

        Public Sub New()
            MyBase.New()
            mRye = Nothing
            mIsConnected = False
            Trace("New")
        End Sub

        Public ReadOnly Property CameraCount() As Integer Implements IFaceSensor.CameraCount
            Get
                Return mCameraCount
            End Get
        End Property

        Public Function Capture(ByVal UseNineCamera As Boolean) As Boolean Implements Sensors.IFaceSensor.Capture
            Try
                mNineCameraMode = UseNineCamera
                If Not RequireConnect() Then Return False
                For i As Integer = 0 To mCameraCount - 1
                    mRye.Capture(i, 1)
                Next
                System.Threading.Thread.Sleep(6000)
                Dim indexList() As Integer
                For i As Integer = 0 To mCameraCount - 1
                    ReDim Preserve indexList(i)
                    indexList(i) = (mRye.PropPicCount(i) - 1)
                Next
                mPictureIndexList = indexList
                Trace("Captured")
                Return True
            Catch ex As Exception
                Return False
                Trace("Captured " & ex.Message)
                Throw (ex)
            Finally
                RequireDisconnect()
            End Try
        End Function

        Private mPictureIndexList() As Integer
        Public ReadOnly Property GetPictureIndexList() As Integer() Implements IFaceSensor.GetPictureIndexList
            Get
                Return mPictureIndexList
            End Get
        End Property

        Public Sub Close() Implements IFaceSensor.Close
            Try
                If mIsConnected Then
                    For i As Integer = 0 To mCameraCount - 1
                        mRye.DisConnect(i)
                    Next
                    mIsConnected = False

                    Trace("Closed")
                End If
            Catch ex As Exception
                Trace("Error" & vbCrLf & ex.Message() & vbCrLf & ex.StackTrace)
                mIsConnected = False
                Throw (ex)
            End Try
        End Sub

        Public Sub Refresh() Implements IFaceSensor.Refresh
            'disconnect, if connect is open
            If mIsConnected Then Close()
            'un-initialize control 
            UnInitialize()
            Trace("In Refresh")
            InitializeControl(False)
        End Sub

        Public Sub DeleteAll(ByVal UseNineCamera As Boolean) Implements IFaceSensor.DeleteAll
            Try
                mNineCameraMode = UseNineCamera
                RequireConnect()
                Trace("Delete All")
                For i As Integer = 0 To mCameraCount - 1
                    mRye.EraseAll(i)
                Next
                RequireDisconnect()
            Catch ex As Exception
                Close()
                Throw ex
            End Try
        End Sub

        Public Sub DeleteLast() Implements IFaceSensor.DeleteLast
            Try
                Trace("Delete")
                For i As Integer = 0 To mCameraCount - 1
                    mRye.EraseLast(i)
                Next
            Catch ex As Exception
            End Try
        End Sub

        Public Function Init(ByVal LCDMode As Integer, ByVal Zoom As Double, ByVal FlashMode As Boolean) As Boolean Implements IFaceSensor.Init
            Try
                mZoom = Zoom
                mFlashMode = FlashMode
                mLCDMode = LCDMode
                'Trace("Zoom = " & mZoom & " FlashMode = " & mFlashMode.ToString & " LCDMode = " & mLCDMode)
                Return InitializeControl()
            Catch ex As Exception
                Return False
            End Try

        End Function
        Public Function Init() As Boolean Implements IFaceSensor.Init
            Try
                Return InitializeControl(False)
            Catch ex As Exception
                Return False
            End Try
        End Function
        Public Function Init(ByVal UseNineCamera As Boolean) As Boolean Implements IFaceSensor.Init
            Try
                mNineCameraMode = UseNineCamera
                Return InitializeControl(False)
            Catch ex As Exception

            End Try
        End Function
        Public Function Open() As Boolean Implements IFaceSensor.Open
            If Not mIsConnected Then
                Try
                    For i As Integer = 0 To mCameraCount - 1
                        mRye.Connect(i)
                    Next
                    mIsConnected = True
                    Trace("Open")
                    Return True
                Catch ex As Exception
                    Return False
                End Try
            Else 'is connected
                Return True
            End If

        End Function
        Private Sub SetCaptureProperties(ByVal flash As Boolean)
            Trace("Setting Control Properties " & mCameraCount)
            For c As Integer = 0 To mCameraCount - 1
                If mFlashMode Then
                    mRye.PropFlash(c) = RyeFlash.RYE_FLASH_ON
                Else
                    mRye.PropFlash(c) = RyeFlash.RYE_FLASH_OFF
                End If
                mRye.PropResolution(c) = 16 'RyeResolution.RYE_2816_2112_JPEG_TYPE_H
                mRye.PropOpticalZoom(c) = CInt(mZoom * 10)
                'Trace("ZOOMED = " & mRye.PropOpticalZoom(c))
                mRye.SetLcdMode(c, mLCDMode)
                mRye.PropExpoBias(c) = RyeExposureMode.RYE_EXPOSURE_APERTURE_PRIORITY
                mRye.PropWhiteBalance(c) = RyeWhiteBalance.RYE_WB_AUTO

            Next
        End Sub
        Public Function SaveCaptureProperties(ByVal PropList As Hashtable) As Boolean Implements IFaceSensor.SaveCaptureProperties
            Open()
            Try
                If mCameraCount = NumberOfCameraRequire Then
                    With mRye
                        For c As Integer = 0 To mCameraCount - 1
                            .PropFlash(c) = CInt(PropList.Item("Flash"))
                            .PropOpticalZoom(c) = CInt(CDbl(PropList.Item("Zoom")) * 10)
                            .PropExpoBias(c) = CInt(PropList.Item("Exposure"))
                            .PropWhiteBalance(c) = CInt(PropList.Item("WB"))
                            .PropResolution(c) = CInt(PropList.Item("Resolution"))
                            .SetLcdMode(c, CInt(PropList.Item("LCD")))
                        Next
                        Close()
                    End With
                    Trace("Save capture properties done.")
                    Return True
                Else
                    Trace("Save capture properties failed.")
                    Return False
                End If
            Catch ex As Exception
                Debugging.WriteLine(ex.Message)
            End Try
        End Function
        Public Function GetCaptureProperties(ByVal PropList As Hashtable) As Boolean Implements IFaceSensor.GetCaptureProperties
            Open()
            Try
                Debugging.WriteLine("Camera opened")
                If mCameraCount = 9 Then
                    PropList.Add("CamCount", mCameraCount)
                    PropList.Add("CameraModel", mRye.PropConnectCamera(0))
                    PropList.Add("Flash", mRye.PropFlash(0))
                    PropList.Add("Zoom", mRye.PropOpticalZoom(0))
                    PropList.Add("Exposure", mRye.PropExpoBias(0))
                    PropList.Add("WB", mRye.PropWhiteBalance(0))
                    PropList.Add("Resolution", mRye.PropResolution(0))
                    Return True
                Else
                    PropList.Add("CamCount", mCameraCount)
                    PropList.Add("CameraModel", mRye.PropConnectCamera(0))
                    Return False
                End If
                Close()
            Catch ex As Exception
                Debugging.WriteLine(ex.ToString)
            End Try
        End Function
        Public ReadOnly Property PictureCount(ByVal cameraNumber As Integer) As Integer Implements IFaceSensor.PictureCount
            Get
                If Not mIsConnected Then Open()
                Try
                    Dim rv As Integer = mRye.PropPicCount(cameraNumber)
                    Return rv
                Catch ex As Exception
                    'Dim fcex As New FaceCamException("Camera " & CamNum & " threw exception: " & ex.Message())
                    'Throw fcex
                End Try
            End Get
        End Property

        Public Function Picture(ByVal CamNum As Integer, ByVal index As Integer) As Byte() Implements IFaceSensor.Picture
            Dim ImgArray() As Byte
            Try
                If Not mIsDownloadCancelled Then
                    If Not mIsInitialized Then Init()
                    Open()
                    If Image(ImgArray, CamNum, index, AddressOf mRye.GetPicture, AddressOf GetPictureSize) Then
                        Return ImgArray
                    Else
                        Return Nothing
                    End If
                End If
            Catch ex As Exception
            Finally
                Close()
            End Try
        End Function

        Public Sub Reset() Implements IFaceSensor.Reset
            Trace("Resetting camera immediately.")
            Close()
            ' This *should* destroy the control
            mRye = Nothing
            System.GC.Collect()
            System.GC.WaitForPendingFinalizers()
            InitializeControl()
        End Sub

        Public Sub Status(ByVal cameraCount As Integer, ByVal cameraIDs() As String) Implements IFaceSensor.Status
            Trace("Status")
        End Sub

        Public Function DownloadThumbnail(ByVal PictureIndexList() As Integer) As Boolean Implements IFaceSensor.DownloadThumbnail
            Trace("Downloading Thumbnails...")
            Try
                If Not RequireConnect() Then Return False
                Dim Img(mCameraCount - 1)()() As Byte
                For c As Integer = 0 To mCameraCount - 1
                    ReDim Preserve Img(c)(0)
                    Debugging.WriteLine("[Thumbnail]" & PictureIndexList(c).ToString)
                    Image(Img(c)(0), c, PictureIndexList(c), AddressOf mRye.GetIndex, AddressOf GetThumbnailSize)
                Next
                mThumbnails = Img
                Return True
            Catch ex As Exception
                Trace("[Thumbnail] " & ex.Message)
                Return False
            Finally
                RequireDisconnect()
            End Try
        End Function

        Private mThumbnails As Byte()()()
        Public ReadOnly Property Thumbnails() As Byte()()() Implements IFaceSensor.Thumbnails
            Get
                Return mThumbnails
            End Get
        End Property

        Public Sub SetCameraIds(ByVal cameraId() As String) Implements Sensors.IFaceSensor.SetCameraIds
            Open()
            For c As Integer = 0 To mCameraCount - 1
                mRye.PropCameraID(c) = cameraId(c)
            Next
        End Sub
        Public ReadOnly Property GetCameraID() As String() Implements IFaceSensor.GetCameraID
            Get
                Dim CameraID() As String
                RequireConnect()
                For c As Integer = 0 To mCameraCount - 1
                    Debugging.WriteLine("IN GET CAMERA ID")
                    ReDim Preserve CameraID(c)
                    If mRye Is Nothing Then Debugging.WriteLine("GetCameraID ")
                    CameraID(c) = mRye.PropCameraID(c)
                    Debugging.WriteLine("GetCameraID " & CameraID.Length)
                Next
                RequireDisconnect()
                Return CameraID
            End Get
        End Property

        Public Sub UnInitialize() Implements IFaceSensor.UnInitialize
            Trace("UnInit")
            mIsInitialized = False
            mIsConnected = False
            mRye = Nothing
        End Sub

        Public ReadOnly Property IsFull() As Boolean Implements IFaceSensor.IsFull
            Get
                Try
                    If Not RequireConnect() Then Return False
                    For i As Integer = 0 To mCameraCount - 1
                        If mRye.PropRemainCount(i) = 0 Then Return True
                    Next
                    Return False
                Catch ex As Exception
                    Return False
                Finally
                    RequireDisconnect()
                End Try

            End Get
        End Property

        Public Function RequireConnect() As Boolean Implements IFaceSensor.RequireConnect
            'require to Initialize Control without configure the camera properties
            If InitializeControl(False) Then
                'Open Connection
                If Open() Then
                    Return True
                End If
            End If
            Return False

        End Function

        Public Sub RequireDisconnect() Implements IFaceSensor.RequireDisconnect
            'Close connection before Uninitialize controls
            Close()
            UnInitialize()
        End Sub

        Public ReadOnly Property ConfigurationType() As Type Implements IFaceSensor.ConfigurationType
            Get
                Return Nothing
            End Get
        End Property
#Region "      Private Functions       "
        ' Picture / thumbnail delegates

        Private Delegate Sub GetImageDelegateType( _
                    ByVal CamNum As Integer, _
                    ByVal BufferSize As Integer, _
                    ByRef Buffer As Object)
        Private Delegate Function GetImageSizeDelegateType(ByVal CamNum As Integer) As Integer

        ' Wrapper to PropPicSize because properties cannot be delegates (apparently)
        Private Function GetPictureSize(ByVal C As Integer) As Integer
            Return mRye.PropPicSize(C)
        End Function

        Private Function GetThumbnailSize(ByVal C As Integer) As Integer
            'Trace("In Get Thumbnail Size")
            Return mRye.PropIndexSize(C)
        End Function

        Private Function Image( _
                    ByRef Img() As Byte, _
                    ByVal CamNum As Integer, _
                    ByVal PicNum As Integer, _
                    ByVal GetImageDelegate As GetImageDelegateType, _
                    ByVal GetImageSizeDelegate As GetImageSizeDelegateType) As Boolean
            Try
                Trace("About to download picture " & PicNum & " from camera " & CamNum)
                mRye.PropCurrentPicture(CamNum) = PicNum + 1
                Dim picSize As Integer = GetImageSizeDelegate(CamNum)
                ReDim Img(picSize - 1)
                Dim boxedBuffer As Object = Img
                GetImageDelegate(CamNum, picSize, boxedBuffer)
                Array.Copy(DirectCast(boxedBuffer, Byte()), Img, picSize)
                Return True
            Catch ex As Exception
                Trace("[Image] " & ex.Message)
                Return False
            End Try
        End Function
        Private NumberOfCameraRequire As Integer
        Private Function InitializeControl(Optional ByVal RequireSetProperty As Boolean = True) As Boolean
            Trace("Initializing Controls")
            Try
                mRye = New RyeNVControl
                mRye.InitControl()
                mCameraCount = mRye.PropCameraCount
                'Dim NumbersOfCameraRequire As Integer
                If mNineCameraMode Then
                    NumberOfCameraRequire = 9
                Else
                    NumberOfCameraRequire = 1
                End If
                Debugging.WriteLine("[Debug] NumberOfCameraRequire = " & NumberOfCameraRequire)
                Debugging.WriteLine("[Debug] mCameraCount = " & mCameraCount)
                If mCameraCount = NumberOfCameraRequire Then
                    If RequireSetProperty Then
                        Open()
                        SetCaptureProperties(False)
                        Close()
                    End If
                    Trace(mCameraCount & " cameras detected")
                    mIsInitialized = True
                    Return True
                Else
                    Trace("Initizalization failed " & mCameraCount & " cameras detected")
                    mIsInitialized = False
                    Return False
                End If
            Catch ex As Exception
            End Try
        End Function

#End Region

    End Class

End Namespace
