// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/metrics/stats_counters.h"

namespace base {

StatsCounter::StatsCounter(const std::string& name)
    : counter_id_(-1) {
  // We prepend the name with 'c:' to indicate that it is a counter.
  if (StatsTable::current()) {
    // TODO(mbelshe): name_ construction is racy and it may corrupt memory for
    // static.
    name_ = "c:";
    name_.append(name);
  }
}

StatsCounter::~StatsCounter() {
}

void StatsCounter::Set(int value) {
  int* loc = GetPtr();
  if (loc)
    *loc = value;
}

void StatsCounter::Add(int value) {
  int* loc = GetPtr();
  if (loc)
    (*loc) += value;
}

StatsCounter::StatsCounter()
    : counter_id_(-1) {
}

int* StatsCounter::GetPtr() {
  StatsTable* table = StatsTable::current();
  if (!table)
    return NULL;

  // If counter_id_ is -1, then we haven't looked it up yet.
  if (counter_id_ == -1) {
    counter_id_ = table->FindCounter(name_);
    if (table->GetSlot() == 0) {
      if (!table->RegisterThread("")) {
        // There is no room for this thread.  This thread
        // cannot use counters.
        counter_id_ = 0;
        return NULL;
      }
    }
  }

  // If counter_id_ is > 0, then we have a valid counter.
  if (counter_id_ > 0)
    return table->GetLocation(counter_id_, table->GetSlot());

  // counter_id_ was zero, which means the table is full.
  return NULL;
}


StatsCounterTimer::StatsCounterTimer(const std::string& name) {
  // we prepend the name with 't:' to indicate that it is a timer.
  if (StatsTable::current()) {
    // TODO(mbelshe): name_ construction is racy and it may corrupt memory for
    // static.
    name_ = "t:";
    name_.append(name);
  }
}

StatsCounterTimer::~StatsCounterTimer() {
}

void StatsCounterTimer::Start() {
  if (!Enabled())
    return;
  start_time_ = TimeTicks::Now();
  stop_time_ = TimeTicks();
}

// Stop the timer and record the results.
void StatsCounterTimer::Stop() {
  if (!Enabled() || !Running())
    return;
  stop_time_ = TimeTicks::Now();
  Record();
}

// Returns true if the timer is running.
bool StatsCounterTimer::Running() {
  return Enabled() && !start_time_.is_null() && stop_time_.is_null();
}

// Accept a TimeDelta to increment.
void StatsCounterTimer::AddTime(TimeDelta time) {
  Add(static_cast<int>(time.InMilliseconds()));
}

void StatsCounterTimer::Record() {
  AddTime(stop_time_ - start_time_);
}


StatsRate::StatsRate(const std::string& name)
    : StatsCounterTimer(name),
      counter_(name),
      largest_add_(std::string(" ").append(name).append("MAX")) {
}

StatsRate::~StatsRate() {
}

void StatsRate::Add(int value) {
  counter_.Increment();
  StatsCounterTimer::Add(value);
  if (value > largest_add_.value())
    largest_add_.Set(value);
}

}  // namespace base
