#!/usr/bin/env python3
#
# Usage: $0 [<options>] [<input> ...]
#        $0 [<options>] --play <cmdlog> [--batch] [-w <waitsecs>] [-o <output>] [field=value ...]

__version__ = '1.5.2'
__version_info__ = 'saul.pw/VisiData v' + __version__

import os
from visidata import *


# for --play
def eval_vd(logpath, *args, **kwargs):
    'Instantiate logpath with args/kwargs replaced and replay all commands.'
    log = logpath.read_text().format(*args, **kwargs)
    src = PathFd(logpath.fqpn, io.StringIO(log), filesize=len(log))
    vs = openSource(src, filetype='vd')
    vs.name += '_vd'
    vd().push(vs)
    vs.vd = vd()
    return vs


def main():
    'Open the given sources using the VisiData interface.'
    import argparse
    parser = argparse.ArgumentParser(description=__doc__)

    parser.add_argument('inputs', nargs='*', help='initial sources')
    parser.add_argument('-f', dest='filetype', default='', help='uses loader for filetype instead of file extension')
    parser.add_argument('-y', dest='confirm_overwrite', default=None, action='store_false', help='overwrites existing files without confirmation')
    parser.add_argument('-p', '--play', dest='play', default=None, help='replays a saved .vd file within the interface')
    parser.add_argument('-b', '--batch', dest='batch', action='store_true', default=False, help='replays in batch mode (with no interface and all status sent to stdout)')
    parser.add_argument('-o', '--output', dest='output', default=None, help='saves the final visible sheet to output (as .tsv) at the end of replay')
    parser.add_argument('-w', dest='replay_wait', default=0, help='time to wait between replayed commands, in seconds')
    parser.add_argument('-d', dest='delimiter', help='delimiter to use for tsv filetype')
    parser.add_argument('--diff', dest='diff', default=None, help='show diffs from all sheets against this source')
    parser.add_argument('-v', '--version', action='version', version=__version_info__)

    for optname in vdtui.options.keys('global'):
        if optname.startswith('color_') or optname.startswith('disp_'):
            continue
        action = 'store_true' if vdtui.options[optname] is False else 'store'
        parser.add_argument('--' + optname.replace('_', '-'), action=action, dest=optname, default=None, help=options._opts._get(optname).helpstr)

    args = parser.parse_args()

    sys.path.append(Path(options.visidata_dir).resolve())

    # user customisations in config file in standard location
    vdtui.loadConfigFile('~/.visidatarc', globals())
    vdtui.addGlobals(globals())

    vdtui.globalCommand('gO', 'open-config', 'vd.push(vdtui.TextSheet("visidatarc", Path("~/.visidatarc")))')

    # apply command-line overrides after .visidatarc
    for optname, optval in vars(args).items():
        if optval is not None and optname not in ['inputs', 'play', 'batch', 'output', 'diff']:
            vdtui.options[optname] = optval

    # fetch motd after options parsing/setting
    domotd()

    flPipedData = not sys.stdin.isatty()

    # always duplicate stdin for input and reopen tty as stdin
    try:
        stdin = open(os.dup(0))
        f = open('/dev/tty')
        os.dup2(f.fileno(), 0)
        vd().stdin = stdin
    except Exception as e:
        print(e)
        vd().stdin = sys.stdin

    stdinSource = PathFd('-', vd().stdin)

    # parse args, including +4:3 starting row:col
    startrow, startcol = None, None
    fmtargs = []
    fmtkwargs = {}
    inputs = []
    for arg in args.inputs:
        if arg.startswith('+'):  # position cursor at start
            if ':' in arg:
                startrow, startcol = arg[1:].split(':')
            else:
                startrow = arg[1:]
        elif args.play and '=' in arg:
            # parse 'key=value' pairs for formatting cmdlog template in replay mode
            k, v = arg.split('=')
            fmtkwargs[k] = v
        elif arg == '-':
            inputs.append(stdinSource)
        else:
            inputs.append(arg)
            fmtargs.append(arg)

    if args.diff:
        vs = openSource(args.diff)
        vd().push(vs)
        setDiffSheet(vs)

    if args.batch:
        vd().status = lambda *args, **kwargs: print(*args, file=sys.stderr)  # ignore kwargs (like priority)
        vd().execAsync = lambda func, *args, **kwargs: func(*args, **kwargs) # disable async

    if not args.play:
        if flPipedData and not inputs:  # '|vd' without explicit '-'
            inputs.append(stdinSource)

        if not inputs:
            inputs = ['.']

        sources = []
        for src in inputs:
            vs = openSource(src)
            vdtui.vd().cmdlog.openHook(vs, src)
            sources.append(vs)
            if startrow is not None:
                vs.cursorRowIndex = int(startrow)-1
            if startcol is not None:
                vs.cursorVisibleColIndex = int(startcol)-1

        if args.batch:
            vd().sheets = sources
            sources[0].reload()
        else:
            vdtui.run(*sources)
    else:
        if args.play == '-':
            vdfile = stdinSource
            assert isinstance(vdfile, PathFd)
            vdfile.name = 'stdin.vd'
        else:
            vdfile = Path(args.play)

        vs = eval_vd(vdfile, *fmtargs, **fmtkwargs)
        if args.batch:
            vs.replay_sync()
        else:
            vs.replay()
            run()

    if args.output and vd().sheets:
        saveSheets(args.output, vd().sheets[0], confirm_overwrite=False)
        sync()

if __name__ == '__main__':
    vdtui.status(__version_info__)
    main()
    sys.stderr.flush()
    os._exit(0)  # cleanup can be expensive with large datasets
