# -*- coding: utf-8 -*-
""" Imports and provides the 'correct' version of readline for the platform.

Readline is used throughout IPython as::

    import IPython.utils.rlineimpl as readline

In addition to normal readline stuff, this module provides have_readline
boolean and _outputfile variable used in IPython.utils.
"""

import os
import re
import sys
import time
import warnings

from subprocess import Popen, PIPE

try:
    from readline import *
    import readline as _rl
    have_readline = True
except ImportError:
    try:
        from pyreadline import *
        import pyreadline as _rl
        have_readline = True
    except ImportError:
        have_readline = False

if have_readline and hasattr(_rl, 'rlmain'):
    # patch add_history to allow for strings in pyreadline <= 1.5:
    # fix copied from pyreadline 1.6
    import pyreadline
    if pyreadline.release.version <= '1.5':
        def add_history(line):
            """add a line to the history buffer."""
            from pyreadline import lineobj
            if not isinstance(line, lineobj.TextLine):
                line = lineobj.TextLine(line)
            return _rl.add_history(line)

if sys.platform == 'win32' and have_readline:
    try:
        _outputfile=_rl.GetOutputFile()
    except AttributeError:
        warnings.warn("Failed GetOutputFile")
        have_readline = False

# Test to see if libedit is being used instead of GNU readline.
# Thanks to Boyd Waters for the original patch.
uses_libedit = False
if sys.platform == 'darwin' and have_readline:
    # Previously this used commands.getstatusoutput, which uses os.popen.
    # Switching to subprocess.Popen, and exponential falloff for EINTR
    # seems to make this better behaved in environments such as PyQt and gdb
    dt = 1e-3
    while dt < 1:
        try:
            p = Popen(['otool', '-L', _rl.__file__], stdout=PIPE, stderr=PIPE)
        except OSError:
            try:
                # otool not available (no XCode), use lsof instead.
                # This *could* have a false positive
                # if another package that uses libedit explicitly
                # has been imported prior to this test.
                p = Popen(['lsof', '-p', str(os.getpid())], stdout=PIPE, stderr=PIPE)
            except OSError:
                # This is highly unlikely, but let's be sure
                # we don't crash IPython just because we can't find lsof
                p = out = err = None
                warnings.warn("libedit detection failed")
                break

        out,err = p.communicate()

        if p.returncode == 4:
            # EINTR
            time.sleep(dt)
            dt *= 2
            continue
        elif p is None or p.returncode:
            warnings.warn("libedit detection failed: %s"%err)
            break
        else:
            break

    if p is not None and p.returncode == 0 and re.search(br'/libedit[\.\d+]*\.dylib\s', out):
        # we are bound to libedit - new in Leopard
        _rl.parse_and_bind("bind ^I rl_complete")
        warnings.warn("Leopard libedit detected - readline will not be well behaved "
            "including some crashes on tab completion, and incorrect history navigation. "
            "It is highly recommended that you install readline, "
            "which is easy_installable with: 'easy_install readline'",
            RuntimeWarning)
        uses_libedit = True
    # cleanup names
    del dt,p,out,err

# the clear_history() function was only introduced in Python 2.4 and is
# actually optional in the readline API, so we must explicitly check for its
# existence.  Some known platforms actually don't have it.  This thread:
# http://mail.python.org/pipermail/python-dev/2003-August/037845.html
# has the original discussion.

if have_readline:
    try:
        _rl.clear_history
    except AttributeError:
        def clear_history(): pass
        _rl.clear_history = clear_history
