#-----------------------------------------------------------------------------
# Purpose:
#
# Author: <authors name>
#
# Copyright : University of Zurich, Giacomo Indiveri, Emre Neftci, Sadique Sheik, Fabio Stefanini
# Licence : GPLv2
#-----------------------------------------------------------------------------
# -*- coding: utf-8 -*-


from .chip_v2 import Chip, NeuronBlock, NeuroChip, Block
from . import experimentTools as et
from .group import AddrGroup, AddrGroupBase
from .population import Population
from .connection import Connection, PConnection
from .mapping import Mapping, PMapping
from .neurosetup import NeuroSetup
from .monitors import Monitors, SpikeMonitor
from .api import ComAPI
from .api import ConfAPI
from . import pyST

######################  Utility functions
from functools import wraps


class DocInherit(object):
    ## {{{ http://code.activestate.com/recipes/576862/ (r1)
    """
    Docstring inheriting method descriptor

    The class itself is also used as a decorator

    doc_inherit decorator

    Usage:

    class Foo(object):
        def foo(self):
            "Frobber"
            pass

    class Bar(Foo):
        @doc_inherit
        def foo(self):
            pass

    Now, Bar.foo.__doc__ == Bar().foo.__doc__ == Foo.foo.__doc__ == "Frobber"
    """

    def __init__(self, mthd):
        self.mthd = mthd
        self.name = mthd.__name__

    def __get__(self, obj, cls):
        if obj:
            return self.get_with_inst(obj, cls)
        else:
            return self.get_no_inst(cls)

    def get_with_inst(self, obj, cls):

        overridden = getattr(super(cls, obj), self.name, None)

        @wraps(self.mthd, assigned=('__name__', '__module__'))
        def f(*args, **kwargs):
            return self.mthd(obj, *args, **kwargs)

        return self.use_parent_doc(f, overridden)

    def get_no_inst(self, cls):

        for parent in cls.__mro__[1:]:
            overridden = getattr(parent, self.name, None)
            if overridden:
                break

        @wraps(self.mthd, assigned=('__name__', '__module__'))
        def f(*args, **kwargs):
            return self.mthd(*args, **kwargs)

        return self.use_parent_doc(f, overridden)

    def use_parent_doc(self, func, source):
        if source is None:
            raise NameError("Can't find {o} in parents".format(self.name))
        func.__doc__ = source.__doc__
        return func

doc_inherit = DocInherit


