// Copyright (c) 2012 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 "content/renderer/dom_storage/dom_storage_cached_area.h"

#include "base/basictypes.h"
#include "base/metrics/histogram.h"
#include "base/time/time.h"
#include "content/common/dom_storage/dom_storage_map.h"
#include "content/renderer/dom_storage/dom_storage_proxy.h"

namespace content {

DOMStorageCachedArea::DOMStorageCachedArea(int64 namespace_id,
                                           const GURL& origin,
                                           DOMStorageProxy* proxy)
    : ignore_all_mutations_(false),
      namespace_id_(namespace_id),
      origin_(origin),
      proxy_(proxy),
      weak_factory_(this) {}

DOMStorageCachedArea::~DOMStorageCachedArea() {}

unsigned DOMStorageCachedArea::GetLength(int connection_id) {
  PrimeIfNeeded(connection_id);
  return map_->Length();
}

base::NullableString16 DOMStorageCachedArea::GetKey(int connection_id,
                                                    unsigned index) {
  PrimeIfNeeded(connection_id);
  return map_->Key(index);
}

base::NullableString16 DOMStorageCachedArea::GetItem(
    int connection_id,
    const base::string16& key) {
  PrimeIfNeeded(connection_id);
  return map_->GetItem(key);
}

bool DOMStorageCachedArea::SetItem(int connection_id,
                                   const base::string16& key,
                                   const base::string16& value,
                                   const GURL& page_url) {
  // A quick check to reject obviously overbudget items to avoid
  // the priming the cache.
  if (key.length() + value.length() > kPerStorageAreaQuota)
    return false;

  PrimeIfNeeded(connection_id);
  base::NullableString16 unused;
  if (!map_->SetItem(key, value, &unused))
    return false;

  // Ignore mutations to 'key' until OnSetItemComplete.
  ignore_key_mutations_[key]++;
  proxy_->SetItem(
      connection_id, key, value, page_url,
      base::Bind(&DOMStorageCachedArea::OnSetItemComplete,
                 weak_factory_.GetWeakPtr(), key));
  return true;
}

void DOMStorageCachedArea::RemoveItem(int connection_id,
                                      const base::string16& key,
                                      const GURL& page_url) {
  PrimeIfNeeded(connection_id);
  base::string16 unused;
  if (!map_->RemoveItem(key, &unused))
    return;

  // Ignore mutations to 'key' until OnRemoveItemComplete.
  ignore_key_mutations_[key]++;
  proxy_->RemoveItem(
      connection_id, key, page_url,
      base::Bind(&DOMStorageCachedArea::OnRemoveItemComplete,
                 weak_factory_.GetWeakPtr(), key));
}

void DOMStorageCachedArea::Clear(int connection_id, const GURL& page_url) {
  // No need to prime the cache in this case.
  Reset();
  map_ = new DOMStorageMap(kPerStorageAreaQuota);

  // Ignore all mutations until OnClearComplete time.
  ignore_all_mutations_ = true;
  proxy_->ClearArea(connection_id,
                    page_url,
                    base::Bind(&DOMStorageCachedArea::OnClearComplete,
                               weak_factory_.GetWeakPtr()));
}

void DOMStorageCachedArea::ApplyMutation(
    const base::NullableString16& key,
    const base::NullableString16& new_value) {
  if (!map_.get() || ignore_all_mutations_)
    return;

  if (key.is_null()) {
    // It's a clear event.
    scoped_refptr<DOMStorageMap> old = map_;
    map_ = new DOMStorageMap(kPerStorageAreaQuota);

    // We have to retain local additions which happened after this
    // clear operation from another process.
    std::map<base::string16, int>::iterator iter =
        ignore_key_mutations_.begin();
    while (iter != ignore_key_mutations_.end()) {
      base::NullableString16 value = old->GetItem(iter->first);
      if (!value.is_null()) {
        base::NullableString16 unused;
        map_->SetItem(iter->first, value.string(), &unused);
      }
      ++iter;
    }
    return;
  }

  // We have to retain local changes.
  if (should_ignore_key_mutation(key.string()))
    return;

  if (new_value.is_null()) {
    // It's a remove item event.
    base::string16 unused;
    map_->RemoveItem(key.string(), &unused);
    return;
  }

  // It's a set item event.
  // We turn off quota checking here to accomodate the over budget
  // allowance that's provided in the browser process.
  base::NullableString16 unused;
  map_->set_quota(kint32max);
  map_->SetItem(key.string(), new_value.string(), &unused);
  map_->set_quota(kPerStorageAreaQuota);
}

size_t DOMStorageCachedArea::MemoryBytesUsedByCache() const {
  return map_.get() ? map_->bytes_used() : 0;
}

void DOMStorageCachedArea::Prime(int connection_id) {
  DCHECK(!map_.get());

  // The LoadArea method is actually synchronous, but we have to
  // wait for an asyncly delivered message to know when incoming
  // mutation events should be applied. Our valuemap is plucked
  // from ipc stream out of order, mutations in front if it need
  // to be ignored.

  // Ignore all mutations until OnLoadComplete time.
  ignore_all_mutations_ = true;
  DOMStorageValuesMap values;
  base::TimeTicks before = base::TimeTicks::Now();
  proxy_->LoadArea(connection_id,
                   &values,
                   base::Bind(&DOMStorageCachedArea::OnLoadComplete,
                              weak_factory_.GetWeakPtr()));
  base::TimeDelta time_to_prime = base::TimeTicks::Now() - before;
  // Keeping this histogram named the same (without the ForRenderer suffix)
  // to maintain histogram continuity.
  UMA_HISTOGRAM_TIMES("LocalStorage.TimeToPrimeLocalStorage",
                      time_to_prime);
  map_ = new DOMStorageMap(kPerStorageAreaQuota);
  map_->SwapValues(&values);

  size_t local_storage_size_kb = map_->bytes_used() / 1024;
  // Track localStorage size, from 0-6MB. Note that the maximum size should be
  // 5MB, but we add some slop since we want to make sure the max size is always
  // above what we see in practice, since histograms can't change.
  UMA_HISTOGRAM_CUSTOM_COUNTS("LocalStorage.RendererLocalStorageSizeInKB",
                              local_storage_size_kb,
                              0, 6 * 1024, 50);
  if (local_storage_size_kb < 100) {
    UMA_HISTOGRAM_TIMES(
        "LocalStorage.RendererTimeToPrimeLocalStorageUnder100KB",
        time_to_prime);
  } else if (local_storage_size_kb < 1000) {
    UMA_HISTOGRAM_TIMES(
        "LocalStorage.RendererTimeToPrimeLocalStorage100KBTo1MB",
        time_to_prime);
  } else {
    UMA_HISTOGRAM_TIMES(
        "LocalStorage.RendererTimeToPrimeLocalStorage1MBTo5MB",
        time_to_prime);
  }
}

void DOMStorageCachedArea::Reset() {
  map_ = NULL;
  weak_factory_.InvalidateWeakPtrs();
  ignore_key_mutations_.clear();
  ignore_all_mutations_ = false;
}

void DOMStorageCachedArea::OnLoadComplete(bool success) {
  DCHECK(success);
  DCHECK(ignore_all_mutations_);
  ignore_all_mutations_ = false;
}

void DOMStorageCachedArea::OnSetItemComplete(const base::string16& key,
                                             bool success) {
  if (!success) {
    Reset();
    return;
  }
  std::map<base::string16, int>::iterator found =
      ignore_key_mutations_.find(key);
  DCHECK(found != ignore_key_mutations_.end());
  if (--found->second == 0)
    ignore_key_mutations_.erase(found);
}

void DOMStorageCachedArea::OnRemoveItemComplete(const base::string16& key,
                                                bool success) {
  DCHECK(success);
  std::map<base::string16, int>::iterator found =
      ignore_key_mutations_.find(key);
  DCHECK(found != ignore_key_mutations_.end());
  if (--found->second == 0)
    ignore_key_mutations_.erase(found);
}

void DOMStorageCachedArea::OnClearComplete(bool success) {
  DCHECK(success);
  DCHECK(ignore_all_mutations_);
  ignore_all_mutations_ = false;
}

}  // namespace content
