# Path: tapes/reservoir.py
# class ExponentiallyDecayingReservoir(object):
#     def __init__(self, size=_DEFAULT_SIZE, alpha=_DEFAULT_ALPHA):
#         self.size = size
#         self.alpha = alpha
#         self.start_time = time()
#         self.next_scale_time = self.start_time + _RESCALE_THRESHOLD
#         self.values = SortedDict()
# 
#     def _rescale_if_needed(self):
#         now = time()
#         if now > self.next_scale_time:
#             self.next_scale_time = now + _RESCALE_THRESHOLD
#             old_start_time = self.start_time
#             self.start_time = now
#             scaling_factor = exp(-self.alpha * (self.start_time - old_start_time))
# 
#             self.values = SortedDict(
#                 (priority * scaling_factor, _WeightedSample(sample.value, sample.weight * scaling_factor))
#                 for priority, sample in self.values.items()
#             )
# 
#     def update(self, value):
#         self._rescale_if_needed()
#         timestamp = time()
#         item_weight = exp(self.alpha * (timestamp - self.start_time))
#         sample = _WeightedSample(value, item_weight)
#         priority = item_weight / random()
# 
#         if len(self.values) < self.size:
#             self.values[priority] = sample
#         else:
#             first_key = next(self.values.iterkeys())
#             if first_key < priority:
#                 self.values.setdefault(priority, sample)
#                 del self.values[first_key]
# 
#     def get_snapshot(self):
#         return _WeightedSnapshot(self.values.values())
# 
# Path: tapes/local/stats.py
# class Stat(object):
# 
#     @abc.abstractmethod
#     def get_values(self):
#         raise NotImplementedError()


from tapes.reservoir import ExponentiallyDecayingReservoir
from .stats import Stat


class Histogram(Stat):
    def __init__(self):
        self.count = 0
        self.reservoir = ExponentiallyDecayingReservoir()

    def update(self, value):
        self.count += 1
        self.reservoir.update(value)

    def get_values(self):
        snapshot = self.reservoir.get_snapshot()
        return {
            'count': self.count,
            'min': snapshot.get_min(),
            'max': snapshot.get_max(),
            'mean': snapshot.get_mean(),
            'stddev': snapshot.get_sd(),
            'q50': snapshot.get_quantile(0.5),
            'q75': snapshot.get_quantile(0.75),

# Path: tapes/reservoir.py
# class ExponentiallyDecayingReservoir(object):
#     def __init__(self, size=_DEFAULT_SIZE, alpha=_DEFAULT_ALPHA):
#         self.size = size
#         self.alpha = alpha
#         self.start_time = time()
#         self.next_scale_time = self.start_time + _RESCALE_THRESHOLD
#         self.values = SortedDict()
# 
#     def _rescale_if_needed(self):
#         now = time()
#         if now > self.next_scale_time:
#             self.next_scale_time = now + _RESCALE_THRESHOLD
#             old_start_time = self.start_time
#             self.start_time = now
#             scaling_factor = exp(-self.alpha * (self.start_time - old_start_time))
# 
#             self.values = SortedDict(
#                 (priority * scaling_factor, _WeightedSample(sample.value, sample.weight * scaling_factor))
#                 for priority, sample in self.values.items()
#             )
# 
#     def update(self, value):
#         self._rescale_if_needed()
#         timestamp = time()
#         item_weight = exp(self.alpha * (timestamp - self.start_time))
#         sample = _WeightedSample(value, item_weight)
#         priority = item_weight / random()
# 
#         if len(self.values) < self.size:
#             self.values[priority] = sample
#         else:
#             first_key = next(self.values.iterkeys())
#             if first_key < priority:
#                 self.values.setdefault(priority, sample)
#                 del self.values[first_key]
# 
#     def get_snapshot(self):
#         return _WeightedSnapshot(self.values.values())
# 
# Path: tapes/local/stats.py
# class Stat(object):
# 
#     @abc.abstractmethod
#     def get_values(self):
#         raise NotImplementedError()


# Path: tapes/local/histogram.py
from tapes.reservoir import ExponentiallyDecayingReservoir
from .stats import Stat



class Histogram(Stat):
    def __init__(self):
        self.count = 0
        self.reservoir = ExponentiallyDecayingReservoir()

    def update(self, value):
        self.count += 1
        self.reservoir.update(value)

    def get_values(self):
        snapshot = self.reservoir.get_snapshot()
        return {
            'count': self.count,
            'min': snapshot.get_min(),
            'max': snapshot.get_max(),
            'mean': snapshot.get_mean(),
            'stddev': snapshot.get_sd(),
            'q50': snapshot.get_quantile(0.5),
            'q75': snapshot.get_quantile(0.75),

            'q95': snapshot.get_quantile(0.95),