__all__ = ['classAddMethod', 'Category']

from _objc import selector, classAddMethods, objc_class

def classAddMethod(cls, name, method):
    """
    Add a single method to a class. 'name' is the ObjC selector
    """
    if isinstance(method, selector):
        sel = selector(method.callable,
                    selector=name,
                    signature=method.signature,
                    isClassMethod=method.isClassMethod)
    else:
        sel = selector(method, selector=name)

    return classAddMethods(cls, [sel])


#
# Syntactic support for categories
#

class _CategoryMeta(type):
    """
    Meta class for categories.
    """
    __slots__ = ()
    _IGNORENAMES = ('__module__', '__name__')
    def _newSubclass(cls, name, bases, methods):
        return type.__new__(cls, name, bases, methods)
    _newSubclass = classmethod(_newSubclass)

    def __new__(cls, name, bases, methods):
        if len(bases) != 1:
            raise TypeError, "Cannot have multiple inheritance with Categories"

        c = bases[0].real_class

        if c.__name__ != name:
            raise TypeError, "Category name must be same as class name"

        m = [ x[1] for x in methods.iteritems() if x[0] not in cls._IGNORENAMES ]
        classAddMethods(c, m)
        return c

def Category(cls):
    """
    Create a category on ``cls``. 

    Usage:
        class SomeClass (Category(SomeClass)):
            def method(self):
                pass

    ``SomeClass`` is an existing class that will be rebound to the same
    value. The side-effect of this class definition is that the methods
    in the class definition will be added to the existing class.
    """
    if not isinstance(cls, objc_class):
        raise TypeError, "Category can only be used on Objective-C classes"
    retval = _CategoryMeta._newSubclass('Category', (), dict(real_class=cls))
    return retval
