import contextlib
import os
import sys


def immediate_exit_with_handlers(exit_status=0):
    """
    Exits using os._exit(exit_status), to terminate when running in
    IPython.start_ipython() (which captures SystemExit and all exceptions).
    But before that abrupt exit it ensures that all the exit handlers
    registerd with atexit are run.
    """
    def run_atexit_handlers():
        # Note: the drawback of this approach is that atexit._exithandlers is
        # NOT available in Python 3
        import atexit
        # This could be done with atexit._run_exitfuncs(), but let's avoid
        # using one more protected function:
        for handler_tuple in reversed(atexit._exithandlers):
            # Try/except is to avoid application process hanging when the 
            # background process (tcl in particular)
            # is already destroyed
            try:
                handler_tuple[0]()
            except:
                pass

    run_atexit_handlers()
    import os
    os._exit(exit_status)


###
### redirect_argv(...) is used to present a consistent, clean sys.argv to
### the file being executed (via "-c somescript.py arg1, arg2..."). The
### redirect_exit(...) is used to substitue in the hard exit that comes
### with "os._exit(status)". Otherwise, ipython prevents "sys.exit(...)"
### exit and dumps us back to the ipython command line.
###
def redirect_exit(msg=None):
    if isinstance(msg, int):
        immediate_exit_with_handlers(msg)
    elif msg is not None:
        sys.stderr.write(str(msg))
    immediate_exit_with_handlers(0)


@contextlib.contextmanager
def redirect_argv(args):
    sys._argv = sys.argv[:]
    ###
    ### this could be cleaned up to be just:
    ###
    ###    sys.argv = ['somescript.py', arg1, arg2...]
    ###
    ### but casa scripts seem to have been
    ### expecting the 'casa' arg as well as the '-c' arg
    sys.argv = ['casa', '-c'] + args
    sys._save_exit = sys.exit
    sys.exit = redirect_exit
    yield
    sys.argv = sys._argv
    sys.exit = sys._save_exit