/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef SRC_BASE_HISTOGRAM_INL_H_
#define SRC_BASE_HISTOGRAM_INL_H_

#include "histogram.h"

#include "utils.h"

#include <algorithm>
#include <cmath>
#include <limits>
#include <ostream>

namespace art {

template <class Value> inline void Histogram<Value>::AddValue(Value value) {
  CHECK_GE(value, 0.0);
  if (value >= max_) {
    Value new_max = ((value + 1) / bucket_width_ + 1) * bucket_width_;
    DCHECK_GT(new_max, max_);
    GrowBuckets(new_max);
  }

  BucketiseValue(value);
  new_values_added_ = true;
}

template <class Value>
inline Histogram<Value>::Histogram(const std::string name)
    : kAdjust(1000),
      kBucketWidth(5),
      kInitialBucketCount(10),
      bucket_width_(kBucketWidth),
      bucket_count_(kInitialBucketCount) {
  name_ = name;
  Reset();
}

template <class Value>
inline void Histogram<Value>::GrowBuckets(Value new_max) {
  while (max_ < new_max) {
    max_ += bucket_width_;
    ranges_.push_back(max_);
    frequency_.push_back(0);
    bucket_count_++;
  }
}

template <class Value> inline size_t Histogram<Value>::FindBucket(Value val) {
  // Since this is only a linear histogram, bucket index can be found simply with
  // dividing the value by the bucket width.
  DCHECK_GE(val, min_);
  DCHECK_LE(val, max_);
  size_t bucket_idx = static_cast<size_t>((double)(val - min_) / bucket_width_);
  DCHECK_GE(bucket_idx, 0ul);
  DCHECK_LE(bucket_idx, bucket_count_);
  return bucket_idx;
}

template <class Value>
inline void Histogram<Value>::BucketiseValue(Value value) {
  CHECK_LT(value, max_);
  sum_ += value;
  sum_of_squares_ += value * value;
  size_t bucket_idx = FindBucket(value);
  sample_size_++;
  if (value > max_value_added_) {
    max_value_added_ = value;
  }
  if (value < min_value_added_) {
    min_value_added_ = value;
  }
  frequency_[bucket_idx]++;
}

template <class Value> inline void Histogram<Value>::Initialize() {
  DCHECK_GT(bucket_count_, 0ul);
  size_t idx = 0;
  for (; idx < bucket_count_; idx++) {
    ranges_.push_back(min_ + static_cast<Value>(idx) * (bucket_width_));
    frequency_.push_back(0);
  }
  // Cumulative frequency and ranges has a length of 1 over frequency.
  ranges_.push_back(min_ + idx * bucket_width_);
  max_ = bucket_width_ * bucket_count_;
}

template <class Value> inline void Histogram<Value>::Reset() {
  bucket_width_ = kBucketWidth;
  bucket_count_ = kInitialBucketCount;
  max_ = bucket_width_ * bucket_count_;
  sum_of_squares_ = 0;
  sample_size_ = 0;
  min_ = 0;
  sum_ = 0;
  min_value_added_ = std::numeric_limits<Value>::max();
  max_value_added_ = std::numeric_limits<Value>::min();
  new_values_added_ = false;
  ranges_.clear();
  frequency_.clear();
  cumulative_freq_.clear();
  cumulative_perc_.clear();
  Initialize();
}

template <class Value> inline void Histogram<Value>::BuildRanges() {
  for (size_t idx = 0; idx < bucket_count_; ++idx) {
    ranges_.push_back(min_ + idx * bucket_width_);
  }
}

template <class Value> inline double Histogram<Value>::Mean() const {
  DCHECK_GT(sample_size_, 0ull);
  return static_cast<double>(sum_) / static_cast<double>(sample_size_);
}

template <class Value> inline double Histogram<Value>::Variance() const {
  DCHECK_GT(sample_size_, 0ull);
  // Using algorithms for calculating variance over a population:
  // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
  Value sum_squared = sum_ * sum_;
  double sum_squared_by_n_squared =
      static_cast<double>(sum_squared) /
      static_cast<double>(sample_size_ * sample_size_);
  double sum_of_squares_by_n =
      static_cast<double>(sum_of_squares_) / static_cast<double>(sample_size_);
  return sum_of_squares_by_n - sum_squared_by_n_squared;
}

template <class Value>
inline void Histogram<Value>::PrintBins(std::ostream &os) {
  DCHECK_GT(sample_size_, 0ull);
  DCHECK(!new_values_added_);
  size_t bin_idx = 0;
  while (bin_idx < cumulative_freq_.size()) {
    if (bin_idx > 0 &&
        cumulative_perc_[bin_idx] == cumulative_perc_[bin_idx - 1]) {
      bin_idx++;
      continue;
    }
    os << ranges_[bin_idx] << ": " << cumulative_freq_[bin_idx] << "\t"
       << cumulative_perc_[bin_idx] * 100.0 << "%\n";
    bin_idx++;
  }
}

template <class Value>
inline void Histogram<Value>::PrintConfidenceIntervals(std::ostream &os,
                                                       double interval) const {
  DCHECK_GT(interval, 0);
  DCHECK_LT(interval, 1.0);

  double per_0 = (1.0 - interval) / 2.0;
  double per_1 = per_0 + interval;
  os << Name() << ":\t";
  TimeUnit unit = GetAppropriateTimeUnit(Mean() * kAdjust);
  os << (interval * 100) << "% C.I. "
     << FormatDuration(Percentile(per_0) * kAdjust, unit);
  os << "-" << FormatDuration(Percentile(per_1) * kAdjust, unit) << " ";
  os << "Avg: " << FormatDuration(Mean() * kAdjust, unit) << " Max: ";
  os << FormatDuration(Max() * kAdjust, unit) << "\n";
}

template <class Value> inline void Histogram<Value>::BuildCDF() {
  DCHECK_EQ(cumulative_freq_.size(), 0ull);
  DCHECK_EQ(cumulative_perc_.size(), 0ull);
  uint64_t accumulated = 0;

  cumulative_freq_.push_back(accumulated);
  cumulative_perc_.push_back(0.0);
  for (size_t idx = 0; idx < frequency_.size(); idx++) {
    accumulated += frequency_[idx];
    cumulative_freq_.push_back(accumulated);
    cumulative_perc_.push_back(static_cast<double>(accumulated) /
                               static_cast<double>(sample_size_));
  }
  DCHECK_EQ(*(cumulative_freq_.end() - 1), sample_size_);
  DCHECK_EQ(*(cumulative_perc_.end() - 1), 1.0);
}

template <class Value> inline void Histogram<Value>::CreateHistogram() {
  DCHECK_GT(sample_size_, 0ull);

  // Create a histogram only if new values are added.
  if (!new_values_added_)
    return;

  // Reset cumulative values in case this is not the first time creating histogram.
  cumulative_freq_.clear();
  cumulative_perc_.clear();
  BuildCDF();
  new_values_added_ = false;
}

template <class Value>
inline double Histogram<Value>::Percentile(double per) const {
  DCHECK_GT(cumulative_perc_.size(), 0ull);
  size_t idx, upper_idx = 0, lower_idx = 0;
  for (idx = 0; idx < cumulative_perc_.size(); idx++) {

    if (per <= cumulative_perc_[idx]) {
      upper_idx = idx;
      break;
    }

    if (per >= cumulative_perc_[idx] && idx != 0 &&
        cumulative_perc_[idx] != cumulative_perc_[idx - 1]) {
      lower_idx = idx;
    }
  }

  double upper_value = static_cast<double>(ranges_[upper_idx]);
  double lower_value = static_cast<double>(ranges_[lower_idx]);

  double lower_perc = cumulative_perc_[lower_idx];
  double upper_perc = cumulative_perc_[upper_idx];

  if (per == lower_perc) {
    return lower_value;
  }
  if (per == upper_perc) {
    return upper_value;
  }
  DCHECK_GT(upper_perc, lower_perc);

  double value = lower_value + (upper_value - lower_value) *
                               (per - lower_perc) / (upper_perc - lower_perc);

  if (value < min_value_added_) {
    value = min_value_added_;
  } else if (value > max_value_added_) {
    value = max_value_added_;
  }

  return value;
}

}  // namespace art
#endif  // SRC_BASE_HISTOGRAM_INL_H_

