import hashlib
import random


def convert_str(data):
    """covert data.

    :param data:
    :return: string
    """

    if isinstance(data, bytes):
        return data.decode()
    if isinstance(data, dict):
        return dict(map(convert_str, data.items()))
    if isinstance(data, tuple):
        return map(convert_str, data)
    if isinstance(data, list):
        return data[0].decode()
    return data


def md5(src: str, algorithm: str = "md5", digits: int = 32) -> str:
    """md5 algorithms.

    :param src: original string.
    :param algorithm: algorithm method.
    :param digits: 16 length or 32 length.
    :return: string.
    """

    algorithm = hashlib.new(algorithm)
    algorithm.update(src.encode('utf8'))
    if digits == 16:
        return algorithm.hexdigest()[8:24]
    else:
        return algorithm.hexdigest()


def random_request_priority(request):
    """random request priority.

    :param request: request.
    :return: priority.
    """

    priority = request.priority
    if 0 <= priority <= 200:
        priority = random.randint(100, 200)
        request.priority = priority


def singleton(cls, *args, **kw):
    """singleton mode.

    :param cls: classname
    :param args: args.
    :param kw: kwargs.
    :return:
    """

    instances = {}

    def _singleton():
        if cls not in instances:
            instances[cls] = cls(*args, **kw)
        return instances[cls]

    return _singleton
