import os
import subprocess
import sys

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

# Default daemon parameters.
# File mode creation mask of the daemon.
UMASK = 0

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

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

DETACHED_PROCESS = 0x00000008
CREATE_NEW_PROCESS_GROUP = 0x00000200

# 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'


def demonize():
	"""Detach a process from the controlling terminal and run it in the
	background as a daemon
	"""
	if is_run_on_windows():
		_run_async_windows()
		return

	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:  # the second child
			os.chdir(WORKDIR)
			os.umask(UMASK)
		else:
			os._exit(0)  # exit parent (the first child) of the second child
	else:
		os._exit(0)  # exit parent of the first child

	import resource
	maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
	if maxfd == resource.RLIM_INFINITY:
		maxfd = MAXFD

	for fd in range(0, maxfd):
		try:
			os.close(fd)
		except OSError:  # fd wasn't open to begin with (ignored)
			pass

	os.open(REDIRECT_TO, os.O_RDWR)  # standard input (0)

	os.dup2(0, 1)  # standard output (1)
	os.dup2(0, 2)  # standard error (2)

	return


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