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
def route(A, X):	
	routePath = []
	while(1):
		
		routePath.append(A)
		if len(routePath) > 20:
			print "route path too much"
		
		# returning if found the node
		if A.nodeKey == X.nodeKey:
			return routePath
		
		# search in leafSet
		leafSet = A.downLeafSet + A.upLeafSet
		if leafSet:  # checking if the leafSet is not empty
			
			minLeaf = getMinLeaf(A)
			if minLeaf is None:
				minLeaf = A
				
			maxLeaf = getMaxLeaf(A)
			if maxLeaf is None:
				maxLeaf = A
				
			if(minLeaf.nodeKey <= X.nodeKey <= maxLeaf.nodeKey):
				leafSet.append(A)  # Adding the currentNode in the leafSet...currentNode can be nearest
				nearestleaf = getMinDistNode(leafSet, X)
				
				# no need to append the routePath if nearestLeaf is the current node
				'''if A.nodeKey != nearestleaf.nodeKey:
					routePath.append(nearestleaf)
					
				return routePath'''
				
				if A.nodeKey == nearestleaf.nodeKey:
					return routePath
				
				A = nearestleaf
				continue

		# search in routing table
		prefixLen = helper.shl(A.nodeKey, X.nodeKey)
		row = prefixLen
		col = int(X.nodeKey[prefixLen], 16)
		distFromA = helper.getNumericDistance(A, X)
		routeTableEntry = A.routingTable[row][col]
		if(isNodeAlive(routeTableEntry)):
			A = routeTableEntry
			continue  # forwarded to the closer node
		else:
			# repair the routingTableEntry
			'''repairRouteTableEntry(A, row, col)'''  # commented here since handled in the deletion
			# Send to numerically closer node
			t_list = A.downLeafSet + A.upLeafSet + A.neighborhoodSet
			for rowEntry in A.routingTable[row]:
				if(isNodeAlive(rowEntry)):
					t_list.append(rowEntry)
			t_list = list(set(t_list))
			
			for node in t_list:
				t_prefixLen = helper.shl(node.nodeKey, X.nodeKey)
				t_dist = helper.getNumericDistance(node, X)
				if(t_prefixLen >= prefixLen and t_dist < distFromA):
					A = node
					break
		
		# returning if no node more near to the last node in the routePath
		if routePath[-1].nodeKey == A.nodeKey:
			return routePath
		
	return routePath
def route(A, X):	
	routePath = []
	accessArr = [0,0,0,0,0,0]
	
	while(1):
		
		routePath.append(A)
		prefixLen = helper.shl(A.nodeKey, X.nodeKey)
		
		if len(routePath) > 20:
			print ("route path too much")
		
		# returning if found the node
		if A.nodeKey == X.nodeKey:
			return routePath, accessArr
		
		# search in leafSet
		accessArr[0] += 1
		leafSet = A.downLeafSet + A.upLeafSet
		if leafSet:  # checking if the leafSet is not empty
			
			minLeaf = getMinLeaf(A)
			maxLeaf = getMaxLeaf(A)
			
			if minLeaf and maxLeaf:
				
				if(minLeaf.nodeKey <= X.nodeKey <= maxLeaf.nodeKey):
					t_leafSet = []
					
					for leaf in leafSet:
						t_prefixLen = helper.shl(leaf.nodeKey, X.nodeKey)
						if t_prefixLen >= prefixLen:
							t_leafSet.append(leaf)
							
					nearestleaf = getMinDistNode(t_leafSet, X)
					
					# no need to append the routePath if nearestLeaf is the current node
					'''if A.nodeKey != nearestleaf.nodeKey:
						routePath.append(nearestleaf)
						
					return routePath'''
					
					accessArr[1] += 1
					A = nearestleaf
					continue

		# search in routing table
		accessArr[2] += 1
		
		row = prefixLen
		col = int(X.nodeKey[prefixLen], 16)
		routeTableEntry = A.routingTable[row][col]
		if(isNodeAlive(routeTableEntry)):
			accessArr[3] += 1
			A = routeTableEntry
			continue  # forwarded to the closer node
		else:
			accessArr[4] += 1
			
			'''# repair the routingTableEntry'''
			# if(routeTableEntry):  # Repairing only if it is not null (i.e it is not active)
			repairRouteTableEntry(A, row, col)  # commented here since handled in the deletion'''
			
			# Send to numerically closer node
			t_list = A.downLeafSet + A.upLeafSet + A.neighborhoodSet
			
			for k in range(row, len(A.routingTable)):
				for rowEntry in A.routingTable[k]:
					if(isNodeAlive(rowEntry)):
						t_list.append(rowEntry)
			
			t_list = list(set(t_list))
			t_list.remove(A)
			t_t_list = []
			
			for node in t_list:  # Getting all nodes with >= prefixLen than the current node
				t_prefixLen = helper.shl(node.nodeKey, X.nodeKey)
				if t_prefixLen >= prefixLen:
						t_t_list.append(node)
			
			nearestNode = getMinDistNode(t_t_list, X)
			distFromA = helper.getNumericDistance(A, X)
			t_dist = helper.getNumericDistance(nearestNode, X)
			
			if(t_dist < distFromA):
				
				if nearestNode in A.neighborhoodSet:
					accessArr[5] += 1
					
				A = nearestNode
				continue
			else:
				# print ("----No more routing possible")
				return routePath, accessArr			
		
	return routePath, accessArr