#!/usr/bin/env python3
"""Create an extra COSMIC panel for the panel-bar applets.

    cosmic-tools-add-panel [--dry-run] [--restart] [--force] [--from Panel]

COSMIC Settings only manages "Panel" and "Dock", but cosmic-panel starts one
panel per name listed in ~/.config/cosmic/com.system76.CosmicPanel/v1/entries.
This script adds one, configured from ~/.config/cosmic-tools/panel-bar.conf:

    PANEL_NAME             name of the new panel (letters, digits, _ -)
    PANEL_ANCHOR           Top | Bottom | Left | Right
    PANEL_SIZE             XS | S | M | L | XL | Custom(N)  (quote Custom(N))
    PANEL_OUTPUT_POSITION  leftmost | rightmost | a connector name, or "all"
    PANEL_LEFT / PANEL_CENTER / PANEL_RIGHT   space-separated applet desktop ids

What it does:
  1. Backs up ~/.config/cosmic/com.system76.CosmicPanel* to
     ~/.config/cosmic-tools/backups/add-panel-<timestamp>/
  2. Copies every setting of an existing panel (--from, default "Panel", else
     "Dock") into com.system76.CosmicPanel.<PANEL_NAME>/v1/ and overrides name,
     anchor, size, output and the applet lists.
  3. Appends PANEL_NAME to `entries`.
  4. Only with --restart: restarts cosmic-panel so the panel appears.
     Otherwise it appears at next login.

--dry-run prints the files it would write and changes nothing.

To undo: remove the name from `entries` (or restore the backup directory) and
restart cosmic-panel or log out. Note that opening the Panel page in COSMIC
Settings may rewrite `entries`; re-run this script if the panel disappears.
"""

import argparse
import os
import re
import shlex
import sys

HERE = os.path.dirname(os.path.abspath(__file__))
for cand in (os.environ.get("COSMIC_TOOLS_PANEL_SHARE", ""),
             os.path.join(HERE, ".."),
             os.path.expanduser("~/.local/share/cosmic-tools/panel-bar")):
    if cand and os.path.isfile(os.path.join(cand, "lib", "ctconfig.py")):
        sys.path.insert(0, os.path.join(cand, "lib"))
        break
import ctconfig     # noqa: E402
import cosmicpanel  # noqa: E402

# Used only when there is no existing panel to copy from.
FALLBACK = {
    "anchor_gap": "false", "autohide": "None", "background": "ThemeDefault",
    "border_radius": "0", "exclusive_zone": "true", "expand_to_edges": "true",
    "keyboard_interactivity": "OnDemand", "layer": "Top", "margin": "0",
    "opacity": "1.0", "padding": "0", "spacing": "0",
    "size_center": "None", "size_wings": "None",
}


def main():
    ap = argparse.ArgumentParser(description=__doc__.split("\n\n")[0])
    ap.add_argument("--dry-run", action="store_true")
    ap.add_argument("--restart", action="store_true",
                    help="restart cosmic-panel afterwards")
    ap.add_argument("--force", action="store_true",
                    help="overwrite a panel of the same name")
    ap.add_argument("--from", dest="template", default=None,
                    help="existing panel to copy settings from (default Panel, then Dock)")
    args = ap.parse_args()

    name = ctconfig.get("PANEL_NAME", "WordBar")
    if not re.match(r"^[A-Za-z0-9_-]+$", name):
        sys.exit("PANEL_NAME may only contain letters, digits, _ and -")
    if name in ("Panel", "Dock"):
        sys.exit("PANEL_NAME must not be Panel or Dock")
    anchor = ctconfig.get("PANEL_ANCHOR", "Top")
    if anchor not in ("Top", "Bottom", "Left", "Right"):
        sys.exit("PANEL_ANCHOR must be Top, Bottom, Left or Right")
    size = ctconfig.get("PANEL_SIZE", "M")
    if not re.match(r"^(XS|S|M|L|XL|Custom\(\d+\))$", size):
        sys.exit("PANEL_SIZE must be XS, S, M, L, XL or Custom(N)")

    position = ctconfig.get("PANEL_OUTPUT_POSITION", "leftmost")
    if position.lower() == "all":
        output = "All"
    else:
        connector = cosmicpanel.resolve_output(position)
        if not connector:
            sys.exit("could not determine the output; set PANEL_OUTPUT_POSITION to a connector name")
        output = 'Name(%s)' % cosmicpanel.ron_string(connector)

    def ids(key):
        return shlex.split(ctconfig.get(key, ""))

    left, center, right = ids("PANEL_LEFT"), ids("PANEL_CENTER"), ids("PANEL_RIGHT")

    entries = cosmicpanel.read_entries()
    target = cosmicpanel.panel_dir(name)
    if (name in entries or os.path.isdir(target)) and not args.force:
        sys.exit("a panel named %s already exists (use --force to overwrite)" % name)

    values = dict(FALLBACK)
    templates = [args.template] if args.template else ["Panel", "Dock"]
    for tmpl in templates:
        src = cosmicpanel.panel_dir(tmpl)
        if os.path.isdir(src):
            for key in os.listdir(src):
                path = os.path.join(src, key)
                # Skip other tools' backup copies living next to the real keys.
                if os.path.isfile(path) and re.match(r"^[a-z_]+$", key):
                    with open(path, encoding="utf-8") as fh:
                        values[key] = fh.read()
            break

    def ron_items(items):
        return "[%s]" % ", ".join(cosmicpanel.ron_string(i) for i in items)

    values.update({
        "name": cosmicpanel.ron_string(name),
        "anchor": anchor,
        "size": size,
        "output": output,
        "plugins_center": "Some(%s)" % ron_items(center),
        "plugins_wings": "Some((%s, %s))" % (ron_items(left), ron_items(right)),
    })
    new_entries = entries + ([name] if name not in entries else [])

    if args.dry_run:
        print("would write %s:" % target)
        for key in sorted(values):
            print("  %-24s %s" % (key, values[key].strip().replace("\n", " ")))
        print("would set %s to %s" % (cosmicpanel.entries_path(), new_entries))
        return 0

    home = cosmicpanel.cosmic_dir()
    to_save = [os.path.join(home, d) for d in sorted(os.listdir(home))
               if d.startswith(cosmicpanel.PANEL_PREFIX)] if os.path.isdir(home) else []
    dest = cosmicpanel.backup("add-panel", to_save)
    print("backup: %s" % dest)

    for key, value in values.items():
        cosmicpanel.write_atomic(os.path.join(target, key), value)
    cosmicpanel.write_atomic(cosmicpanel.entries_path(), cosmicpanel.ron_list(new_entries))
    print("created panel %s (%s, %s, %s)" % (name, anchor, size, output))

    if args.restart:
        cosmicpanel.restart_panel()
    else:
        print("the panel appears after the next login, or run with --restart")
    return 0


if __name__ == "__main__":
    sys.exit(main())
