# Copyright 2010-2011 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

import platform
import pty
import termios

from portage import os
from portage.output import get_term_size, set_term_size
from portage.util import writemsg

# Disable the use of openpty on Solaris as it seems Python's openpty
# implementation doesn't play nice on Solaris with Portage's
# behaviour causing hangs/deadlocks.
# Additional note for the future: on Interix, pipes do NOT work, so
# _disable_openpty on Interix must *never* be True
_disable_openpty = platform.system() in ("SunOS",)

_fbsd_test_pty = platform.system() == "FreeBSD"


def _create_pty_or_pipe(copy_term_size=None):
    """
    Try to create a pty and if then fails then create a normal
    pipe instead.

    @param copy_term_size: If a tty file descriptor is given
            then the term size will be copied to the pty.
    @type copy_term_size: int
    @rtype: tuple
    @return: A tuple of (is_pty, master_fd, slave_fd) where
            is_pty is True if a pty was successfully allocated, and
            False if a normal pipe was allocated.
    """

    got_pty = False

    global _disable_openpty, _fbsd_test_pty

    if _fbsd_test_pty and not _disable_openpty:
        # Test for python openpty breakage after freebsd7 to freebsd8
        # upgrade, which results in a 'Function not implemented' error
        # and the process being killed.
        pid = os.fork()
        if pid == 0:
            pty.openpty()
            os._exit(os.EX_OK)
        pid, status = os.waitpid(pid, 0)
        if (status & 0xFF) == 140:
            _disable_openpty = True
        _fbsd_test_pty = False

    if _disable_openpty:
        master_fd, slave_fd = os.pipe()
    else:
        try:
            master_fd, slave_fd = pty.openpty()
            got_pty = True
        except OSError as e:
            _disable_openpty = True
            writemsg(f"openpty failed: '{str(e)}'\n", noiselevel=-1)
            del e
            master_fd, slave_fd = os.pipe()

    if got_pty:
        # Disable post-processing of output since otherwise weird
        # things like \n -> \r\n transformations may occur.
        mode = termios.tcgetattr(slave_fd)
        mode[1] &= ~termios.OPOST
        termios.tcsetattr(slave_fd, termios.TCSANOW, mode)

    if got_pty and copy_term_size is not None and os.isatty(copy_term_size):
        rows, columns = get_term_size()
        set_term_size(rows, columns, slave_fd)

    return (got_pty, master_fd, slave_fd)
