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

__version__ = 'saul.pw/VisiData v1.0'

import os
from visidata import *


option('color_diff', 'red', 'color of values different from --diff source')
option('color_diff_add', 'yellow', 'color of rows/columns added to --diff source')


# 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')
    vd().push(vs)
    vs.vd = vd()
    return vs

# for --diff
def makeDiffColorizer(othersheet):
    def colorizeDiffs(sheet, col, row, cellval):
        vcolidx = sheet.visibleCols.index(col)
        rowidx = sheet.rows.index(row)
        if vcolidx < len(othersheet.visibleCols) and rowidx < len(othersheet.rows):
            otherval = othersheet.visibleCols[vcolidx].getValue(othersheet.rows[rowidx])
            if cellval.value != otherval:
                return options.color_diff
        else:
            return options.color_diff_add
    return colorizeDiffs


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=True, 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__)

    for optname, v in vdtui.baseOptions.items():
        name, optval, defaultval, helpstr = v
        if name.startswith('color_') or name.startswith('disp_'):
            continue
        action = 'store_true' if optval is False else 'store'
        parser.add_argument('--' + optname.replace('_', '-'), action=action, dest=optname, default=None, help=helpstr)

    args = parser.parse_args()

    # user customisations in config file in standard location
    fnrc = '~/.visidatarc'
    p = Path(fnrc)
    if p.exists():
        code = compile(open(p.resolve()).read(), p.resolve(), 'exec')
        exec(code, globals())

    vdtui.addGlobals(globals())

    # command-line overrides
    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

    stdinSource = None
    if not sys.stdin.isatty():
        # duplicate stdin for input and reopen tty as stdin
        stdinSource = PathFd('stdin', open(os.dup(0)))
        f = open('/dev/tty')
        os.dup2(f.fileno(), 0)

    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 '=' 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 stdinSource and stdinSource not in inputs:  # '|vd' without explicit '-'
        inputs.append(stdinSource)

    if args.diff:
        vs = openSource(args.diff)
        vd().push(vs)
        Sheet.colorizers.append(Colorizer("cell", 8, makeDiffColorizer(vs)))

    if not args.play:
        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

        vdtui.run(*sources)
        return

    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:
        vd().status = print
        vd().execAsync = lambda func, *args, **kwargs: func(*args, **kwargs) # disable async
        vs.replay_sync()
        if args.output:
            saveSheet(vd().sheets[0], args.output, confirm_overwrite=False)
            sync()
    else:
        vs.replay()
        run()

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