"""
Diameter Base Protocol - RFC 3588
http://tools.ietf.org/html/rfc3588
"""
import logging

from packetracer import packetracer, triggerlist

logger = logging.getLogger("packetracer")

# Request/Answer Command Codes
ABORT_SESSION		= 274
ACCOUTING		= 271
CAPABILITIES_EXCHANGE	= 257
DEVICE_WATCHDOG		= 280
DISCONNECT_PEER		= 282
RE_AUTH			= 258
SESSION_TERMINATION	= 275


class Diameter(packetracer.Packet):
	__hdr__ = (
		("v", "B", 1),
		("len", "3s", b"\x00" * 3),
		("flags", "B", 0),
		("cmd", "3s", b"\x00" * 3),
		("app_id", "I", 0),
		("hop_id", "I", 0),
		("end_id", "I", 0),
		("avps", None, triggerlist.TriggerList)
	)

	def __get_r(self):
		return (self.flags >> 7) & 0x1

	def __set_r(self, r):
		self.flags = (self.flags & ~0x80) | ((r & 0x1) << 7)
	request_flag = property(__get_r, __set_r)

	def __get_p(self):
		return (self.flags >> 6) & 0x1

	def __set_p(self, p):
		self.flags = (self.flags & ~0x40) | ((p & 0x1) << 6)
	proxiable_flag = property(__get_p, __set_p)

	def __get_e(self):
		return (self.flags >> 5) & 0x1

	def __set_e(self, e):
		self.flags = (self.flags & ~0x20) | ((e & 0x1) << 5)
	error_flag = property(__get_e, __set_e)

	def __get_t(self):
		return (self.flags >> 4) & 0x1

	def __set_t(self, t):
		self.flags = (self.flags & ~0x10) | ((t & 0x1) << 4)
	retransmit_flag = property(__get_t, __set_t)

	def _dissect(self, buf):
		self._init_triggerlist("avps", buf[20:], self._parse_avps)
		return len(buf)

	def _parse_avps(self, buf):
		off = 0
		avps = []
		buflen = len(buf)

		# parse AVPs
		while off < buflen:
			avplen = int.from_bytes(buf[off + 5: off + 8], "big")
			# REAL length of AVP is multiple of 4 Bytes
			mod_len = avplen % 4
			if mod_len != 0:
				avplen += 4 - mod_len
			avp = AVP(buf[off: off + avplen])
			avps.append(avp)
			off += avplen
		return avps


class AVP(packetracer.Packet):
	__hdr__ = (
		("code", "I", 0),
		("flags", "B", 0),
		("len", "3s", b""),
	)

	def __get_v(self):
		return (self.flags >> 7) & 0x1

	def __set_v(self, v):
		self.flags = (self.flags & ~0x80) | ((v & 0x1) << 7)
	vendor_flag = property(__get_v, __set_v)

	def __get_m(self):
		return (self.flags >> 6) & 0x1

	def __set_m(self, m):
		self.flags = (self.flags & ~0x40) | ((m & 0x1) << 6)
	mandatory_flag = property(__get_m, __set_m)

	def __get_p(self):
		return (self.flags >> 5) & 0x1

	def __set_p(self, p):
		self.flags = (self.flags & ~0x20) | ((p & 0x1) << 5)
	protected_flag = property(__get_p, __set_p)
