#!/usr/bin/env python3
#
# Stream-based realtime scientific data plotter.
# Copyright (c) 2022, Hiroyuki Ohsaki.
# All rights reserved.
#

# automatic speed control
# multiple polots in row

import fileinput
import re
import sys
import time

from perlcompat import die, warn, getopts
import rplot
import tbdump

def usage():
    die(f"""\
usage: {sys.argv[0]} [-vcW] [-x n[,n...]] [-g #] [-w #] [-F #] [file...]
  -v       verbose mode
  -c       curses mode (disable GUI display)
  -x list  exclude specified files from display
  -g val   specify the spacing of vertial grids
  -w val   specify the window range
  -W       automatic window range mode
  -F fps   limit the frequency of display
""")

def process_line(rp, line):
    fields = line.split()
    for n, v in enumerate(fields):
        sr = rp.series(n)
        # Regard the prceeding string as a field label.
        m = re.search(r'^(\w+)=(.+)', v)
        if m:
            label, v = m.groups()
            sr.label = label
        sr.append(float(v))

def need_display(fps=30, last_draw=[0]):
    curtime = time.time()
    # Limit the frame rate by FPS.
    if curtime - last_draw[0] < 1 / fps:
        return False
    last_draw[0] = curtime
    return True

def redraw_display(sc, rp):
    sc.clear()
    rp.draw_series()
    sc.update()

def do_automatic_grid(rp):
    delta = rp.vmax - rp.vmin
    if delta >= 100:
        rp.grid, rp.subgrid = 100, 20
    elif delta >= 10:
        rp.grid, rp.subgrid = 10, 2
    elif delta >= 1:
        rp.grid, rp.subgrid = 1, .2
    elif delta >= .1:
        rp.grid, rp.subgrid = .1, .02

def do_automatic_window(rp, started=[None]):
    if rp.window:
        return
    curtime = time.time()
    # Record the program invokation time.
    if started[0] is None:
        started[0] = curtime
    if curtime - started[0] >= 5:
        # Automatically change to the fixed window mode after 5 seconds.
        rp.window = len(rp.series(0))

def main():
    opt = getopts('vcWx:g:w:F:') or usage()
    use_curses = opt.c
    excluded = [int(s) for s in opt.x.split(',')] if opt.x else []
    grid = float(opt.g) if opt.g else 1
    automatic_grid = True if not opt.g else False
    window = float(opt.w) if opt.w else None
    automatic_window = opt.W
    fps = float(opt.F) if opt.F else 30.

    sc = rplot.Screen(curses=use_curses)
    rp = rplot.Plot(screen=sc, grid=1, subgrid=.2)
    rp.excluded = excluded
    rp.grid = grid
    rp.window = window

    _hook = fileinput.hook_encoded('utf-8', 'backslashreplace')
    for line in fileinput.input(openhook=_hook):
        line = line.rstrip()
        process_line(rp, line)
        if need_display(fps):
            redraw_display(sc, rp)
            if automatic_grid:
                do_automatic_grid(rp)
            if automatic_window:
                do_automatic_window(rp)
    rp.wait()

if __name__ == "__main__":
    main()
