# -*- coding: utf-8 -*-

global showDepotInfoFunction
showDepotInfoFunction = \
'''
	def showDepotInfo():
		logger.info(u"Choosing depot from list of depots:")
		logger.info(u"   Master depot: %s" % masterDepot)
		for alternativeDepot in alternativeDepots:
			logger.info(u"   Alternative depot: %s" % alternativeDepot)
'''

global getDepotWithLowestLatencyFunction
getDepotWithLowestLatencyFunction = \
'''
	def getDepotWithLowestLatency(latency):
		"""
		Given a dict with depot as key and latency as value it will \
return the depot with the lowest latency.

		Will return None if no depot can be determined.
		"""
		selectedDepot = None
		if latency:
			minValue = 1000
			for (depot, value) in latency.items():
				if value < minValue:
					minValue = value
					selectedDepot = depot
			logger.notice(u"Depot with lowest latency: %s (%0.3f ms)" % (selectedDepot, minValue*1000))

		return selectedDepot
'''

global getLatencyInformationFunction
getLatencyInformationFunction = \
'''
	def getLatencyInformation(depots):
		"""
		Pings the given depots and returns the latency information in \
a dict with depot as key and the latency as value.

		Depots that can't be reached in time will not be included.
		"""
		from OPSI.Util.Ping import ping
		from OPSI.Util.HTTP import urlsplit

		latency = {}
		for depot in depots:
			if not depot.repositoryRemoteUrl:
				logger.info(
					"Skipping {depot} because repositoryRemoteUrl is "
					"missing.".format(depot=depot)
				)
				continue

			try:
				(_, host, _, _, _, _) = urlsplit(depot.repositoryRemoteUrl)
				# To increase the timeout (in seconds) for the ping you
				# can implement it in the following way:
				#  depotLatency = ping(host, timeout=5)
				depotLatency = ping(host)

				if depotLatency is None:
					logger.info(u"Ping to depot {0} timed out.".format(depot))
				else:
					logger.info(u"Latency of depot %s: %0.3f ms" % (depot, depotLatency * 1000))
					latency[depot] = depotLatency
			except Exception as e:
				logger.warning(e)

		return latency
'''


def getDepotSelectionAlgorithmByMasterDepotAndLatency(self):
	return '''\
def selectDepot(clientConfig, masterDepot, alternativeDepots=[]):
	{getLatencyInformationFunction}
	{getDepotWithLowestLatencyFunction}
	{showDepotInfoFunction}

	showDepotInfo()

	if alternativeDepots:
		from collections import defaultdict

		# Mapping of depots to its master.
		# key: Master depot
		# value: All slave depots + master
		depotsByMaster = defaultdict(list)

		allDepots = [masterDepot] + alternativeDepots

		for depot in allDepots:
			if depot.masterDepotId:
				depotsByMaster[depot.masterDepotId].append(depot)
			else:
				depotsByMaster[depot.id].append(depot)

		depotsWithLatency = getLatencyInformation(depotsByMaster[masterDepot.id])
		depotWithLowestLatency = getDepotWithLowestLatency(depotsWithLatency)

		if not depotWithLowestLatency:
			logger.info('No depot with lowest latency. Falling back to master depot.')
			depotWithLowestLatency = masterDepot

		return depotWithLowestLatency

	return masterDepot
'''.format(
	showDepotInfoFunction=showDepotInfoFunction,
	getLatencyInformationFunction=getLatencyInformationFunction,
	getDepotWithLowestLatencyFunction=getDepotWithLowestLatencyFunction
)

def getDepotSelectionAlgorithmByLatency(self):
	return '''\
def selectDepot(clientConfig, masterDepot, alternativeDepots=[]):
	{getLatencyInformationFunction}
	{getDepotWithLowestLatencyFunction}
	{showDepotInfoFunction}

	showDepotInfo()

	selectedDepot = masterDepot
	if alternativeDepots:
		depotsWithLatency = getLatencyInformation([masterDepot] + alternativeDepots)
		selectedDepot = getDepotWithLowestLatency(depotsWithLatency)

		if not selectedDepot:
			logger.info('No depot with lowest latency. Falling back to master depot.')
			selectedDepot = masterDepot

	return selectedDepot
'''.format(
	showDepotInfoFunction=showDepotInfoFunction,
	getLatencyInformationFunction=getLatencyInformationFunction,
	getDepotWithLowestLatencyFunction=getDepotWithLowestLatencyFunction
)

def getDepotSelectionAlgorithmByNetworkAddress(self):
	return '''\
def selectDepot(clientConfig, masterDepot, alternativeDepots=[]):
	{showDepotInfoFunction}

	showDepotInfo()

	selectedDepot = masterDepot
	if alternativeDepots:
		from OPSI.Util import ipAddressInNetwork

		depots = [masterDepot]
		depots.extend(alternativeDepots)
		for depot in depots:
			if not depot.networkAddress:
				logger.warning(u"Network address of depot '%s' not known" % depot)
				continue

			if ipAddressInNetwork(clientConfig['ipAddress'], depot.networkAddress):
				logger.notice(u"Choosing depot with networkAddress %s for ip %s" % (depot.networkAddress, clientConfig['ipAddress']))
				selectedDepot = depot
				break
			else:
				logger.info(u"IP %s does not match networkAddress %s of depot %s" % (clientConfig['ipAddress'], depot.networkAddress, depot))

	return selectedDepot
'''.format(
	showDepotInfoFunction=showDepotInfoFunction,
)


def getDepotSelectionAlgorithm(self):
	""" Returns the selected depot selection algorythm.	"""
	# return self.getDepotSelectionAlgorithmByMasterDepotAndLatency()
	# return self.getDepotSelectionAlgorithmByLatency()
	return self.getDepotSelectionAlgorithmByNetworkAddress()


def getBytes(self, num):
	if (num <= 0):
		return ""
	len128 = "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"
	bytes = ""
	while (len(bytes) < num):
		bytes += len128
	if (len(bytes) > num):
		bytes = bytes[:num]
	return bytes
