def updateLeafSet(Z, X):
	# Adding Z to the leafSet
	if(isEligibleUpLeaf(Z, X)):
		X.upLeafSet.append(Z)
	elif(isEligibleDownLeaf(Z, X)):
		X.downLeafSet.append(Z)
		
	# Taking leafSet from Z
	t_leafSet = Z.downLeafSet + Z.upLeafSet
	for t_leaf in t_leafSet:
		if(len(X.downLeafSet) < lowLeafSetLen and isEligibleDownLeaf(t_leaf, X)):
				X.downLeafSet.append(t_leaf)
		if(len(X.upLeafSet) < upLeafSetLen and isEligibleUpLeaf(t_leaf, X)):
				X.upLeafSet.append(t_leaf)
def updateOthers(X):
	t_nodes = X.neighborhoodSet + X.upLeafSet + X.downLeafSet
	
	for routeTableRow in X.routingTable:
		for routeTableEntry in routeTableRow:
			if(isNodeAlive(routeTableEntry)):
				t_nodes.append(routeTableEntry)
				
	t_nodes = list(set(t_nodes))

	# Updating neighborhoodSet of others
	for otherNode in t_nodes:
		# adding X into the neighborhoodSet of otherNode if not enough neighbors
		if(len(otherNode.neighborhoodSet) < neighborSetLen):
			otherNode.neighborhoodSet.append(X)
			break
		# replacing neighbor of otherNode with X if more closer
		for neighborOfOtherNode in otherNode.neighborhoodSet:
			if(getRelativeDistance(neighborOfOtherNode, otherNode) > getRelativeDistance(X, otherNode)):
				otherNode.neighborhoodSet.remove(neighborOfOtherNode)
				otherNode.neighborhoodSet.append(X)
				break


	# updating leafs of others
	for otherNode in t_nodes:
		# adding X into the leafSet of leaf if not enough leafs
		if(len(otherNode.downLeafSet) < lowLeafSetLen and isEligibleDownLeaf(X, otherNode)):
				otherNode.downLeafSet.append(X)
				break
		elif(len(otherNode.upLeafSet) < upLeafSetLen and isEligibleUpLeaf(X, otherNode)):
				otherNode.upLeafSet.append(X)
				break
		
		# replacing leaf of otherNode with X if more numerically closer
		t_leafOfOtherNodeSet = otherNode.downLeafSet + otherNode.upLeafSet
		for leafOfOtherNode in t_leafOfOtherNodeSet:
			if leafOfOtherNode in otherNode.downLeafSet and X.nodeKey < otherNode.nodeKey:
				if(getNumericDistance(leafOfOtherNode, otherNode) > getNumericDistance(X, otherNode)):
					otherNode.downLeafSet.remove(leafOfOtherNode)
					otherNode.downLeafSet.append(X)
					break
			if leafOfOtherNode in otherNode.upLeafSet and X.nodeKey > otherNode.nodeKey:
				if(getNumericDistance(leafOfOtherNode, otherNode) > getNumericDistance(X, otherNode)):
					otherNode.upLeafSet.remove(leafOfOtherNode)
					otherNode.upLeafSet.append(X)
					break


	# updating nodes in routing table with X
	for otherNode in t_nodes:
		prefixLen = helper.shl(otherNode.nodeKey, X.nodeKey)
		row = prefixLen
		col = int(X.nodeKey[prefixLen], 16)
		routeTableEntry = otherNode.routingTable[row][col]
		if not(isNodeAlive(routeTableEntry)):
			otherNode.routingTable[row][col] = X
def nodeDeleted(X):
	X.isNodeActive = False
	for node in nodes:
		# Repair leaf set
		if X in node.upLeafSet:
			node.upLeafSet.remove(X)
			temp = getMaxLeaf(node)
			
			if temp:
				t_leafSet = temp.downLeafSet + temp.upLeafSet
				for leaf in t_leafSet:
					if isEligibleUpLeaf(leaf, node) and leaf not in node.upLeafSet and isNodeAlive(leaf):
						node.upLeafSet.append(leaf)
						break

		elif X in node.downLeafSet:
			node.downLeafSet.remove(X)
			temp = getMinLeaf(node)
			
			if temp:
				t_leafSet = temp.downLeafSet + temp.upLeafSet
				for leaf in t_leafSet:
					if isEligibleDownLeaf(leaf, node) and leaf not in node.downLeafSet and isNodeAlive(leaf):
						node.downLeafSet.append(leaf)
						break
				
		# Repair neighborhood set
		if X in node.neighborhoodSet:
			node.neighborhoodSet.remove(X)
			t_neighborOfNeighborList = []
			# getting all the neighbor of neighbors
			for neighbor in node.neighborhoodSet:
				if(isNodeAlive(neighbor)):
					t_neighborOfNeighborList += neighbor.neighborhoodSet
			
			t_neighborOfNeighborList = list(set(t_neighborOfNeighborList))
			while t_neighborOfNeighborList:
				closestNeighborOfNeighbor = getClosestNode(t_neighborOfNeighborList, node)
				
				if(closestNeighborOfNeighbor.nodeKey == node.nodeKey):
					t_neighborOfNeighborList.remove(closestNeighborOfNeighbor)
					continue
				
				node.neighborhoodSet.append(closestNeighborOfNeighbor)
				break
		
		# Repair routing table
		for routeTableRow in node.routingTable:
			try:
				if X in routeTableRow:
					row = node.routingTable.index(routeTableRow)
					col = routeTableRow.index(X)
					repairRouteTableEntry(node, row, col)
					break
			except ValueError:
				continue
def noisyDelete(X):
	X.isNodeActive = False
	affectedCount = 0
	
	for node in nodes:
		
		if not(isNodeAlive(node)):  # no need to repair the dead nodes
			continue
		
		affectedFlag = False
		
		# Repair leaf set
		if X in node.upLeafSet:
			affectedFlag = True
			node.upLeafSet.remove(X)
			temp = getMaxLeaf(node)
			
			if temp:
				t_leafSet = temp.downLeafSet + temp.upLeafSet
				for leaf in t_leafSet:
					if isEligibleUpLeaf(leaf, node) and leaf not in node.upLeafSet and isNodeAlive(leaf):
						node.upLeafSet.append(leaf)
						break

		elif X in node.downLeafSet:
			affectedFlag = True
			node.downLeafSet.remove(X)
			temp = getMinLeaf(node)
			
			if temp:
				t_leafSet = temp.downLeafSet + temp.upLeafSet
				for leaf in t_leafSet:
					if isEligibleDownLeaf(leaf, node) and leaf not in node.downLeafSet and isNodeAlive(leaf):
						node.downLeafSet.append(leaf)
						break
				
		# Repair neighborhood set
		if X in node.neighborhoodSet:
			affectedFlag = True
			node.neighborhoodSet.remove(X)
			t_neighborOfNeighborList = []
			# getting all the neighbor of neighbors
			for neighbor in node.neighborhoodSet:
				if(isNodeAlive(neighbor)):
					for neighborOfneighbor in neighbor.neighborhoodSet:
						if(isNodeAlive(neighborOfneighbor)):
							t_neighborOfNeighborList.append(neighborOfneighbor)
			
			t_neighborOfNeighborList = list(set(t_neighborOfNeighborList))
			while t_neighborOfNeighborList:
				closestNeighborOfNeighbor = getClosestNode(t_neighborOfNeighborList, node)
				
				try:
					if(closestNeighborOfNeighbor.nodeKey == node.nodeKey):
						t_neighborOfNeighborList.remove(closestNeighborOfNeighbor)
						continue
				
					node.neighborhoodSet.append(closestNeighborOfNeighbor)
					break
				except AttributeError:
					print ("Error")
		
		# Repair routing table
		for routeTableRow in node.routingTable:
			try:
				if X in routeTableRow:
					affectedFlag = True
					row = node.routingTable.index(routeTableRow)
					col = routeTableRow.index(X)
					repairRouteTableEntry(node, row, col)
					break
			except ValueError:
				continue
		
		if affectedFlag:
			affectedCount += 1
		
	return affectedCount