# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
from __python__ import bound_methods, hash_literals

from read_book.globals import ui_operations

THRESHOLD = 5
FILTER_THRESHOLD = 25
MAX_SAMPLES = 256


class Timers:
    def __init__(self):
        self.reset_read_timer()
        self.rates = []
        self.average = self.stddev = 0
        self.chapter_times = v'{}'
        self.current_chapter = None

    def start_book(self, book):
        self.reset_read_timer()
        self.rates = []
        self.chapter_times = v'{}'
        self.current_chapter = None
        if book?.saved_reading_rates?.rates:
            self.rates = book.saved_reading_rates.rates.slice(0)
            self.calculate()
        if book?.saved_reading_rates?.chapter_times:
            self.chapter_times = Object.assign(v'{}', book.saved_reading_rates.chapter_times)

    def set_chapter(self, name):
        self.current_chapter = name

    def reset_read_timer(self):
        self.last_scroll_at = None

    def calculate(self):
        rates = self.rates
        rlen = rates.length
        if rlen >= THRESHOLD:
            avg = 0
            for v'var i = 0; i < rlen; i++':
                avg += rates[i]
            avg /= rlen
            self.average = avg
            sq = 0
            for v'var i = 0; i < rlen; i++':
                x = rates[i] - avg
                sq += x * x
            self.stddev = Math.sqrt(sq / (rlen - 1))
        else:
            self.average = self.stddev = 0

    def on_human_scroll(self, amt_scrolled):
        last_scroll_at = self.last_scroll_at
        self.last_scroll_at = now = window.performance.now()
        if last_scroll_at is None:
            return
        time_since_last_scroll = (now - last_scroll_at) / 1000
        if time_since_last_scroll <= 0 or time_since_last_scroll >= 300:
            return
        if self.current_chapter:
            self.chapter_times[self.current_chapter] = (self.chapter_times[self.current_chapter] or 0) + time_since_last_scroll
        if time_since_last_scroll < 2:
            return
        rate = amt_scrolled / time_since_last_scroll
        if self.rates.length >= FILTER_THRESHOLD and Math.abs(rate - self.average) > 2 * self.stddev:
            return
        if self.rates.length >= MAX_SAMPLES:
            self.rates.shift()
        self.rates.push(rate)
        self.calculate()
        if ui_operations.update_reading_rates:
            ui_operations.update_reading_rates({'rates': self.rates.slice(0), 'chapter_times': Object.assign(v'{}', self.chapter_times)})

    def time_for(self, length):
        if length >= 0 and self.rates.length >= THRESHOLD and self.average > 0:
            return length / self.average
        return None
