#!/usr/bin/python3

from numpy import zeros, sqrt
import math, time

import asteval

class ArgEval:
    '''
    Helper to transform (a list of) string-based arguments into
    pythonic data types (floats, ints, lists, dict, ...) while
    applying a mild form of expression evaluation based on
    `lmfit`'s `asteval`.

    The "source code" is loaded from a single line. It's expected
    to either be a single expression, or a short-form of a Python
    dictionary of the form "foo:..,bar:..." (representing the
    long form "{'foo': ..., 'bar': ...}").
    '''
    def __init__(self, line: str, *keys, **kfmt):
        '''
        Args:
          line: The source code
          *keys: list of strings representing possible keys in
            dictionaries. For every "key" a corresponding symbol
            by the same name, and with the string as a content,
            will be preset in the `asteval` interpreter.
          **kfmt: Alternative way of specifying the keys. Each
            key of `kfmt` will be treated as one of the `*keys`,
            i.e. a corresponding symbol will be created in the
            interpreter; 
        '''
        pass
        

class FpsCounter:
    def __init__(self, pts=100, label="FPS"):
        self.told = time.time()
        self.told_diff = 0
        self.fps_history = zeros(pts)
        self.ji = 0
        self.label = label
        
    def mark(self):
        tnow = time.time()
        tdiff = 1/(tnow-self.told)
        self.fps_history[self.ji] = tdiff
        self.ji = (self.ji+1)%self.fps_history.shape[0]
        self.told = tnow

    @property
    def fps(self):
        return self.fps_history.mean()

    @property
    def jitter(self):
        return sqrt( ((self.fps_history-self.fps_history.mean())**2).mean() )

    def __str__(self):
        return "%s: %2.1f ± %d Hz" % (self.label, self.fps, math.ceil(self.jitter))


    def __repr__(self):
        return str(self)
