from bytecodehacks.code_editor import Function
from bytecodehacks.ops import *
import types,new

def rewrite_method(meth,attrs):
    f = Function(meth)
    code = f.func_code
    cs = code.co_code

    code.co_varnames.insert(0,"self")
    code.co_names.insert(0,"self")
    
    i = 0
    while i < len(cs):
        op = cs[i]
        if op.has_name_or_local():
            op.arg = op.arg + 1
        if  ( op.has_name_or_local() and op.name in attrs
              and op.__class__ not in [LOAD_ATTR,STORE_ATTR]):
            if op.arg < code.co_argcount:
                raise ValueError, "parameter also instance member!"
            if op.__class__ in [LOAD_FAST, LOAD_NAME, LOAD_GLOBAL]:
                attrop = LOAD_ATTR
            else:
                attrop = STORE_ATTR
            cs[i:i+1] = [LOAD_FAST(0),attrop(op.name)]
            i = i + 2
        elif  ( op.has_name_or_local() and op.name == "self"
                and op.__class__ is LOAD_GLOBAL):
            import dis
            dis.dis(meth)
            print op.name, op.__class__
            cs[i] = LOAD_FAST(0)
            print cs[i]
            i = i + 1
        else:
            i = i + 1
    code.co_argcount = code.co_argcount + 1
    return f.make_function()

class SelflessClass:
    inited = 0
    def __init__(self,name,bases,ns):
        print "SelflessClass.__init__", bases
        self.__name__ = name
        if self.inited:
            try:
                attrs = ns['__attrs__']
            except KeyError:
                pass
            else:
                for k,v in ns.items():
                    if type(v) is types.FunctionType:
                        ns[k] = rewrite_method(v,attrs)
            newbases = []
            for base in bases:
                if type(base) is types.ClassType:
                    newbases.append(base)
                elif isinstance(base,SelflessClass) and hasattr(base,"klass"):
                    newbases.append(base.klass)
            self.__bases__ = tuple(newbases)
            self.klass = new.classobj(name,self.__bases__,ns)
            self.__find_init(self.klass)
        else:
            self.__bases__ = bases
            self.__class__.inited = 1
    def __find_init(self,klass):
        if hasattr(klass,"__init__"):
            self.init = klass.__init__
        else:
            for base in klass.__bases__:
                self.__find_init(base)
    def __call__(self,*args,**kw):
        inst = new.instance(self.klass,{})
        if self.init:
            apply(self.init,(inst,)+args,kw)
        return inst

Selfless = SelflessClass("Selfless",(),{})

class MyClass(Selfless):
    __attrs__ = ["a"]
    def __init__():
        a = 1
    def get_a():
        return a
    def set_a(newa):
        a = newa

class D(MyClass):
    def __init__(self,b):
        MyClass.klass.__init__(self)
        self.b = b
    def set_b(self,b):
        self.b = b
    def get_b(self):
        return self.b

class S(Selfless,MyClass):
    __attrs__ = ["mc"]
    def __init__(c):
        MyClass.klass.__init__(self)
        mc = c
    def set_c(c):
        mc = c
    def get_c():
        return c
