Wait for card insertion and returns a card service.

def waitforcard(self):
        """Wait for card insertion and returns a card service."""
        AbstractCardRequest.waitforcard(self)
        cardfound = False

        # for non infinite timeout, a timer will signal
        # the end of the time-out by setting the evt event
        evt = threading.Event()
        if INFINITE == self.timeout:
            timertimeout = 1
        else:
            timertimeout = self.timeout
        timer = threading.Timer(
            timertimeout, signalEvent, [evt, INFINITE == self.timeout])

        # create a dictionary entry for new readers
        readerstates = {}
        readernames = self.getReaderNames()
        for reader in readernames:
            if not reader in readerstates:
                readerstates[reader] = (reader, SCARD_STATE_UNAWARE)

        # remove dictionary entry for readers that disappeared
        for oldreader in list(readerstates.keys()):
            if oldreader not in readernames:
                del readerstates[oldreader]

        # call SCardGetStatusChange only if we have some readers
        if {} != readerstates:
            hresult, newstates = SCardGetStatusChange(
                self.hcontext, 0, list(readerstates.values()))
        else:
            hresult = 0
            newstates = []

        # we can expect normally time-outs or reader
        # disappearing just before the call
        # otherwise, raise execption on error
        if 0 != hresult and \
            SCARD_E_TIMEOUT != hresult and \
            SCARD_E_UNKNOWN_READER != hresult:
                raise CardRequestException(
                    'Failed to SCardGetStatusChange ' + \
                    SCardGetErrorMessage(hresult))

        # in case of timeout or reader disappearing,
        # the content of the states is useless
        # in which case we clear the changed bit
        if SCARD_E_TIMEOUT == hresult or SCARD_E_UNKNOWN_READER == hresult:
            for state in newstates:
                state[1] = state[1] & (0xFFFFFFFF ^ SCARD_STATE_CHANGED)

        # update readerstate
        for state in newstates:
            readername, eventstate, atr = state
            readerstates[readername] = (readername, eventstate)

        # if a new card is not requested, just return the first available
        if not self.newcardonly:
            for state in newstates:
                readername, eventstate, atr = state
                if eventstate & SCARD_STATE_PRESENT:
                    reader = PCSCReader(readername)
                    if self.cardType.matches(atr, reader):
                        if self.cardServiceClass.supports('dummy'):
                            cardfound = True
                            return self.cardServiceClass(
                                    reader.createConnection())

        timerstarted = False
        while not evt.isSet() and not cardfound:

            if not timerstarted:
                timerstarted = True
                timer.start()

            time.sleep(self.pollinginterval)

            # create a dictionary entry for new readers
            readernames = self.getReaderNames()
            for reader in readernames:
                if not reader in readerstates:
                    readerstates[reader] = (reader, SCARD_STATE_UNAWARE)

            # remove dictionary entry for readers that disappeared
            for oldreader in list(readerstates.keys()):
                if oldreader not in readernames:
                    del readerstates[oldreader]

            # wait for card insertion
            if {} != readerstates:
                hresult, newstates = SCardGetStatusChange(
                    self.hcontext, 0, list(readerstates.values()))
            else:
                hresult = SCARD_E_TIMEOUT
                newstates = []

            # time-out
            if SCARD_E_TIMEOUT == hresult:
                if evt.isSet():
                    raise CardRequestTimeoutException()

            # reader vanished before or during the call
            elif SCARD_E_UNKNOWN_READER == hresult:
                pass

            # some error happened
            elif 0 != hresult:
                timer.cancel()
                raise CardRequestException(
                    'Failed to get status change ' + \
                    SCardGetErrorMessage(hresult))

            # something changed!
            else:

                # check if we have to return a match, i.e.
                # if no new card in inserted and there is a card found
                # or if a new card is requested, and there is a change+present
                for state in newstates:
                    readername, eventstate, atr = state
                    r, oldstate = readerstates[readername]

                    # the status can change on a card already inserted, e.g.
                    # unpowered, in use, ...
                    # if a new card is requested, clear the state changed bit
                    # if the card was already inserted and is still inserted
                    if self.newcardonly:
                        if oldstate & SCARD_STATE_PRESENT and \
                            eventstate & \
                                (SCARD_STATE_CHANGED | SCARD_STATE_PRESENT):
                            eventstate = eventstate & \
                                (0xFFFFFFFF ^ SCARD_STATE_CHANGED)

                    if (self.newcardonly and \
                            eventstate & SCARD_STATE_PRESENT and \
                            eventstate & SCARD_STATE_CHANGED) or \
                        (not self.newcardonly and \
                         eventstate & SCARD_STATE_PRESENT):
                        reader = PCSCReader(readername)
                        if self.cardType.matches(atr, reader):
                            if self.cardServiceClass.supports('dummy'):
                                cardfound = True
                                timer.cancel()
                                return self.cardServiceClass(
                                        reader.createConnection())

                    # update state dictionary
                    readerstates[readername] = (readername, eventstate)

            if evt.isSet():
                raise CardRequestTimeoutException()