#!/usr/bin/python

# pylint: disable=import-outside-toplevel

import os
import sys
import shlex
from shutil import which


def usage(msg, exit_code=1):
    if msg:
        sys.stderr.write("%s\n" % msg)
    sys.stderr.write("usage: run_scaled --scale=VALUE application [optionalarguments]\n")
    sys.stderr.write("   ie: run_scaled --scale=2     xterm +ls -fg blue\n")
    sys.exit(exit_code)


def parse_scale(scale):
    try:
        try:
            if scale.endswith("%"):
                value = float(scale[:-1])/100
            else:
                value = float(scale)
        except ValueError:
            #try parsing as a fraction:
            from fractions import Fraction
            value = float(Fraction(scale))
    except ValueError:
        return usage("invalid scale value '%s'" % (scale,))
    if value<0.1 or value>10:
        return usage("scale value %f is out of range" % (value,))
    return value


def get_screen_spec():
    #figure out the dpi and vfb size to use,
    dpi = width = height = 0
    from xpra.util.env import OSEnvContext
    with OSEnvContext():
        os.environ["GDK_SCALE"] = "1"
        os.environ["GDK_DPI_SCALE"] = "1"
        import gi
        gi.require_version('Gdk', '3.0')
        from gi.repository import Gdk
        screen = Gdk.Screen.get_default()
        if screen:
            import warnings
            with warnings.catch_warnings():
                warnings.simplefilter("ignore")
                width = screen.get_width()
                height = screen.get_height()
                if 0<width<2**16 and 0<height<2**16:
                    def dpiv(size, size_mm):
                        return int(0.5 + size * 25.4 / size_mm)
                    dpi = (dpiv(width, screen.get_width_mm()) + dpiv(height, screen.get_height_mm()))//2
    return width, height, dpi


xpra_cmd = which("xpra") or ""
if not xpra_cmd and sys.argv[0].find("run_scaled") >= 0:
    xpra_cmd = sys.argv[0].replace("run_scaled", "xpra")
if not xpra_cmd or not os.path.exists(xpra_cmd):
    usage("cannot find 'xpra' on $PATH")


def get_argv() -> list[str]:
    # default value:
    scale = 2
    command_argv = []
    extra_xpra_args: list[str] = []

    # If "--" is present, the command is after that
    if "--" in sys.argv:
        split_idx = sys.argv.index("--")
        args = sys.argv[1:split_idx]
        command_argv = sys.argv[split_idx+1:]
        extra_xpra_args = []
    else:
        args = sys.argv[1:]

    for x in args:
        if x in ("--help", "-h"):
            usage(None, 0)
        elif x.startswith("--scale="):
            scale = parse_scale(x[len("--scale="):])
        else:
            if extra_xpra_args is None:
                command_argv.append(x)
            else:
                extra_xpra_args.append(x)
    if not command_argv:
        usage("missing command argument")

    xpra_argv = [
        xpra_cmd,
        "start",
        "--start-child=%s" % shlex.join(command_argv),
        "--attach=yes",
        "--exit-with-children=yes",
        "--desktop-scaling=%s" % scale,
        "--encodings=rgb",
        "--compress=0",
        "--systemd-run=no",
    ] + extra_xpra_args

    width, height, dpi = get_screen_spec()
    # if found, prefer Xvfb, as it is faster to startup:
    xvfb = which("Xvfb") or ""
    if xvfb:
        from xpra.scripts.config import get_Xvfb_command
        xpra_argv.append("--xvfb=%s" % shlex.join(get_Xvfb_command(width, height, dpi*scale)))
    if width > 0 and height > 0:
        xpra_argv.append("--resize-display=%ix%i" % (width//scale, height//scale))
    if 10 < dpi < 1000:
        xpra_argv.append("--dpi=%i" % (dpi*scale))
    return xpra_argv


os.execv(xpra_cmd, get_argv())
