#utility to aid disassembly during boot phase
import dis, sys
#_verbose=None
#_log=sys.stderr
__all__=()
IMPORT_NAME = dis.opname.index('IMPORT_NAME')
IMPORT_FROM = dis.opname.index('IMPORT_FROM')
try:
    IMPORT_STAR = dis.opname.index('IMPORT_STAR')
except:
    IMPORT_STAR = 999
STORE_NAME = dis.opname.index('STORE_NAME')
STORE_FAST = dis.opname.index('STORE_FAST')
STORE_GLOBAL = dis.opname.index('STORE_GLOBAL')
LOAD_GLOBAL = dis.opname.index('LOAD_GLOBAL')
EXEC_STMT = dis.opname.index('EXEC_STMT')
SET_LINENO = dis.opname.index('SET_LINENO')
BUILD_LIST = dis.opname.index('BUILD_LIST')
LOAD_CONST = dis.opname.index('LOAD_CONST')
JUMP_IF_FALSE = dis.opname.index('JUMP_IF_FALSE')
JUMP_IF_TRUE = dis.opname.index('JUMP_IF_TRUE')
JUMP_FORWARD = dis.opname.index('JUMP_FORWARD')
COND_OPS = [JUMP_IF_TRUE, JUMP_IF_FALSE]
STORE_OPS = [STORE_NAME, STORE_FAST, STORE_GLOBAL]

def _pass1(code,lno):
    instrs = []
    i = 0
    n = len(code)
    curline = 0
    incondition = 0
    out = 0
    HAVE_ARGUMENT = dis.HAVE_ARGUMENT
    while i < n:
        if i >= out:
            incondition = 0
        c = code[i]
        i = i+1
        op = ord(c)
        if op >= HAVE_ARGUMENT:
            oparg = ord(code[i]) + ord(code[i+1])*256
            i = i+2
        else:
            oparg = None
        if not incondition and op in COND_OPS:
            incondition = 1
            out = i + oparg
        elif incondition and op == JUMP_FORWARD:
            out = max(out, i + oparg)
        if op == SET_LINENO:
            curline = oparg
            #if curline>lno: break
            #elif curline<=lno: instrs = []
        else:
            instrs.append((op, oparg, incondition, curline))
    return instrs

def _scan_code(f):
    M = []
    W = []
    co = f.f_code
    instrs = _pass1(co.co_code,f.f_lineno)
    lastname = None
    for i in xrange(len(instrs)):
        op, oparg, conditional, curline = instrs[i]
        if op == IMPORT_NAME:
            name = lastname = co.co_names[oparg]
            #if _verbose>2: print >>_log, '_scan_code: IMPORT_NAME', name
            M.append((name, None, conditional))
        elif op == IMPORT_FROM:
            name = co.co_names[oparg]
            #if _verbose>2: print >>_log, '_scan_code: IMPORT_FROM', lastname, name
            M.append((lastname, name, conditional))
            assert lastname is not None
        elif op == IMPORT_STAR:
            #if _verbose>2: print >>_log, '_scan_code: IMPORT_STAR', lastname
            M.append((lastname,'*',conditional))
        elif op == STORE_NAME:
            pass
        elif op in STORE_OPS:
            pass
        elif op == LOAD_GLOBAL:
            name = co.co_names[oparg]
            cndtl = ['', 'conditional'][conditional]
            if name == "__import__":
                W.append("W: top level %s __import__ hack detected at line %s"  % (cndtl, curline))
            elif name == "eval":
                W.append("W: top level %s eval hack detected at line %s"  % (cndtl, curline))
        elif op == EXEC_STMT:
            cndtl = ['', 'conditional'][conditional]
            W.append("W: top level %s exec statment detected at line %s"  % (cndtl, curline))
        else:
            lastname = None
    return M, W
    
def _rl_boot(pyzName):
    import _rl_archive, _rl_iu, sys
    if hasattr(sys,'_rl_booted'): return
    _rl_iu._globalownertypes.insert(0, _rl_archive.PYZOwner)
    im=sys.importManager=_rl_iu.ImportManager()
    im.install()
    im._bootPYZ=pyzName
    sys.path.insert(0,pyzName)
    sys._rl_booted = 1

def _fix_import(pyzName, modName):
    '''
    for all active frames above this we check for imports and ensure
    that they are correctly set up.
    '''
    import sys, __builtin__
    if hasattr(sys,'_rl_booted'): return
    _rl_boot(pyzName)
    del sys.modules[modName]
    modNameD = modName+'.'
    n = len(modNameD)
    for m in sys.modules.keys():
        if m[:n]==modNameD : del sys.modules[m]
    __import__ = __builtin__.__import__ # this should be our manager now
    __import__(modName)
    f = sys._getframe(3)
    while f:
        M,W = _scan_code(f)
        #if _verbose: print >>_log, f.f_code.co_name, f.f_lineno, M,W
        for m,fL,_ in M:
            if m[:n]==modNameD or m==modName:
                if not fL and m in sys.modules.keys(): continue
                if fL: m += '.'+fL
                try:
                    #if _verbose: print >>_log, '_fix_import', m, fL
                    __import__(m,f.f_globals,None,[fL])
                except:
                    pass
        f = f.f_back
