/// <summary>
        /// Create an unknown state list for a named reader
        /// </summary>
        /// <remarks>
        /// Sets the currentState and eventState to 'Unaware' for the reader
        /// </remarks>
        /// <param name="readerName">Reader name for which to create initial state</param>
        /// <returns>List of unknown reader states</returns>
        private SmartcardInterop.ScardReaderState CreatePendingReaderState(string readerName)
        {
            var state = new SmartcardInterop.ScardReaderState
            {
                reader       = readerName,
                currentState = SmartcardInterop.State.Unaware,
                eventState   = 0,
                atrLength    = 0
            };

            return(state);
        }
        /// <summary>
        /// Call the card removed delegate for each changed reader
        /// </summary>
        /// <param name="state">State class containing the smartcard reader name</param>
        private void FireCardRemovedEvent(SmartcardInterop.ScardReaderState state)
        {
            if (this.DebounceState(state.reader, CardEvent.Remove))
            {
                return;
            }

            var args = new SmartcardEventArgs(null, state.reader);

            this.logger.DebugFormat("Firing card removed event for reader {0}", state.reader);
            this.OnCardRemoved?.Invoke(this, args);
        }
        /// <summary>
        /// Call the card detected delegate for each changed reader
        /// </summary>
        /// <param name="state">State class containing the smartcard reader name</param>
        private void FireCardPresentEvent(SmartcardInterop.ScardReaderState state)
        {
            if (this.DebounceState(state.reader, CardEvent.Insert))
            {
                return;
            }

            var cardname = this.FindCardWithAtr(state.atr);
            var scard    = new Smartcard(state.reader, cardname);
            var args     = new SmartcardEventArgs(scard, state.reader);

            this.logger.DebugFormat("Firing card insert event for reader {0}, card {1}", state.reader, cardname);
            this.OnCardInserted?.Invoke(this, args);
        }
        /// <summary>
        /// Monitor for smartcard change events and fire events on detected changes
        /// </summary>
        private void WaitForReaderStateChange()
        {
            var awaitNewReader = new SmartcardInterop.ScardReaderState
            {
                reader       = NotificationReader,
                currentState = 0,
                eventState   = 0,
                atrLength    = 0
            };

            this.currentState.Add(awaitNewReader);

            var i      = 0;
            var result = 0;

            while (!this.cancelToken.IsCancellationRequested)
            {
                try
                {
                    i++;
                    var scardstate = this.currentState.ToArray();

                    this.logger.DebugFormat("StateChange - start: {0}; last status = 0x{1}; statecount = {2}", i, result.ToString("X"), scardstate.Length);

                    // We have a 30 second timeout rather than infinite. As of Windows 8, the smartcard
                    // service shuts down if no readers attached and more than a couple of minutes have
                    // elapsed since the last SCard API call. So a 30 second timeout will keep the service
                    // alive and mean we're not reseting context (and thus restarting smartcard service)
                    // every couple of minutes.
                    result = SmartcardInterop.SCardGetStatusChange(this.readerContext, 30000, scardstate, scardstate.Length);
                    if (this.cancelToken.IsCancellationRequested || result == SmartcardException.SCardECancelled)
                    {
                        this.logger.Debug("Cancellation requested");
                        break;
                    }

                    if (result == SmartcardException.SCardETimeout)
                    {
                        continue;
                    }

                    this.logger.Debug("StateChange - result: 0x" + result.ToString("X"));
                    var scardstatelist = scardstate.ToList();

                    // If the service has stopped, then we need to flag all existing cards as removed
                    if (this.HandleStoppedService(scardstatelist, result))
                    {
                        // Need to reset the smartcard context
                        this.ResetContext();
                        this.currentState.Add(awaitNewReader);
                        continue;
                    }

                    // All other errors, throw an exception
                    if (result != SmartcardException.SCardSuccess)
                    {
                        this.logger.DebugFormat("Failed to get smartcard state: error 0x{0}", result);
                        throw new SmartcardException(result);
                    }

                    // Now deal with the actual smartcard changes
                    var scardChanges = scardstatelist.Where(x => (x.eventState & SmartcardInterop.State.Changed) != 0).ToList();
                    if (scardChanges.Count == 0)
                    {
                        continue;
                    }

                    this.DumpState(scardChanges);

                    this.HandleRemovedReaders(scardChanges, result);
                    this.HandleRemovedCards(scardChanges, result);
                    this.HandleInsertedCards(ref scardChanges, result);

                    this.SaveState(scardChanges);
                }
                catch (SmartcardException ex)
                {
                    if (ex.Status == SmartcardException.SCardEServiceStopped || ex.Status == SmartcardException.SCardENoService)
                    {
                        this.logger.Debug("Smartcard service stopped; resetting context");
                        this.ResetContext();
                        this.currentState.Add(awaitNewReader);
                    }
                    else
                    {
                        throw;
                    }
                }
            }

            this.logger.Debug("Monitoring stopped.");
        }