import logging

logger = logging.getLogger("packetracer")
from_bytes = int.from_bytes


def _get_der_tlv(der_bts):
	off = 0
	tagstart = off
	#logger.debug("tagstart: %d" % tagstart)
	# is_hightag = False
	is_primitive = (der_bts[off] & 0x20) == 0
	#logger.debug("primitive: %r" % is_primitive)

	# high tag number form
	if (der_bts[off] & 0x1F) == 0x1F:
		#logger.debug("got high tag form")
		# is_hightag = True
		off += 1

		while (der_bts[off] & 0x80) != 0:
			off += 1
	off += 1

	lenstart = off
	#logger.debug("lenstart: %d" % lenstart)
	vlen = der_bts[off]
	is_lenshort = (vlen & 0x80) == 0

	if not is_lenshort:
		len_octets = vlen & 0x7F
		lenbts = der_bts[lenstart + 1: lenstart + 1 + len_octets]
		vlen = from_bytes(lenbts, byteorder="big", signed=False)
		#logger.debug("length longform, bytes: %r (%d) = %d" % (lenbts, len_octets, vlen))
		off += len_octets
	off += 1
	valuestart = off
	return lenstart - tagstart, valuestart - lenstart, vlen, is_primitive


def decode_der(der_bts, result=None, extract_cb=None, _firstrun=True, _level=0):
	off = 0
	end = len(der_bts)

	if _firstrun:
		#logger.debug(">>> first run")
		try:
			taglen, lenlen, vlen, prim = _get_der_tlv(der_bts)
		except IndexError:
			result.append(None)
			return
		end = taglen + lenlen + vlen

	while off < end:
		try:
			taglen, lenlen, vlen, prim = _get_der_tlv(der_bts[off:])
		except IndexError:
			result.append(None)
			break

		value = der_bts[off + taglen + lenlen: off + taglen + lenlen + vlen]

		if not prim:
			result_tmp = []
			#logger.debug("sub calling: %d %d %d %d %r" % (off, taglen, lenlen, vlen, _firstrun))
			try:
				decode_der(value, result=result_tmp, extract_cb=extract_cb, _firstrun=False, _level=_level + 1)
			except:
				# None indicates decoding error
				result_tmp = [None]
			value = result_tmp

		result.append([
			der_bts[off: off + taglen],
			der_bts[off + taglen: off + taglen + lenlen],
			value]
		)
		off += (taglen + lenlen + vlen)

	try:
		extract_cb(result)
	except:
		#logger.exception(ex)
		pass
