# Synthetic children provider example for class MaskedData
# to use me:
# command script import ./example.py --allow-reload
# type synthetic add MaskedData --python-class example.MaskedData_SyntheticChildrenProvider
class MaskedData_SyntheticChildrenProvider:
	def __init__(self, valobj, dict):
		self.valobj = valobj # remember the SBValue since you will not have another chance to get it :-)

	def num_children(self):
		# you could perform calculations involving the SBValue and/or its children to determine this value
		# here, we have an hardcoded value - but since you have stored the SBValue you could use it to
		# help figure out the correct thing to return here. if you return a number N, you should be prepared to
		# answer questions about N children
		return 4

	def has_children(self):
		# we simply say True here because we know we have 4 children
		# in general, you want to make this calculation as simple as possible
		# and return True if in doubt (you can always return num_children == 0 later)
		return True

	def get_child_index(self,name): 
		# given a name, return its index
		# you can return None if you don't know the answer for a given name
		if name == "value":
			return 0
		# here, we are using a reserved C++ keyword as a child name - we could not do that in the source code
		# but we are free to use the names we like best in the synthetic children provider class
		# we are also not respecting the order of declaration in the C++ class itself - as long as
		# we are consistent, we can do that freely
		if name == "operator":
			return 1
		if name == "mask":
			return 2
		# this member does not exist in the original class - we will compute its value and show it to the user
		# when returning synthetic children, there is no need to only stick to what already exists in memory
		if name == "apply()":
			return 3
		return None # no clue, just say none

	def get_child_at_index(self,index):
		# precautionary measures
		if index < 0:
			return None
		if index > self.num_children():
			return None
		if self.valobj.IsValid() == False:
			return None
		if index == 0:
			return self.valobj.GetChildMemberWithName("value")
		if index == 1:
			# fetch the value of the operator
			op_chosen = self.valobj.GetChildMemberWithName("oper").GetValueAsUnsigned()
			# if it is a known value, return a descriptive string for it
			# we are not doing this in the most efficient possible way, but the code is very readable
			# and easy to maintain - if you change the values on the C++ side, the same changes must be made here
			if op_chosen == 0:
				return self.valobj.CreateValueFromExpression("operator",'(const char*)"none"')
			elif op_chosen == 1:
				return self.valobj.CreateValueFromExpression("operator",'(const char*)"AND"')
			elif op_chosen == 2:
				return self.valobj.CreateValueFromExpression("operator",'(const char*)"OR"')
			elif op_chosen == 3:
				return self.valobj.CreateValueFromExpression("operator",'(const char*)"XOR"')
			elif op_chosen == 4:
				return self.valobj.CreateValueFromExpression("operator",'(const char*)"NAND"')
			elif op_chosen == 5:
				return self.valobj.CreateValueFromExpression("operator",'(const char*)"NOR"')
			else:
				return self.valobj.CreateValueFromExpression("operator",'(const char*)"unknown"') # something else
		if index == 2:
			return self.valobj.GetChildMemberWithName("mask")
		if index == 3:
			# for this, we must fetch all the other elements
			# in an efficient implementation, we would be caching this data for efficiency
			value = self.valobj.GetChildMemberWithName("value").GetValueAsUnsigned()
			operator = self.valobj.GetChildMemberWithName("oper").GetValueAsUnsigned()
			mask = self.valobj.GetChildMemberWithName("mask").GetValueAsUnsigned()
			# compute the masked value according to the operator
			if operator == 1:
				value = value & mask
			elif operator == 2:
				value = value | mask
			elif operator == 3:
				value = value ^ mask
			elif operator == 4:
				value = ~(value & mask)
			elif operator == 5:
				value = ~(value | mask)
			else:
				pass
			value &= 0xFFFFFFFF # make sure Python does not extend our values to 64-bits
			# return it - again, not the most efficient possible way. we should actually be pushing the computed value
			# into an SBData, and using the SBData to create an SBValue - this has the advantage of readability
			return self.valobj.CreateValueFromExpression("apply()",'(uint32_t)(' + str(value) + ')')

	def update(self):
		# we do not do anything special in update - but this would be the right place to lookup
		# the data we use in get_child_at_index and cache it
		pass
