from parallels.core import messages
import sys

class UniqueNameGenerator:
	"""Generator of unique names.

	Unique name generator helps to make existing names unique by adding suffix.

	Generator remembers all names it has generated and when you give it new
	name which is already known to generator it tries to add suffix to make name unique.
	Generator first suffixes with increasing numbers until it finds free name.
	Concrete suffix format is given to constructor.

	Additionally generator ensures that returned names are no longer than
	given maximum length by truncating name when necessary.

	>>> generate_name = UniqueNameGenerator("_%d", 5)
	>>> generate_name('some')
	'some'
	>>> generate_name('another')
	'anoth'
	>>> generate_name('some')
	'som_2'
	>>> generate_name('some')
	'som_3'
	"""
	def __init__(self, suffix_format, max_length=sys.maxint):
		"""Create unique name generator.

		suffix_format: format string for turning ordinal number into suffix.
			Used as `suffix_format % i` where `i` is int.
		max_length: maximum generated name length.
		"""
		self.suffix_format = suffix_format
		self.max_length = max_length
		self.names = set()

	def __call__(self, name):
		new_name = self.generate(self.names, name, self.suffix_format, self.max_length)
		self.names.add(new_name)
		return new_name

	@classmethod
	def generate(self, existing_names, name, suffix_format, max_length=sys.maxint):
		i = 1
		new_name = name[:max_length]
		while new_name in existing_names:
			i += 1
			suffix = suffix_format % i
			if len(suffix) > max_length:
				raise Exception(messages.UNIQUE_NAME_SUFFIX_IS_TOO_LONG)
			length = max_length - len(suffix)
			new_name = name[:length] + suffix

		return new_name

	def add(self, name):
		"""Do not generate unique name, just ensure that given name
		is unique and remember it.
		"""
		if name is self.names:
			raise Exception(u"Name is not unique: %s" % (name,))

		self.names.add(name)

if __name__ == '__main__':
	import doctest
	doctest.testmod()


