# -*- coding: utf-8 -*-
"""Decorator factory class which returns a decorator function that
marks a function as deprecated.

"""

from __future__ import absolute_import, division, print_function, unicode_literals

import collections
import warnings


class deprecated(object):
    """Decorator factory class which returns a decorator function that
    marks a function as deprecated. It will result in a warning being
    emitted when the function is used, once per invocation point and
    deprecated function. The doc string of the deprecated function is
    overwritten with a deprecation message.

    @deprecated(use_instead="c_to_p(...)")
    def hgvsc_to_hgvsp():
        ...

    results in warnings like this:

    variantmapper.py:280: DeprecationWarning: Call to deprecated function
      hgvsc_to_hgvsp; use c_to_p(...) instead

    """

    def __init__(self, use_instead=None):
        # only warn once per caller location and function
        self.seen = collections.Counter()
        self.use_instead = use_instead

    def __call__(self, func):
        msg = "Call to deprecated function {}".format(func.__name__)
        if self.use_instead:
            msg += '; use ' + self.use_instead + ' instead'

        def wrapper(*args, **kwargs):
            fingerprint = (func.__name__, func.__code__.co_filename, func.__code__.co_firstlineno)
            if fingerprint not in self.seen:
                warnings.warn_explicit(
                    msg,
                    category=DeprecationWarning,
                    filename=func.__code__.co_filename,
                    lineno=func.__code__.co_firstlineno + 1)
            self.seen.update([fingerprint])
            return func(*args, **kwargs)

        wrapper.__doc__ = "Deprecated"
        if self.use_instead:
            wrapper.__doc__ += '; use ' + self.use_instead + ' instead'
        return wrapper