// 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 "ppapi/shared_impl/var_tracker.h"

#include <string.h>

#include <limits>

#include "base/logging.h"
#include "base/memory/shared_memory.h"
#include "ppapi/shared_impl/host_resource.h"
#include "ppapi/shared_impl/id_assignment.h"
#include "ppapi/shared_impl/proxy_lock.h"
#include "ppapi/shared_impl/resource_var.h"
#include "ppapi/shared_impl/var.h"

namespace ppapi {

VarTracker::VarInfo::VarInfo()
    : var(), ref_count(0), track_with_no_reference_count(0) {}

VarTracker::VarInfo::VarInfo(Var* v, int input_ref_count)
    : var(v), ref_count(input_ref_count), track_with_no_reference_count(0) {}

VarTracker::VarTracker(ThreadMode thread_mode) : last_var_id_(0) {
  if (thread_mode == SINGLE_THREADED)
    thread_checker_.reset(new base::ThreadChecker);
}

VarTracker::~VarTracker() {}

void VarTracker::CheckThreadingPreconditions() const {
  DCHECK(!thread_checker_ || thread_checker_->CalledOnValidThread());
#ifndef NDEBUG
  ProxyLock::AssertAcquired();
#endif
}

int32 VarTracker::AddVar(Var* var) {
  CheckThreadingPreconditions();

  return AddVarInternal(var, ADD_VAR_TAKE_ONE_REFERENCE);
}

Var* VarTracker::GetVar(int32 var_id) const {
  CheckThreadingPreconditions();

  VarMap::const_iterator result = live_vars_.find(var_id);
  if (result == live_vars_.end())
    return NULL;
  return result->second.var.get();
}

Var* VarTracker::GetVar(const PP_Var& var) const {
  CheckThreadingPreconditions();

  if (!IsVarTypeRefcounted(var.type))
    return NULL;
  return GetVar(static_cast<int32>(var.value.as_id));
}

bool VarTracker::AddRefVar(int32 var_id) {
  CheckThreadingPreconditions();

  DLOG_IF(ERROR, !CheckIdType(var_id, PP_ID_TYPE_VAR))
      << var_id << " is not a PP_Var ID.";
  VarMap::iterator found = live_vars_.find(var_id);
  if (found == live_vars_.end()) {
    NOTREACHED();  // Invalid var.
    return false;
  }

  VarInfo& info = found->second;
  if (info.ref_count == 0) {
    // All live vars with no refcount should be tracked objects.
    DCHECK(info.track_with_no_reference_count > 0);
    DCHECK(info.var->GetType() == PP_VARTYPE_OBJECT);

    TrackedObjectGettingOneRef(found);
  }

  // Basic refcount increment.
  info.ref_count++;
  return true;
}

bool VarTracker::AddRefVar(const PP_Var& var) {
  CheckThreadingPreconditions();

  if (!IsVarTypeRefcounted(var.type))
    return true;
  return AddRefVar(static_cast<int32>(var.value.as_id));
}

bool VarTracker::ReleaseVar(int32 var_id) {
  CheckThreadingPreconditions();

  DLOG_IF(ERROR, !CheckIdType(var_id, PP_ID_TYPE_VAR))
      << var_id << " is not a PP_Var ID.";
  VarMap::iterator found = live_vars_.find(var_id);
  if (found == live_vars_.end())
    return false;

  VarInfo& info = found->second;
  if (info.ref_count == 0) {
    NOTREACHED() << "Releasing an object with zero ref";
    return false;
  }
  info.ref_count--;

  if (info.ref_count == 0) {
    // Hold a reference to the Var until it is erased so that we don't re-enter
    // live_vars_.erase() during deletion.
    // TODO(raymes): Make deletion of Vars iterative instead of recursive.
    scoped_refptr<Var> var(info.var);
    if (var->GetType() == PP_VARTYPE_OBJECT) {
      // Objects have special requirements and may not necessarily be released
      // when the refcount goes to 0.
      ObjectGettingZeroRef(found);
    } else {
      // All other var types can just be released.
      DCHECK(info.track_with_no_reference_count == 0);
      var->ResetVarID();
      live_vars_.erase(found);
    }
  }
  return true;
}

bool VarTracker::ReleaseVar(const PP_Var& var) {
  CheckThreadingPreconditions();

  if (!IsVarTypeRefcounted(var.type))
    return false;
  return ReleaseVar(static_cast<int32>(var.value.as_id));
}

int32 VarTracker::AddVarInternal(Var* var, AddVarRefMode mode) {
  // If the plugin manages to create millions of strings.
  if (last_var_id_ == std::numeric_limits<int32>::max() >> kPPIdTypeBits)
    return 0;

  int32 new_id = MakeTypedId(++last_var_id_, PP_ID_TYPE_VAR);
  std::pair<VarMap::iterator, bool> was_inserted =
      live_vars_.insert(std::make_pair(
          new_id, VarInfo(var, mode == ADD_VAR_TAKE_ONE_REFERENCE ? 1 : 0)));
  // We should never insert an ID that already exists.
  DCHECK(was_inserted.second);

  return new_id;
}

VarTracker::VarMap::iterator VarTracker::GetLiveVar(int32 id) {
  return live_vars_.find(id);
}

int VarTracker::GetRefCountForObject(const PP_Var& plugin_object) {
  CheckThreadingPreconditions();

  VarMap::iterator found = GetLiveVar(plugin_object);
  if (found == live_vars_.end())
    return -1;
  return found->second.ref_count;
}

int VarTracker::GetTrackedWithNoReferenceCountForObject(
    const PP_Var& plugin_object) {
  CheckThreadingPreconditions();

  VarMap::iterator found = GetLiveVar(plugin_object);
  if (found == live_vars_.end())
    return -1;
  return found->second.track_with_no_reference_count;
}

// static
bool VarTracker::IsVarTypeRefcounted(PP_VarType type) {
  return type >= PP_VARTYPE_STRING;
}

VarTracker::VarMap::iterator VarTracker::GetLiveVar(const PP_Var& var) {
  return live_vars_.find(static_cast<int32>(var.value.as_id));
}

VarTracker::VarMap::const_iterator VarTracker::GetLiveVar(const PP_Var& var)
    const {
  return live_vars_.find(static_cast<int32>(var.value.as_id));
}

PP_Var VarTracker::MakeArrayBufferPPVar(uint32 size_in_bytes) {
  CheckThreadingPreconditions();

  scoped_refptr<ArrayBufferVar> array_buffer(CreateArrayBuffer(size_in_bytes));
  if (!array_buffer.get())
    return PP_MakeNull();
  return array_buffer->GetPPVar();
}

PP_Var VarTracker::MakeArrayBufferPPVar(uint32 size_in_bytes,
                                        const void* data) {
  CheckThreadingPreconditions();

  ArrayBufferVar* array_buffer = MakeArrayBufferVar(size_in_bytes, data);
  return array_buffer ? array_buffer->GetPPVar() : PP_MakeNull();
}

ArrayBufferVar* VarTracker::MakeArrayBufferVar(uint32 size_in_bytes,
                                               const void* data) {
  CheckThreadingPreconditions();

  ArrayBufferVar* array_buffer(CreateArrayBuffer(size_in_bytes));
  if (!array_buffer)
    return NULL;
  memcpy(array_buffer->Map(), data, size_in_bytes);
  return array_buffer;
}

PP_Var VarTracker::MakeArrayBufferPPVar(uint32 size_in_bytes,
                                        base::SharedMemoryHandle handle) {
  CheckThreadingPreconditions();

  scoped_refptr<ArrayBufferVar> array_buffer(
      CreateShmArrayBuffer(size_in_bytes, handle));
  if (!array_buffer.get())
    return PP_MakeNull();
  return array_buffer->GetPPVar();
}

PP_Var VarTracker::MakeResourcePPVar(PP_Resource pp_resource) {
  CheckThreadingPreconditions();

  ResourceVar* resource_var = MakeResourceVar(pp_resource);
  return resource_var ? resource_var->GetPPVar() : PP_MakeNull();
}

std::vector<PP_Var> VarTracker::GetLiveVars() {
  CheckThreadingPreconditions();

  std::vector<PP_Var> var_vector;
  var_vector.reserve(live_vars_.size());
  for (VarMap::const_iterator iter = live_vars_.begin();
       iter != live_vars_.end();
       ++iter) {
    var_vector.push_back(iter->second.var->GetPPVar());
  }
  return var_vector;
}

void VarTracker::TrackedObjectGettingOneRef(VarMap::const_iterator obj) {
  // Anybody using tracked objects should override this.
  NOTREACHED();
}

void VarTracker::ObjectGettingZeroRef(VarMap::iterator iter) {
  DeleteObjectInfoIfNecessary(iter);
}

bool VarTracker::DeleteObjectInfoIfNecessary(VarMap::iterator iter) {
  if (iter->second.ref_count != 0 ||
      iter->second.track_with_no_reference_count != 0)
    return false;  // Object still alive.
  iter->second.var->ResetVarID();
  live_vars_.erase(iter);
  return true;
}

}  // namespace ppapi
