import sys

from random import sample
from string import digits, ascii_uppercase, ascii_lowercase

from parallels.core import messages


def get_unique_filename(prefix='tmp-', suffix='', length=8):
    chars = ascii_lowercase + ascii_uppercase + digits
    filename = prefix + ''.join(sample(chars, length)) + suffix
    return filename


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=None):
        """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.
        """
        if max_length is None:
            if sys.version_info.major >= 3:
                max_length = sys.maxsize
            else:
                max_length = sys.maxint
        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(cls, existing_names, name, suffix_format, max_length=None):
        if max_length is None:
            if sys.version_info.major >= 3:
                max_length = sys.maxsize
            else:
                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(messages.FAILURE_NAME_NOT_UNIQUE)

        self.names.add(name)


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