/*
 * Copyright 2012 Google Inc.
 *
 * 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.
 */

// Author: morlovich@google.com (Maksim Orlovich)

#include "net/instaweb/http/public/url_async_fetcher_stats.h"

#include "base/logging.h"
#include "net/instaweb/http/public/async_fetch.h"
#include "pagespeed/kernel/base/statistics.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/string_util.h"
#include "pagespeed/kernel/base/timer.h"
#include "pagespeed/kernel/http/response_headers.h"

namespace {

const int kFetchLatencyUsHistogramMaxValue = 500 * 1000;

const char kFetchLatencyUsHistogram[] = "_fetch_latency_us";

const char kFetches[] = "_fetches";
const char kBytesFetched[] = "_bytes_fetched";
const char kApproxHeaderBytesFetched[] = "_approx_header_bytes_fetched";

}  // namespace

namespace net_instaweb {

class UrlAsyncFetcherStats::StatsAsyncFetch : public SharedAsyncFetch {
 public:
  StatsAsyncFetch(UrlAsyncFetcherStats* stats_fetcher,
                  AsyncFetch* base_fetch)
      : SharedAsyncFetch(base_fetch),
        stats_fetcher_(stats_fetcher),
        size_(0) {
    start_time_us_ = stats_fetcher_->timer_->NowUs();
  }

  virtual ~StatsAsyncFetch() {
  }

  virtual void HandleHeadersComplete() {
    stats_fetcher_->approx_header_bytes_fetched_->Add(
        response_headers()->SizeEstimate());
    SharedAsyncFetch::HandleHeadersComplete();
  }

  virtual void HandleDone(bool success) {
    int64 end_time_us = stats_fetcher_->timer_->NowUs();
    stats_fetcher_->fetch_latency_us_histogram_->Add(
        end_time_us - start_time_us_);
    stats_fetcher_->fetches_->Add(1);
    stats_fetcher_->bytes_fetched_->Add(size_);

    SharedAsyncFetch::HandleDone(success);
    delete this;
  }

  virtual bool HandleWrite(const StringPiece& content,
                           MessageHandler* handler) {
    size_ += content.size();
    return SharedAsyncFetch::HandleWrite(content, handler);
  }

 private:
  UrlAsyncFetcherStats* stats_fetcher_;
  int64 start_time_us_;
  int64 size_;

  DISALLOW_COPY_AND_ASSIGN(StatsAsyncFetch);
};

UrlAsyncFetcherStats::UrlAsyncFetcherStats(StringPiece prefix,
                                           UrlAsyncFetcher* base_fetcher,
                                           Timer* timer,
                                           Statistics* statistics)
    : base_fetcher_(base_fetcher),
      timer_(timer),
      fetch_latency_us_histogram_(statistics->GetHistogram(
          StrCat(prefix, kFetchLatencyUsHistogram))),
      fetches_(statistics->GetVariable(StrCat(prefix, kFetches))),
      bytes_fetched_(statistics->GetVariable(StrCat(prefix, kBytesFetched))),
      approx_header_bytes_fetched_(
          statistics->GetVariable(StrCat(prefix, kApproxHeaderBytesFetched))) {
  fetch_latency_us_histogram_->SetMaxValue(kFetchLatencyUsHistogramMaxValue);

  DCHECK(!base_fetcher->fetch_with_gzip())
      << "A fetcher wrapped by UrlAsyncFetcherStats should not be handling "
      << "gzip itself, but rather letting UrlAsyncFetcherStats handle it";
}

UrlAsyncFetcherStats::~UrlAsyncFetcherStats() {
}

void UrlAsyncFetcherStats::InitStats(StringPiece prefix,
                                     Statistics* statistics) {
  Histogram* fetch_latency_us_histogram =
      statistics->AddHistogram(StrCat(prefix, kFetchLatencyUsHistogram));
  fetch_latency_us_histogram->SetMaxValue(kFetchLatencyUsHistogramMaxValue);
  statistics->AddVariable(StrCat(prefix, kFetches));
  statistics->AddVariable(StrCat(prefix, kBytesFetched));
  statistics->AddVariable(StrCat(prefix, kApproxHeaderBytesFetched));
}

bool UrlAsyncFetcherStats::SupportsHttps() const {
  return base_fetcher_->SupportsHttps();
}


void UrlAsyncFetcherStats::Fetch(const GoogleString& url,
                                 MessageHandler* message_handler,
                                 AsyncFetch* fetch) {
  fetch = EnableInflation(fetch);
  base_fetcher_->Fetch(url, message_handler, new StatsAsyncFetch(this, fetch));
}

int64 UrlAsyncFetcherStats::timeout_ms() {
  return base_fetcher_->timeout_ms();
}

void UrlAsyncFetcherStats::ShutDown() {
  base_fetcher_->ShutDown();
}

}  // namespace net_instaweb
