# Path: yubioath/core/exc.py
# class CardError(Exception):
# 
#     def __init__(self, status, message=''):
#         super(CardError, self).__init__('Card Error (%04x): %s' %
#                                         (status, message))
#         self.status = status
# 
# class InvalidSlotError(Exception):
# 
#     def __init__(self):
#         super(InvalidSlotError, self).__init__(
#             'The selected slot does not contain a valid OATH credential.')
# 
# class NeedsTouchError(Exception):
# 
#     def __init__(self):
#         super(NeedsTouchError, self).__init__(
#             'The selected slot needs touch to be used.')
# 
# Path: yubioath/core/utils.py
# def format_code(code, digits=6):
#     return ('%%0%dd' % digits) % (code % 10 ** digits)
# 
# def parse_full(resp):
#     offs = byte2int(resp[-1]) & 0xf
#     return parse_truncated(resp[offs:offs+4])
# 
# def time_challenge(t=None):
#     return struct.pack('>q', int((t or time.time())/30))


from .exc import CardError, InvalidSlotError, NeedsTouchError
from .utils import (format_code, parse_full, time_challenge)
class LegacyOathCcid(object):

    """
    CCID interface to a legacy OATH-enabled YubiKey.
    """

    def __init__(self, device):
        self._device = device

        self._select()

    def _send(self, ins, data='', p1=0, p2=0, expected=0x9000):
        resp, status = self._device.send_apdu(0, ins, p1, p2, data)
        if expected != status:
            raise CardError(status)
        return resp

    def _select(self):
        self._send(0xa4, YKLEGACY_AID, p1=0x04)

    def calculate(self, slot, digits=6, timestamp=None, mayblock=0):
        data = time_challenge(timestamp)
        try:
            resp = self._send(INS_CHALRESP, data, p1=SLOTS[slot])
        except CardError as e:
            if e.status == 0x6985:
                raise NeedsTouchError()
            raise
        if not resp:
            raise InvalidSlotError()

# Path: yubioath/core/exc.py
# class CardError(Exception):
# 
#     def __init__(self, status, message=''):
#         super(CardError, self).__init__('Card Error (%04x): %s' %
#                                         (status, message))
#         self.status = status
# 
# class InvalidSlotError(Exception):
# 
#     def __init__(self):
#         super(InvalidSlotError, self).__init__(
#             'The selected slot does not contain a valid OATH credential.')
# 
# class NeedsTouchError(Exception):
# 
#     def __init__(self):
#         super(NeedsTouchError, self).__init__(
#             'The selected slot needs touch to be used.')
# 
# Path: yubioath/core/utils.py
# def format_code(code, digits=6):
#     return ('%%0%dd' % digits) % (code % 10 ** digits)
# 
# def parse_full(resp):
#     offs = byte2int(resp[-1]) & 0xf
#     return parse_truncated(resp[offs:offs+4])
# 
# def time_challenge(t=None):
#     return struct.pack('>q', int((t or time.time())/30))


# Path: yubioath/core/legacy_ccid.py
from .exc import CardError, InvalidSlotError, NeedsTouchError
from .utils import (format_code, parse_full, time_challenge)

class LegacyOathCcid(object):

    """
    CCID interface to a legacy OATH-enabled YubiKey.
    """

    def __init__(self, device):
        self._device = device

        self._select()

    def _send(self, ins, data='', p1=0, p2=0, expected=0x9000):
        resp, status = self._device.send_apdu(0, ins, p1, p2, data)
        if expected != status:
            raise CardError(status)
        return resp

    def _select(self):
        self._send(0xa4, YKLEGACY_AID, p1=0x04)

    def calculate(self, slot, digits=6, timestamp=None, mayblock=0):
        data = time_challenge(timestamp)
        try:
            resp = self._send(INS_CHALRESP, data, p1=SLOTS[slot])
        except CardError as e:
            if e.status == 0x6985:
                raise NeedsTouchError()
            raise
        if not resp:
            raise InvalidSlotError()

        return format_code(parse_full(resp), digits)