# Copyright (c) 2011, 2012 Godefroid Chapelle
# 
# This file is part of ipdb.
# GNU package is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free 
# Software Foundation, either version 2 of the License, or (at your option) 
# any later version.
#
# GNU package is distributed in the hope that it will be useful, but 
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.

import sys
import os
import traceback

from contextlib import contextmanager

try:
    from pdb import Restart
except ImportError:
    class Restart(Exception):
        pass

import IPython

if IPython.__version__ > '0.10.2':
    from IPython.core.debugger import Pdb, BdbQuit_excepthook
    try:
        get_ipython
    except NameError:
        # Make it more resilient to different versions of IPython and try to
        # find a module.
        possible_modules = ['IPython.frontend.terminal.embed',  # Older IPython
                            'IPython.terminal.embed']           # Newer IPython

        count = len(possible_modules)
        for module in possible_modules:
            try:
                embed = __import__(module, fromlist=["InteractiveShellEmbed"])
                InteractiveShellEmbed = embed.InteractiveShellEmbed
            except ImportError:
                count -= 1
                if count == 0:
                    raise

        ipshell = InteractiveShellEmbed()
        def_colors = ipshell.colors
    else:
        def_colors = get_ipython.im_self.colors

    from IPython.utils import io

    def update_stdout():
        # setup stdout to ensure output is available with nose
        io.stdout = sys.stdout = sys.__stdout__
else:
    from IPython.Debugger import Pdb, BdbQuit_excepthook
    from IPython.Shell import IPShell
    from IPython import ipapi

    ip = ipapi.get()
    if ip is None:
        IPShell(argv=[''])
        ip = ipapi.get()
    def_colors = ip.options.colors

    from IPython.Shell import Term

    def update_stdout():
        # setup stdout to ensure output is available with nose
        Term.cout = sys.stdout = sys.__stdout__

def wrap_sys_excepthook():
    # make sure we wrap it only once or we would end up with a cycle
    #  BdbQuit_excepthook.excepthook_ori == BdbQuit_excepthook
    if sys.excepthook != BdbQuit_excepthook:
        BdbQuit_excepthook.excepthook_ori = sys.excepthook
        sys.excepthook = BdbQuit_excepthook

def set_trace(frame=None):
    update_stdout()
    wrap_sys_excepthook()
    if frame is None:
        frame = sys._getframe().f_back
    Pdb(def_colors).set_trace(frame)


def post_mortem(tb):
    update_stdout()
    wrap_sys_excepthook()
    p = Pdb(def_colors)
    p.reset()
    if tb is None:
        return
    while tb.tb_next is not None:
        tb = tb.tb_next
    p.interaction(tb.tb_frame, tb)


def pm():
    post_mortem(sys.last_traceback)


def run(statement, globals=None, locals=None):
    Pdb(def_colors).run(statement, globals, locals)


def runcall(*args, **kwargs):
    return Pdb(def_colors).runcall(*args, **kwargs)


def runeval(expression, globals=None, locals=None):
    return Pdb(def_colors).runeval(expression, globals, locals)


@contextmanager
def launch_ipdb_on_exception():
    try:
        yield
    except Exception:
        e, m, tb = sys.exc_info()
        print >>sys.stderr, m.__repr__()
        post_mortem(tb)
    finally:
        pass


def main():
    if not sys.argv[1:] or sys.argv[1] in ("--help", "-h"):
        print "usage: ipdb.py scriptfile [arg] ..."
        sys.exit(2)

    mainpyfile = sys.argv[1]     # Get script filename
    if not os.path.exists(mainpyfile):
        print 'Error:', mainpyfile, 'does not exist'
        sys.exit(1)

    del sys.argv[0]         # Hide "pdb.py" from argument list

    # Replace pdb's dir with script's dir in front of module search path.
    sys.path[0] = os.path.dirname(mainpyfile)

    # Note on saving/restoring sys.argv: it's a good idea when sys.argv was
    # modified by the script being debugged. It's a bad idea when it was
    # changed by the user from the command line. There is a "restart" command
    # which allows explicit specification of command line arguments.
    pdb = Pdb(def_colors)
    while 1:
        try:
            pdb._runscript(mainpyfile)
            if pdb._user_requested_quit:
                break
            print "The program finished and will be restarted"
        except Restart:
            print "Restarting", mainpyfile, "with arguments:"
            print "\t" + " ".join(sys.argv[1:])
        except SystemExit:
            # In most cases SystemExit does not warrant a post-mortem session.
            print "The program exited via sys.exit(). Exit status: ",
            print sys.exc_info()[1]
        except:
            traceback.print_exc()
            print "Uncaught exception. Entering post mortem debugging"
            print "Running 'cont' or 'step' will restart the program"
            t = sys.exc_info()[2]
            pdb.interaction(None, t)
            print "Post mortem debugger finished. The " + mainpyfile + \
                  " will be restarted"

if __name__ == '__main__':
    main()

@@ -1046,17 +1046,8 @@
 hon.
-frontend.
 term
@@ -1064,13 +1064,22 @@
 ',  
-# Old
+         # New
 er I
@@ -1114,32 +1114,41 @@
        'IPython.
+frontend.
 terminal.embed'%5D
@@ -1149,30 +1149,21 @@
 mbed'%5D  
-         # New
+# Old
 er IPyth

fix for warn("The top-level frontend package has been deprecated.[...]