"""Generic metaclass.

XXX This is very much a work in progress.

"""

import types

class MetaMethodWrapper:

    def __init__(self, func, inst):
	self.func = func
	self.inst = inst
	self.__name__ = self.func.__name__

    def __call__(self, *args, **kw):
	return apply(self.func, (self.inst,) + args, kw)

class MetaHelper:

    __methodwrapper__ = MetaMethodWrapper # For derived helpers to override

    def __helperinit__(self, formalclass):
	self.__formalclass__ = formalclass

    def __getattr__(self, name):
	# Invoked for any attr not in the instance's __dict__
	try:
	    raw = self.__formalclass__.__getattr__(name)
	except AttributeError:
	    try:
		ga = self.__formalclass__.__getattr__('__usergetattr__')
	    except KeyError:
		raise AttributeError, name
	    return ga(self, name)
	if type(raw) != types.FunctionType:
	    return raw
	return self.__methodwrapper__(raw, self)

class MetaClass:

    """A generic metaclass.

    This can be subclassed to implement various kinds of meta-behavior.

    """

    __helper__ = MetaHelper		# For derived metaclasses to override

    __inited = 0

    def __init__(self, name, bases, dict):
	try:
	    ga = dict['__getattr__']
	except KeyError:
	    pass
	else:
	    dict['__usergetattr__'] = ga
	    del dict['__getattr__']
	self.__name__ = name
	self.__bases__ = bases
	self.__realdict__ = dict
	self.__inited = 1

    def __getattr__(self, name):
	try:
	    return self.__realdict__[name]
	except KeyError:
	    for base in self.__bases__:
		try:
		    return base.__getattr__(name)
		except AttributeError:
		    pass
	    raise AttributeError, name

    def __setattr__(self, name, value):
	if not self.__inited:
	    self.__dict__[name] = value
	else:
	    self.__realdict__[name] = value

    def __call__(self, *args, **kw):
	inst = self.__helper__()
	inst.__helperinit__(self)
	try:
	    init = inst.__getattr__('__init__')
	except AttributeError:
	    init = lambda: None
	apply(init, args, kw)
	return inst
    

Meta = MetaClass('Meta', (), {})


def _test():
    class C(Meta):
	def __init__(self, *args):
	    print "__init__, args =", args
	def m1(self, x):
	    print "m1(x=%s)" %`x`
    print C
    x = C()
    print x
    x.m1(12)
    class D(C):
	def __getattr__(self, name):
	    if name[:2] == '__': raise AttributeError, name
	    return "getattr:%s" % name
    x = D()
    print x.foo
    print x._foo
##     print x.__foo
##     print x.__foo__


if __name__ == '__main__':
    _test()

    
