#!/usr/bin/env python3
# -*- python -*-
#
# Copyright © 2023 Red Hat, Inc
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

""" Run an X client in a dedicated Xwayland server on a Wayland compositor headless """

import argparse
import os
import sys
from time import sleep
from wlheadless.wlheadless_common import WlheadlessCommon


class XwfbArgsAction(argparse.Action):
    """
    argparse class to parse escaped server arguments.
    """
    def __init__(self, option_strings, dest, **kwargs):
        super().__init__(option_strings, dest, default = [], **kwargs)

    def __call__(self, parser, namespace, values, option_string = None):
        items = getattr(namespace, self.dest, 0)
        if items == 0:
            items = []
        items.append(values.replace('\\',''))
        setattr(namespace, self.dest, items)


wlheadless_common = WlheadlessCommon()
compositor = wlheadless_common.get_compositor()

parser = argparse.ArgumentParser(description = 'Run an X11 client in a dedicated '
                                               'Xwayland server on a Wayland '
                                               'compositor headless.')
parser.add_argument('command',
                     help = 'The program to run and arguments.',
                     nargs = '*')
parser.add_argument('-a',
                    '--auto-servernum',
                    help = 'Unused, kept for backward compatibility only.')
parser.add_argument('-c',
                    '--compositor',
                    help = 'Use the compositor class implementation.',
                    default = compositor)
parser.add_argument('-d',
                    '--auto-display',
                    help = 'Unused, kept for backward compatibility only.')
parser.add_argument('-e',
                    '--error-file',
                    help = 'File used to store xauth and X server errors.',
                    default = '/dev/null')
parser.add_argument('-f',
                    '--auth-file',
                    help = 'File used to store auth cookie.')
parser.add_argument('-n',
                    '--server-num',
                    help = 'Xserver number to use.')
parser.add_argument('-l',
                    '--listen-tcp',
                    help = 'Enable TCP port listening in the X server.',
                    action = 'store_true')
parser.add_argument('-p',
                    '--xauth-proto',
                    help = 'Xauthority protocol name to use.',
                    default = '.')
parser.add_argument('-s',
                    '--server-args',
                    help = 'Arguments to pass to the X server.',
                    action = XwfbArgsAction)
parser.add_argument('-w',
                    '--wait',
                    help = 'Delay in seconds to wait for the X server to start '
                           'before running COMMAND.',
                    type = int,
                    default = 0)
parser.add_argument('-z',
                    '--compositor-args',
                    help = 'Arguments to pass to the Wayland compositor.',
                    action = XwfbArgsAction)
args = parser.parse_args()

if not args.command:
    parser.print_help()
    sys.exit(os.EX_USAGE)

wlheadless = wlheadless_common.load_compositor(args.compositor)
if not wlheadless:
    sys.exit(-1)

xwayland = wlheadless.xwayland
xwayland.setup_tempdir()
xwayland.setup_xauth(args.auth_file)

xserver_args = ['-fullscreen', '-noreset', '-auth', xwayland.xauthfile]
xserver_args.extend(args.server_args)
if args.listen_tcp:
    xserver_args.extend(['-listen', 'tcp'])
if args.server_num:
    xserver_args.append(':' + args.server_num)

with open(args.error_file, 'a') as logfile:
    os.close(sys.stderr.fileno())
    os.dup2(logfile.fileno(), sys.stderr.fileno())

    if wlheadless.run_compositor(args.compositor_args) < 0:
        xwayland.cleanup()
        sys.exit(-1)

    if wlheadless.wait_compositor() != 0:
        xwayland.cleanup()
        sys.exit(-1)

    if wlheadless.spawn_xwayland(xserver_args) < 0:
        xwayland.cleanup()
        sys.exit(-1)

    if xwayland.create_xauth_entry(args.xauth_proto) != 0:
        xwayland.cleanup()
        sys.exit(-1)

    sleep(args.wait)
    status = os.EX_DATAERR
    try:
        status = wlheadless_common.run_command(args.command)
    except Exception as error:
        print(str(error))

xwayland.cleanup()
wlheadless_common.cleanup()
sys.exit(status)
