import os
import subprocess
import sys

from parallels.core.utils.common import is_run_on_windows
from parallels.core import messages


def demonize():
    """Run migrator in async mode"""
    if is_run_on_windows():
        _run_async_windows()
    else:
        _run_async_unix()


# Default working directory for the daemon.
UNIX_WORKDIR = '/'

# Default maximum for the number of available file descriptors.
UNIX_MAXFD = 1024


def _run_async_unix():
    """Detach a process from the controlling terminal and run it in the background as a daemon"""
    try:
        pid = os.fork()
    except OSError as exception:
        raise Exception('%s [%d]' % (exception.strerror, exception.errno))
    if pid == 0:  # the first child
        os.setsid()

        try:
            pid = os.fork()  # fork a second child
        except OSError as exception:
            raise Exception('%s [%d]' % (exception.strerror, exception.errno))

        if pid != 0:
            os._exit(0)  # exit parent (the first child) of the second child
    else:
        os._exit(0)  # exit parent of the first child

    # Here we are in the second child

    os.chdir(UNIX_WORKDIR)
    _configure_file_permissions_unix()
    _configure_maxfd_unix()
    _configure_std_streams_unix()


def _configure_std_streams_unix():
    # The standard I/O file descriptors are redirected to /dev/null by default.
    if hasattr(os, 'devnull'):
        redirect_to = os.devnull
    else:
        redirect_to = '/dev/null'
    os.open(redirect_to, os.O_RDWR)  # standard input (0)
    os.dup2(0, 1)  # standard output (1)
    os.dup2(0, 2)  # standard error (2)


def _configure_maxfd_unix():
    import resource

    maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
    if maxfd == resource.RLIM_INFINITY:
        maxfd = UNIX_MAXFD
    for fd in range(0, maxfd):
        try:
            os.close(fd)
        except OSError:  # fd wasn't open to begin with (ignored)
            pass


def _configure_file_permissions_unix():
    # Configure migrator so:
    # - nobody except root and Plesk user under which migrator is running can read/modify the files.
    # - both backend (running as superuser) and frontend (running as "psaadm") could work with the files.
    # Expected permissions for files created by backend are:
    # rw-rw---- root psaadm
    # Expected permissions for directories created by backend are:
    # rwxrwx--- root psaadm
    # So, frontend could work with files by group "psadm", and backend could work with the files as superuser.
    import grp

    try:
        frontend_group_entry = grp.getgrnam('psaadm')
    except KeyError:
        frontend_group_entry = None

    if frontend_group_entry is not None:
        frontend_group_id = frontend_group_entry.gr_gid
        os.setegid(frontend_group_id)

    # Do not allow others to work with files
    os.umask(0o007)


WINDOWS_DETACHED_PROCESS = 0x00000008
WINDOWS_CREATE_NEW_PROCESS_GROUP = 0x00000200


def _run_async_windows():
    pid = subprocess.Popen(
        [sys.executable] + [arg for arg in sys.argv if arg != '--async'],
        creationflags=WINDOWS_DETACHED_PROCESS | WINDOWS_CREATE_NEW_PROCESS_GROUP
    ).pid
    print(messages.STARTED_ASYNC_MIGRATION_PROCESS % pid)
    sys.exit(0)
