Option Strict On

Imports System.IO
Imports System.Drawing
Imports System.Delegate
Imports System.Text
Imports System.Threading
Imports System.Runtime.Serialization.Formatters.Binary

Imports Mbark.Threading
Imports Mbark.UI
Imports Mbark.SensorMessages

Imports AxLSCAPTURECTRLLib
Imports LSCAPTURECTRLLib

Namespace Mbark.Sensors
    Public Class SmithsHeimmanSensor
        Inherits BaseSensor

#Region " Windows Form Designer generated code "

        Public Sub New()
            MyBase.New()

            'This call is required by the Windows Form Designer.
            InitializeComponent()

            'Add any initialization after the InitializeComponent() call
            CreateNew()
        End Sub

        'UserControl overrides dispose to clean up the component list.
        Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
            If disposing Then
                If Not (components Is Nothing) Then
                    components.Dispose()
                End If
            End If
            MyBase.Dispose(disposing)
        End Sub

        'Required by the Windows Form Designer
        Private components As System.ComponentModel.IContainer

        'NOTE: The following procedure is required by the Windows Form Designer
        'It can be modified using the Windows Form Designer.  
        'Do not modify it using the code editor.
        '        Friend WithEvents mSHB_LS2Ctrl As AxLSCAPTURECTRLLib.AxLsCaptureCtrl
        Friend WithEvents TimeOutCounter As System.Windows.Forms.Timer
        '        Friend WithEvents mSHB_LS2Ctrl As AxLSCAPTURECTRLLib.AxLsCaptureCtrl
        Friend WithEvents mSHBMessageCtrl As Syncfusion.Windows.Forms.Tools.GradientLabel
        Friend WithEvents mSHB_LS2Ctrl As AxLSCAPTURECTRLLib.AxLsCaptureCtrl
        <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
            Me.components = New System.ComponentModel.Container
            Dim resources As System.Resources.ResourceManager = New System.Resources.ResourceManager(GetType(SmithsHeimmanSensor))
            Me.TimeOutCounter = New System.Windows.Forms.Timer(Me.components)
            Me.mSHBMessageCtrl = New Syncfusion.Windows.Forms.Tools.GradientLabel
            Me.mSHB_LS2Ctrl = New AxLSCAPTURECTRLLib.AxLsCaptureCtrl
            Me.MainPanel.SuspendLayout()
            Me.InnerPanel.SuspendLayout()
            CType(Me.OuterPanel, System.ComponentModel.ISupportInitialize).BeginInit()
            Me.OuterPanel.SuspendLayout()
            CType(Me.mSHB_LS2Ctrl, System.ComponentModel.ISupportInitialize).BeginInit()
            Me.SuspendLayout()
            '
            'ActivateSensorButton
            '
            Me.ActivateSensorButton.Name = "ActivateSensorButton"
            '
            'CancelSensorButton
            '
            Me.CancelSensorButton.Name = "CancelSensorButton"
            '
            'TimeoutIndicator
            '
            Me.TimeoutIndicator.Name = "TimeoutIndicator"
            Me.TimeoutIndicator.Size = New System.Drawing.Size(638, 16)
            '
            'MainPanel
            '
            Me.MainPanel.Controls.Add(Me.mSHB_LS2Ctrl)
            Me.MainPanel.Controls.Add(Me.mSHBMessageCtrl)
            Me.MainPanel.Name = "MainPanel"
            Me.MainPanel.Size = New System.Drawing.Size(816, 408)
            '
            'InnerPanel
            '
            Me.InnerPanel.Name = "InnerPanel"
            Me.InnerPanel.Size = New System.Drawing.Size(638, 358)
            '
            'OuterPanel
            '
            Me.OuterPanel.Name = "OuterPanel"
            Me.OuterPanel.Size = New System.Drawing.Size(640, 440)
            '
            'mSHBMessageCtrl
            '
            Me.mSHBMessageCtrl.BackgroundColor = New Syncfusion.Drawing.BrushInfo(Syncfusion.Drawing.GradientStyle.Vertical, System.Drawing.Color.FromArgb(CType(237, Byte), CType(240, Byte), CType(247, Byte)), System.Drawing.SystemColors.ActiveCaptionText)
            Me.mSHBMessageCtrl.BorderSides = CType((((System.Windows.Forms.Border3DSide.Left Or System.Windows.Forms.Border3DSide.Top) _
                        Or System.Windows.Forms.Border3DSide.Right) _
                        Or System.Windows.Forms.Border3DSide.Bottom), System.Windows.Forms.Border3DSide)
            Me.mSHBMessageCtrl.BorderStyle = System.Windows.Forms.Border3DStyle.Flat
            Me.mSHBMessageCtrl.Dock = System.Windows.Forms.DockStyle.Fill
            Me.mSHBMessageCtrl.Font = New System.Drawing.Font("Microsoft Sans Serif", 14.25!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
            Me.mSHBMessageCtrl.Location = New System.Drawing.Point(0, 0)
            Me.mSHBMessageCtrl.Name = "mSHBMessageCtrl"
            Me.mSHBMessageCtrl.Size = New System.Drawing.Size(816, 408)
            Me.mSHBMessageCtrl.TabIndex = 0
            Me.mSHBMessageCtrl.TextAlign = System.Drawing.ContentAlignment.MiddleCenter
            '
            'mSHB_LS2Ctrl
            '
            Me.mSHB_LS2Ctrl.ContainingControl = Me
            Me.mSHB_LS2Ctrl.Enabled = True
            Me.mSHB_LS2Ctrl.Location = New System.Drawing.Point(456, 272)
            Me.mSHB_LS2Ctrl.Name = "mSHB_LS2Ctrl"
            Me.mSHB_LS2Ctrl.OcxState = CType(resources.GetObject("mSHB_LS2Ctrl.OcxState"), System.Windows.Forms.AxHost.State)
            Me.mSHB_LS2Ctrl.Size = New System.Drawing.Size(1280, 1024)
            Me.mSHB_LS2Ctrl.TabIndex = 1
            Me.mSHB_LS2Ctrl.Visible = False
            '
            'SmithsHeimmanSensor
            '
            Me.Name = "SmithsHeimmanSensor"
            Me.Size = New System.Drawing.Size(640, 440)
            Me.MainPanel.ResumeLayout(False)
            Me.InnerPanel.ResumeLayout(False)
            CType(Me.OuterPanel, System.ComponentModel.ISupportInitialize).EndInit()
            Me.OuterPanel.ResumeLayout(False)
            CType(Me.mSHB_LS2Ctrl, System.ComponentModel.ISupportInitialize).EndInit()
            Me.ResumeLayout(False)

        End Sub

#End Region

        Private Const AspectRatio As Single = 1576.0! / 1572.0!
        Private mIsUsabilityTestMode As Boolean = True

        Private mActive As Boolean = False
        'Private configFile As String = "C:\Program Files\Cross Match Technologies\ScanCtrl\binaries\LS_ILM.cfg"
        Private ConfigurationDirectory As String = "Configurations"
        Private ConfigurationFileName As String = "LS_ILM.cfg"
        Private mConfigurationFileLocation As String
        Private mShowAllCapturedImagesAsThumbnail As Boolean

        Private Const mInitExpirationTime As Integer = 15000 'ms
        Private Const mConfigExpirationTime As Integer = 10000 'ms
        Private Const DownloadCommandExpirationTime As Integer = 5000 'ms

        Private mCaptureExpirationTime As Integer  '= 30000 'ms
        Private mCaptureCriticalTime As Integer

        Protected Delegate Function ProcessDelegate() As Object
        Protected Delegate Function CaptureDelegate(ByVal CmdGuid As Guid) As Object
        Protected Delegate Sub ConfigurationDelegate(ByVal config As SensorConfiguration)

        Private Sub CreateNew()
            MyBase.TimeoutIndicator.CriticalTime = mCaptureCriticalTime '5 * 1000
            MyBase.MainPanelAspectRatio = AspectRatio

            mConfigurationFileLocation = SmithsHeimannShared.GetSmithsHeimannConfigurationFile
            If mConfigurationFileLocation = String.Empty Then Throw New FileNotFoundException("Configuration file")

            WritableRequiresConfiguration = True
            WritableHasConfigurationClass = True

            WritableConfigurationClassname = "Mbark.Sensors.SmithsHeimmanConfiguration"
        End Sub
        Private mModality As SensorModality = SensorModality.Fingerprint
        Public Overrides ReadOnly Property Modality() As SensorModality
            Get
                Return mModality
            End Get
        End Property
        Public Overrides ReadOnly Property IsActive() As Boolean
            Get
                Return mActive
            End Get
        End Property

        Private mName As String = "Smiths Heimann"
        Public Overrides ReadOnly Property FriendlyName() As String
            Get
                Return mName
            End Get
        End Property

#Region "       Initialization         "

        Public Overrides ReadOnly Property InitializationCommandTemplate() As Threading.AsyncCommandTemplate
            Get
                Static init As AsyncCommandTemplate
                If init Is Nothing Then
                    init = New AsyncCommandTemplate
                    With init
                        .TargetMethod = CreateDelegate(GetType(ProcessDelegate), Me, "Initialize")
                        .ExpirationTime = mInitExpirationTime
                        .IgnoreUnderlyingHandleOfTargetControl = True
                    End With
                End If
                Return init
            End Get
        End Property

        Private Function Initialize() As Object
            'Initialization helper function 
            WritableRequiresRecovery = False

            Dim errorCode As Integer
            Try
                errorCode = mSHB_LS2Ctrl.ILM_MAIN_init(mConfigurationFileLocation, MainInitConstants.lcINIT_HIDE_INIDLG)
                Dim noError As Boolean = errorCode = 0
                Dim alreadyInitialized As Boolean = errorCode = IlmErrorConstants.lcILM_ERR_ALREADY_INITIALIZED
                Dim isDirty As Boolean = errorCode > 600

                If noError Or alreadyInitialized Or isDirty Then
                    If isDirty Then
                        Me.mSHBMessageCtrl.Text = "Platten is dirty or" & vbNewLine & "exposed to direct light"
                    End If
                    SensorProperties()
                    MarkAsOnline()
                Else
                    WritableRequiresRecovery = True

                    MarkAsOffline()
                    Dim ife As New InitializationFailureException
                    ife.MachineNotes = SmithsHeimannShared.ErrorCodeToString(errorCode)
                    ife.Sensor = Me
                    Throw ife
                End If

            Catch ex As Exception
                MarkAsOffline()
                Dim ife As New InitializationFailureException
                ife.MachineNotes = SmithsHeimannShared.ErrorCodeToString(errorCode)
                ife.Sensor = Me
                Throw ife
            End Try

        End Function

        Private mSensorProperties As New SensorProperties
        Private Sub SensorProperties()
            Dim manufacturer, modelname, serialnumber As String
            With mSHB_LS2Ctrl
                .ILM_MAIN_systemCheck(MainSystemCheckConstants.lcST_ILM_GET_VENDOR, mSensorProperties.Manufacturer)
                .ILM_MAIN_systemCheck(MainSystemCheckConstants.lcST_ILM_GET_PNAME, mSensorProperties.ModelName)
                mName = "Smiths Heimann " & mSensorProperties.ModelName
                .ILM_MAIN_systemCheck(MainSystemCheckConstants.lcST_ILM_GET_SERNUM, mSensorProperties.SerialNumber)
                Dim versionObj As Object
                .ILM_MAIN_getVersion(versionObj)
                Dim version As String = CType(versionObj, String())(0)
                Dim VersionArr() As String = version.Split(" ".ToCharArray)
                mSensorProperties.VendorLibraryName = VersionArr(0)
                mSensorProperties.VendorLibraryVersion = VersionArr(4)
                mSensorProperties.Modality = Modality
            End With
        End Sub
#End Region

#Region "       Configuration         "

        Private mIsConfigured As Boolean = False

        Public Overrides ReadOnly Property ConfigurationCommandTemplate() As Threading.AsyncCommandTemplate
            Get
                Static config As AsyncCommandTemplate
                If config Is Nothing Then
                    config = New AsyncCommandTemplate
                    With config
                        .TargetMethod = CreateDelegate(GetType(ConfigurationDelegate), Me, "Configuration")
                        .ExpirationTime = mConfigExpirationTime
                        .IgnoreUnderlyingHandleOfTargetControl = True
                    End With
                End If
                Return config
            End Get
        End Property

        Public Sub Configuration(ByVal config As SensorConfiguration)

            Try
                If Not mIsConfigured Then
                    Dim SHConfig As SmithsHeimmanConfiguration = DirectCast(config, SmithsHeimmanConfiguration)
                    mContrastThreshold = SHConfig.ContrastThreshold
                    mRemoveHandContrastThreshold = SHConfig.RemoveHandContrastThreshold
                    mRemoveHandTimeThreshold = SHConfig.RemoveHandTimeThreshold
                    mStabilityThreshold = SHConfig.CaptureTime
                    mCaptureExpirationTime = SHConfig.CaptureExpirationTime
                    mCaptureCriticalTime = SHConfig.CaptureCriticalTime
                    'Update Capture Command Template Capture Timeout
                    mCaptureCommandTemplate.ExpirationTime = SHConfig.CaptureExpirationTime
                    TimeoutIndicator.CriticalTime = mCaptureCriticalTime
                    mShowAllCapturedImagesAsThumbnail = SHConfig.ShowAllCapturedImagesAsThumbnail
                    mIsConfigured = True
                End If
                MyBase.MarkAsOnline()
            Catch ex As Exception
                Debugging.Break(ex)
            End Try

            
        End Sub
#End Region

#Region "       Uninitialization        "
        Public Overrides Sub Uninitialize()
            Debugging.WriteLine("SH: UNINIT")
            mSHB_LS2Ctrl.ILM_MAIN_exit()
            MyBase.Uninitialize()
        End Sub
#End Region

#Region "       Capture         "

        Private mCaptureResult As Integer
        Private mTrueCaptureResultMethod As ResultMethod
        Private mCapturingFinger As New BodyParts
        Private mliveWidth As Integer = 800
        Private mliveHeight As Integer = 800
        Private mCaptureValue As Integer = 1
        Private mDoEventMillisecond As Integer = 100
        Private mDoEventsFrequency As Integer = 10

        Private mTotalNumberofImage As Integer = 0
        Private mContrastThreshold As Integer
        Private mRemoveHandContrastThreshold As Integer
        Private mRemoveHandTimeThreshold As Integer
        Private mStabilityThreshold As Integer
        Private mMaxTriesBeforeCapture As Integer = 3

        Private mCaptureCommandTemplate As AsyncCommandTemplate
        Public Overrides ReadOnly Property CaptureCommandTemplate() As Threading.AsyncCommandTemplate
            Get

                If mCaptureCommandTemplate Is Nothing Then
                    mCaptureCommandTemplate = New AsyncCommandTemplate
                    With mCaptureCommandTemplate
                        .TargetMethod = CreateDelegate(GetType(ProcessDelegate), Me, "CaptureImage")
                        .ExpirationTime = mCaptureExpirationTime
                        .IgnoreUnderlyingHandleOfTargetControl = True
                    End With
                End If
                Return mCaptureCommandTemplate
            End Get
        End Property

        Private mUsabilityCaptureDone As Boolean
        Private CaptureStartTime As Double
        Private NoActivityGrnLightOffTime As Double

        Private Function CaptureImage() As Object
            WritablePollingWasCanceled = False

            WritableLastCaptureSuccessful = False
            WritableLatestThumbnail = Nothing
            Dim CaptureResultArray() As Object
            CaptureStartTime = DateTime.Now.TimeOfDay.TotalMilliseconds
            NoActivityGrnLightOffTime = CaptureStartTime + mCaptureExpirationTime - TimeoutIndicator.CriticalTime
            'DebuggingConsoleWriteLine(CaptureStartTime & " " & NoActivityGrnLightOffTime)

            Try
                With mSHB_LS2Ctrl
                    WritableLatestThumbnail = Nothing
                    mCaptureValue = 1
                    .ILM_BEEPER_start(BeeperConstants.lcBEEP_PATTERN_4)

                    If Not Open(mSHB_LS2Ctrl, SmithsHeimannShared.ImageType.SlapFingerprintCapture) Then
                        MarkAsOffline()
                        Dim sce As New CaptureFailureException
                        sce.Sensor = Me
                        sce.MachineNotes = "Cannot open sensor for recording"
                        Throw sce
                    End If

                    SetCurrentHandLight(TargetParts(), SignalColor.Green)

                    DisplayInstruction(Messages.Polling & vbNewLine)

                    'start AutoCapture
                    If mIsUsabilityTestMode Then
                        mUsabilityCaptureDone = False
                        CaptureResultArray = AutoCaptureForUsabilityStudy()
                    Else
                        CaptureResultArray = AutoCapture()
                    End If

                    DisplayInstruction()
                    If IsTimeout Or PollingWasCanceled Then
                        MarkasOnline()
                        If PollingWasCanceled Then
                            StopCountdownTimerNow()

                            Dim pce As New PollingCanceledException
                            pce.Sensor = Me
                            pce.MachineNotes = "Polling Canceled"
                            Throw pce
                        End If
                        If IsTimeout Then

                            Dim cte As New CaptureTimeoutException
                            cte.Sensor = Me
                            cte.MachineNotes = "Capture timeout"
                            Throw cte
                        End If
                    End If

                    If mCaptureValue = ErrorCode.PrematureCapture Then
                        MarkAsOnLine()
                        DisplayInstruction(Messages.PrematureLift)
                        Dim cfe As New CaptureFailureException
                        cfe.MachineNotes = Messages.PrematureLift
                        cfe.Sensor = Me
                        Throw cfe
                    End If

                    'if mCapture Value != 0 then throw exception
                    If mCaptureValue <> CommonErrorConstants.lcOK Then
                        MarkAsOffLine()
                        Dim cfe As New CaptureFailureException
                        cfe.Sensor = Me
                        cfe.MachineNotes = ErrorCodeToString(mCaptureValue)
                        Throw cfe
                    End If

                    If mUsabilityCaptureDone Then
                        DisplayInstruction(Messages.PleaseRemoveHand)
                        RemoveHand()
                    End If

                    DisplayInstruction()
                    'If Not imagearray Is Nothing Then
                    Dim CaptureResultList As CaptureResultCollection = CreateCaptureResultCollection(CaptureResultArray)
                    Me.LastReviewImageAcceptable = True
                    MarkAsOnline()
                    SetCurrentHandLight()

                    Return CaptureResultList
                    'End If
                End With
            Catch ex As ThreadInterruptedException
                MarkAsOnline()
                DisplayInstruction()
                If mIsUsabilityTestMode And mUsabilityCaptureDone Then
                    Dim CaptureResultList As CaptureResultCollection = CreateCaptureResultCollection(CaptureResultArray)
                    Me.LastReviewImageAcceptable = True
                    MarkAsOnline()
                    Return CaptureResultList
                End If
                MyBase.WritableIsTimeout = True


                Dim cte As New CaptureTimeoutException
                cte.Sensor = Me
                Throw cte
            Finally
                StopCountdownTimerNow()

                mSHB_LS2Ctrl.ClearResultPicture(0)
                mSHB_LS2Ctrl.ClearDisplay()
            End Try

        End Function

        Private Function CreateCaptureResultCollection(ByVal CaptureResultArray() As Object) As CaptureResultCollection
            Dim ImageArray As Object() = CType(CaptureResultArray(0), Object())
            Dim TimeStamps As Object() = CType(CaptureResultArray(1), Object())

            Dim ByteObj As Object
            Dim CaptureResultList As New CaptureResultCollection
            Dim xDpi As Single = 500
            Dim yDpi As Single = 500

            Dim FingerprintImage As Bitmap

            'save image
            With mSHB_LS2Ctrl
                For c As Integer = 0 To mTotalNumberofImage - 1
                    'ByteObj = CaptureResultArray(c)
                    ByteObj = ImageArray(c)
                    'save image for download
                    FingerprintImage = (New Bitmap(SmithsHeimannShared.FullImageToBitmap(Me, EmptyPalette, ByteObj)))
                    FingerprintImage.SetResolution(xDpi, yDpi)
                    Dim lResult As New CaptureResult
                    lResult.ImageProperties.Image = FingerprintImage
                    lResult.ImageProperties.Timestamp = CType(TimeStamps(c), DateTime)
                    lResult.SensorProperties = mSensorProperties
                    CaptureResultList.Results(c) = lResult
                Next
                If mShowAllCapturedImagesAsThumbnail Then
                    WritableLatestThumbnail = SetThumbnails(CaptureResultList)
                Else
                    WritableLatestThumbnail = FingerprintImage
                End If
                Return CaptureResultList
            End With
        End Function
        Private Function SetThumbnails(ByVal results As CaptureResultCollection) As Bitmap
            Dim Index, x, y As Integer
            Dim SpacePadding As Integer = 10

            Dim TotalCol As Integer = 3
            Dim TotalRow As Integer = CInt(Math.Ceiling(results.Count / 3))

            Dim NewBmpWidth As Integer = CInt(results(0).ImageProperties.Image.Width / 5) * 3
            Dim NewBmpHeight As Integer = CInt(results(0).ImageProperties.Image.Height / 5) * TotalRow
            Dim NewBitmap As New Bitmap(NewBmpWidth, NewBmpHeight)
            Dim g As Graphics = Graphics.FromImage(NewBitmap)


            Dim count As Integer = 0
            For row As Integer = 0 To TotalRow - 1
                For col As Integer = 0 To TotalCol - 1
                    Dim img As Image = results(count).ImageProperties.Image
                    x = (CInt(img.Width / 5) * col)
                    y = (CInt(img.Height / 5) * row)
                    g.DrawImage(img, x, y)
                    count += 1
                    If count = results.Count Then Exit For
                Next
            Next
            Return NewBitmap
        End Function

        Private Function AutoCaptureForUsabilityStudy() As Object()
            Dim rv As Integer
            Dim rect(3) As Object
            rect(0) = 0  ' left 
            rect(1) = 0   ' top 
            rect(2) = mliveWidth ' right 
            rect(3) = mliveHeight ' bottom
            Dim RawImageArray() As Object
            Dim TimeStamps() As Object
            Dim IsStartCapturing As Boolean = False
            Dim IsHandDetected As Boolean = False
            Dim StartTime As Double
            Dim HasHandActivity As Integer = 1700

            'reset the total number of image taken during capture
            mTotalNumberofImage = 0
            With mSHB_LS2Ctrl
                WritableIsTimeout = False
                Dim LowestContrast As Integer = Integer.MaxValue
                StartTime = DateTime.Now.TimeOfDay.TotalMilliseconds
                'TargetParts.BodyCategory
                Do
                    Dim CurrentContrast As Integer
                    'once capture started, don't check contrast
                    If Not IsStartCapturing Then
                        rv = GetContrast(CurrentContrast)
                        Debugging.WriteLine(CurrentContrast.ToString)
                        If rv <> 0 Then mCaptureValue = rv : Exit Do
                    End If

                    If CurrentContrast < mContrastThreshold Then

                        rv = .ILM_PALM_takePicture(True, rect)

                        ReDim Preserve RawImageArray(mTotalNumberofImage)
                        ReDim Preserve TimeStamps(mTotalNumberofImage)

                        .GetResultRawPicture(0, RawImageArray(mTotalNumberofImage))

                        TimeStamps(mTotalNumberofImage) = DateTime.UtcNow
                        mTotalNumberofImage += 1

                        'start the 5 second timing once it falls in the threshold the first time
                        If Not IsStartCapturing Then
                            IsStartCapturing = True
                            StartTime = DateTime.Now.TimeOfDay.TotalMilliseconds
                        Else 'if capture has started, then check if the timer has reach the threshold
                            If (DateTime.Now.TimeOfDay.TotalMilliseconds - StartTime) >= mStabilityThreshold Then
                                'check for premature capture
                                GetContrast(CurrentContrast)
                                If Not (CurrentContrast > mContrastThreshold) Then
                                    mUsabilityCaptureDone = True
                                Else
                                    rv = ErrorCode.PrematureCapture
                                End If
                                Exit Do
                            End If
                        End If
                        Dim timeLeft As Double = mStabilityThreshold - (DateTime.Now.TimeOfDay.TotalMilliseconds - StartTime)
                        mSHBMessageCtrl.Text = String.Format("{0:0.00}{1}seconds remain", timeLeft / 1000, vbNewLine)
                        mSHBMessageCtrl.Refresh()
                    Else
                        If IsStartCapturing Then
                            mSHBMessageCtrl.Text = Messages.Polling & vbNewLine & "."
                            IsStartCapturing = False
                        Else
                            mSHBMessageCtrl.Text = mSHBMessageCtrl.Text & "."
                        End If
                    End If
                    WaitWithDoEvents(mDoEventMillisecond, mDoEventsFrequency)
                    Dim currentTime As Double = DateTime.Now.TimeOfDay.TotalMilliseconds
                    If DateTime.Now.TimeOfDay.TotalMilliseconds >= NoActivityGrnLightOffTime Then
                        SetCurrentHandLight()
                    End If
                Loop While (Not IsTimeout) And (Not PollingWasCanceled)
                'turn off LED
                SetCurrentHandLight()
                If Not PollingWasCanceled Then
                    If IsTimeout Then
                        'return -2 if timeout
                        .ILM_BEEPER_start(BeeperConstants.lcBEEP_PATTERN_5)
                        mCaptureValue = ErrorCode.CaptureTimeout
                    Else 'return the rc value if not timeout
                        mCaptureValue = rv
                    End If
                Else ' return -1 if process cancel
                    .ILM_BEEPER_start(BeeperConstants.lcBEEP_PATTERN_4)
                    mCaptureValue = ErrorCode.CaptureCancel
                End If
            End With

            If Not RawImageArray Is Nothing AndAlso Not TimeStamps Is Nothing Then
                Dim obj As Object() = {RawImageArray, TimeStamps}
                Return obj
            Else
                Return Nothing
            End If
        End Function
        Private Function GetContrast(ByRef CurrentContrast As Integer) As Integer
            Dim rv As Integer
            With mSHB_LS2Ctrl
                rv = .ILM_PALM_optimizeContrast(OptimizeContrastConstants.lcOPT_CONTRAST)
                If rv <> 0 Then Return rv

                rv = .ILM_PALM_getContrast(GetContrastModeConstants.lcCONTRAST_ACTUAL, CurrentContrast)
                If rv <> 0 Then Return rv
            End With
        End Function
        Private QuitRemoveHandFunction As Double = 2000
        Private Sub RemoveHand()
            Dim CurrentContrast As Integer
            Dim rv As Integer
            Dim StartTime As Double = DateTime.Now.TimeOfDay.TotalMilliseconds

            With mSHB_LS2Ctrl
                Do
                    rv = GetContrast(CurrentContrast)
                    If rv <> 0 Then mCaptureValue = rv : Exit Do
                    '  if hand is detected then flash red
                    If (DateTime.Now.TimeOfDay.TotalMilliseconds - StartTime) >= mRemoveHandTimeThreshold Then
                        mSHB_LS2Ctrl.ILM_BEEPER_start(BeeperConstants.lcBEEP_PATTERN_5)
                        SetCurrentHandLight(TargetParts(), SignalColor.Red)
                    End If
                    WaitWithDoEvents(mDoEventMillisecond, mDoEventsFrequency)
                    If (DateTime.Now.TimeOfDay.TotalMilliseconds - CaptureStartTime) >= (mCaptureExpirationTime - QuitRemoveHandFunction) Then
                        Exit Do
                    End If
                Loop While (CurrentContrast <= mRemoveHandContrastThreshold AndAlso Not IsTimeout)

                SetCurrentHandLight()
                'Must stop the CounterTimer soon after Capture returns from the reader
                StopCountdownTimerNow()
            End With

        End Sub

        Private Function AutoCapture() As Object()
            Dim rc As Integer
            Dim rect(3) As Object
            rect(0) = 0  ' left 
            rect(1) = 0   ' top 
            rect(2) = mliveWidth ' right 
            rect(3) = mliveHeight ' bottom
            Dim RawObj As Object
            Dim done As Boolean = False
            Dim RawImageArray() As Object
            Dim TimeStamps() As Object
            With mSHB_LS2Ctrl
                WritableIsTimeOut = False
                Dim LowestContrast As Integer = Integer.MaxValue
                Dim SameContrast As Integer = 0
                mTotalNumberofImage = 0

                Do
                    Dim CurrentContrast As Integer
                    rc = .ILM_PALM_optimizeContrast(OptimizeContrastConstants.lcOPT_CONTRAST)
                    If rc <> 0 Then mCaptureValue = rc : Exit Do

                    rc = .ILM_PALM_getContrast(GetContrastModeConstants.lcCONTRAST_ACTUAL, CurrentContrast)
                    If rc <> 0 Then mCaptureValue = rc : Exit Do
                    If SameContrast > 0 Then
                        mSHBMessageCtrl.Text = "Polling" & vbNewLine & (4 - SameContrast)
                    Else
                        mSHBMessageCtrl.Text = mSHBMessageCtrl.Text & "."
                    End If
                    ' if contrast number is between the range continously (3 times), then capture the image
                    If CurrentContrast < mContrastThreshold Then
                        SameContrast += 1
                        If SameContrast = mMaxTriesBeforeCapture Then
                            rc = .ILM_PALM_takePicture(True, rect)
                            ReDim Preserve RawImageArray(mTotalNumberofImage)
                            ReDim Preserve TimeStamps(mTotalNumberofImage)
                            .GetResultRawPicture(0, RawImageArray(mTotalNumberofImage))
                            TimeStamps(mTotalNumberofImage) = DateTime.UtcNow
                            mTotalNumberofImage += 1
                        End If
                    Else
                        SameContrast = 0
                    End If
                    WaitWithDoEvents(mDoEventMillisecond, mDoEventsFrequency)
                Loop While (Not IsTimeout) And (Not PollingWasCanceled) And (SameContrast <> mMaxTriesBeforeCapture)

                'Must stop the CounterTimer soon after Capture returns from the reader
                StopCountdownTimerNow()

                If Not PollingWasCanceled Then
                    If IsTimeout Then
                        'return -2 if timeout
                        .ILM_BEEPER_start(BeeperConstants.lcBEEP_PATTERN_5)
                        mCaptureValue = ErrorCode.CaptureTimeout
                    Else 'return the rc value if not timeout
                        mCaptureValue = rc
                    End If
                Else ' return -1 if process cancel
                    .ILM_BEEPER_start(BeeperConstants.lcBEEP_PATTERN_4)
                    mCaptureValue = ErrorCode.CaptureCancel
                End If
            End With
            Close(mSHB_LS2Ctrl, SmithsHeimannShared.ImageType.SlapFingerprintCapture)
            If Not RawImageArray Is Nothing AndAlso Not TimeStamps Is Nothing Then
                Dim obj As Object() = {RawImageArray, TimeStamps}
                Return obj
            Else
                Return Nothing
            End If

        End Function

        '        Public Function FullImageToBitmap(ByVal fullImageAsObject As Object) As Bitmap
        '            If EmptyPalette Is Nothing Then InitEmptyPalette()
        '
        '            Dim fullImage As Array = CType(fullImageAsObject, Array)
        '            Try
        '                Dim maxRow As Integer = fullImage.GetUpperBound(0)
        '                Dim maxColumn As Integer = fullImage.GetUpperBound(1)
        '                Dim width As Integer = maxColumn + 1
        '                Dim height As Integer = maxRow + 1
        '
        '                Dim imageAsBytes((maxColumn + 1) * (maxRow + 1) - 1) As Byte
        '                System.Buffer.BlockCopy(fullImage, 0, imageAsBytes, 0, fullImage.Length)
        '
        '                Dim bmp As Bitmap = ConvertBytesAsObjectToBitmap(imageAsBytes, width, height)
        '                bmp.RotateFlip(RotateFlipType.Rotate90FlipX)
        '                Return bmp
        '            Catch ex As Exception
        '                Debugger.Break()
        '            End Try
        '        End Function

        Private Function getVersionNumber() As String
            Dim versionObj As Object
            mSHB_LS2Ctrl.ILM_MAIN_getVersion(versionObj)
            Dim VersionInfoList() As String = CType(versionObj, String())
            Dim delimiter() As Char = ",".ToCharArray
            Dim list() As String = VersionInfoList(0).Split(delimiter)
            'remove the space at the beginning of the string
            Return list(1).Remove(0, 1)
        End Function

        Private Sub DisplayInstruction(Optional ByVal message As String = Nothing)
            mSHBMessageCtrl.Text = message
            Refresh()
        End Sub

        Private Sub SetCurrentHandLight(Optional ByVal Hand As BodyParts = Nothing, Optional ByVal SignalColor As SignalColor = Nothing)
            Dim mode As SignalLEDConstants = SignalLEDConstants.Light_Off
            If Not Hand Is Nothing Then
                If BodyParts.ForLeftSlapTask.ContainsSet(Hand) Then
                    If SignalColor = SignalColor.Green Then mode = SignalLEDConstants.Left_Green
                    If SignalColor = SignalColor.Red Then mode = SignalLEDConstants.Left_Red
                ElseIf BodyParts.ForRightSlapTask.ContainsSet(Hand) Then
                    If SignalColor = SignalColor.Green Then mode = SignalLEDConstants.Right_Green
                    If SignalColor = SignalColor.Red Then mode = SignalLEDConstants.Right_Red
                ElseIf BodyParts.ForThumbsSlapTask.ContainsSet(Hand) Then
                    If SignalColor = SignalColor.Green Then mode = SignalLEDConstants.Thumbs_Green
                    If SignalColor = SignalColor.Red Then mode = SignalLEDConstants.Thumbs_Red
                End If
            End If
            Dim rc As Integer = mSHB_LS2Ctrl.ILM_SignalLED_activate(mode)
        End Sub
#End Region
        Enum SignalColor
            Green
            Red
        End Enum
        Enum SignalLEDConstants
            Light_Off = SigLedConstants.lcSIGLED_3L_OFF
            Left_Green = SigLedConstants.lcSIGLED_3L_LGNP1
            Left_Red = SigLedConstants.lcSIGLED_3L_LRDP1
            Right_Green = SigLedConstants.lcSIGLED_3L_RGNP1
            Right_Red = SigLedConstants.lcSIGLED_3L_RRDP1
            Thumbs_Green = SigLedConstants.lcSIGLED_3L_MGNP0
            Thumbs_Red = SigLedConstants.lcSIGLED_3L_MRDP0
        End Enum
#Region "       Download      "
        Protected Overrides Function CreateDownloadCommand(ByVal id As Guid) As AsyncCommand
            Dim DownloadCommand As New AsyncCommand(DownloadCommandTemplate)
            DownloadCommand.TargetMethodArg(0) = id
            Return DownloadCommand
        End Function

        Public Overrides ReadOnly Property DownloadCommandTemplate() As Threading.AsyncCommandTemplate
            Get
                Static download As AsyncCommandTemplate
                If download Is Nothing Then
                    download = New AsyncCommandTemplate
                    With download
                        .TargetMethod = CreateDelegate(GetType(DownloadDelegate), Me, "DownloadImage")
                        Dim args As Object() = {Guid.Empty}
                        .TargetMethodArgs(args)
                        .ExpirationTime = 5000 ' 3mins
                        .IgnoreUnderlyingHandleOfTargetControl = True
                    End With
                End If
                Return download
            End Get
        End Property
        Private Delegate Function DownloadDelegate(ByVal id As Guid) As Object
        Private Function DownloadImage(ByVal id As Guid) As Object
        End Function
#End Region
        Private Sub CancelSensorButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles CancelSensorButton.Click
            Writablepollingwascanceled = True
        End Sub

        Private Enum ErrorCode
            Sucess = 0
            CaptureTimeout = -2
            CaptureCancel = -1
            PrematureCapture = -3
        End Enum

        Protected Overrides Sub OnLoad(ByVal e As EventArgs)
            Me.mSHBMessageCtrl.Font = UI.GlobalUISettings.Defaults.Fonts.LargeBold
        End Sub

    End Class

    <Serializable()> Public Class SmithsHeimmanConfiguration
        Inherits SensorConfiguration

        Public BaseContrast As Double = 1400
        Public WhitePercentage As Double = 70
        Public RemoveHandContrastThreshold As Integer = 1600 'contrast number
        Public RemoveHandTimeThreshold As Integer = 3000
        Public CaptureTime As Integer = 5000
        Public CaptureExpirationTime As Integer = 30000
        Public CaptureCriticalTime As Integer = 5000
        Public ShowAllCapturedImagesAsThumbnail As Boolean = True

        Public Overrides Function Clone() As Object
            Dim newConfiguration As New SmithsHeimmanConfiguration
            With newConfiguration
                .BaseContrast = BaseContrast
                .WhitePercentage = WhitePercentage
                .RemoveHandContrastThreshold = RemoveHandContrastThreshold
                .RemoveHandTimeThreshold = RemoveHandTimeThreshold
                .CaptureTime = CaptureTime
                .CaptureExpirationTime = CaptureExpirationTime
                .CaptureCriticalTime = CaptureCriticalTime
                .ShowAllCapturedImagesAsThumbnail = ShowAllCapturedImagesAsThumbnail
            End With
            Return newConfiguration
        End Function

        Public ReadOnly Property ContrastThreshold() As Integer
            Get
                Return CInt(BaseContrast * (WhitePercentage / 100))
            End Get
        End Property





    End Class
End Namespace
