# The MIT License
#
# Copyright (c) 2008 Bob Farrell
# Copyright (c) 2013 Sebastian Ramacher
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

from __future__ import print_function

import os
import sys
import traceback

import bpython
from bpdb.debugger import BPdb
from optparse import OptionParser
from pdb import Restart

__version__ = bpython.__version__


def set_trace():
    """ Just like pdb.set_trace(), a helper function that creates
    a debugger instance and sets the trace. """
    debugger = BPdb()
    debugger.set_trace(sys._getframe().f_back)


# Adopted verbatim from pdb for completeness:

def post_mortem(t=None):
    # handling the default
    if t is None:
        # sys.exc_info() returns (type, value, traceback) if an exception is
        # being handled, otherwise it returns None
        t = sys.exc_info()[2]
        if t is None:
            raise ValueError("A valid traceback must be passed if no "
                             "exception is being handled")

    p = BPdb()
    p.reset()
    p.interaction(None, t)


def pm():
    post_mortem(getattr(sys, "last_traceback", None))


def main():
    parser = OptionParser(
        usage='Usage: %prog [options] [file [args]]')
    parser.add_option('--version', '-V', action='store_true',
                      help='Print version and exit.')
    options, args = parser.parse_args(sys.argv)
    if options.version:
        print('bpdb on top of bpython version', __version__, end="")
        print('on top of Python', sys.version.split()[0])
        print('(C) 2008-2013 Bob Farrell, Andreas Stuehrk et al. '
              'See AUTHORS for detail.')
        return 0

    # The following code is based on Python's pdb.py.
    mainpyfile = args[1]
    if not os.path.exists(mainpyfile):
        print('Error:', mainpyfile, 'does not exist')
        return 1

    # Hide bpdb from argument list.
    del sys.argv[0]

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

    pdb = BPdb()
    while True:
        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")
