#!/usr/bin/env python3
"Command line program to exercise/test/debug the _internal command."
# Mark Blakeney, Oct 2019

from __future__ import annotations

import argparse
import importlib
import sys
from pathlib import Path
from typing import Any

CMD = '_internal'
GESTURE = 'swipe'
PROG = Path(sys.argv[0]).resolve()
NAME = Path.cwd().name
CACHE = Path.home() / '.cache' / PROG.name


def import_path(pathstr: str) -> Any:
    "Import given module path"
    path = Path(pathstr)
    modname = path.stem.replace('-', '_')
    spec = importlib.util.spec_from_loader(  # type: ignore
        modname,
        importlib.machinery.SourceFileLoader(modname, pathstr),  # type: ignore
    )
    module = importlib.util.module_from_spec(spec)  # type: ignore
    spec.loader.exec_module(module)
    return module


opt = argparse.ArgumentParser(description=__doc__)
opt.add_argument('-c', '--conffile', help='alternative configuration file')
opt.add_argument('-i', '--initial', type=int, help='initial desktop')
opt.add_argument('-C', '--cols', type=int, default=1, help='number of columns')
opt.add_argument(
    '-t', '--text', action='store_true', help='output desktop change in text'
)
opt.add_argument('-n', '--nocache', action='store_true', help='do not use cache')
opt.add_argument('num', type=int, help='number of desktops')
opt.add_argument('action', nargs='?', help='action to perform')
opt.add_argument('-d', '--display', type=int, help=argparse.SUPPRESS)
opt.add_argument('-s', '--set', type=int, help=argparse.SUPPRESS)
args = opt.parse_args()


def showgrid(pos: int, num: int, cols: int) -> None:
    print()
    end = ''
    for i in range(num):
        end = '\n' if (i % cols) == (cols - 1) else ''
        if i == pos:
            print(f' {i:02} ', end=end)
        else:
            print(' ** ', end=end)
    if end != '\n':
        print()


if args.set is not None:
    print(args.set)
    sys.exit(0)

if args.display is not None:
    for i in range(args.num):
        ds = '*' if i == args.display else '-'
        print(f'{i} {ds} -')
    sys.exit(0)

if args.initial is None:
    if args.nocache:
        opt.error('Initial value must be specified')
    if not CACHE.exists():
        opt.error('Need initial desktop specified')
    start = int(CACHE.read_text().strip())
else:
    start = args.initial

lg = import_path(NAME)
icmd = lg.internal_commands[CMD]

icmd.CMDLIST = f'{PROG} -d {start} {args.num}'.split()
icmd.CMDSET = f'{PROG} {args.num} -s'.split()

lg.read_conf(args.conffile, NAME + '.conf')
motions = lg.handlers[GESTURE.upper()].motions
actions = {k: v for k, v in motions.items() if isinstance(v, icmd)}

if not args.action or args.action not in actions:
    opt.error(f'action must be one of {list(actions.keys())}')

cmd = motions[args.action]
print(f'Command "{GESTURE} {args.action} is "{cmd}"')
res = cmd.run(block=True)

if res:
    end = int(res.strip())
    if not args.nocache:
        CACHE.write_text(str(end))
else:
    end = start

if end < 0 or end >= args.num:
    sys.exit(f'Desktop change from {start} to {end}, out of range 0 to <{args.num}!')

if args.text:
    if start != end:
        print(f'Desktop change from {start} to {end}')
    else:
        print('No change')
else:
    showgrid(start, args.num, args.cols)
    showgrid(end, args.num, args.cols)
