// Copyright 2016 the V8 project 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 "src/inspector/inspected-context.h"

#include "src/debug/debug-interface.h"
#include "src/inspector/injected-script.h"
#include "src/inspector/string-util.h"
#include "src/inspector/v8-console.h"
#include "src/inspector/v8-inspector-impl.h"

#include "include/v8-inspector.h"

namespace v8_inspector {

class InspectedContext::WeakCallbackData {
 public:
  WeakCallbackData(InspectedContext* context, V8InspectorImpl* inspector,
                   int groupId, int contextId)
      : m_context(context),
        m_inspector(inspector),
        m_groupId(groupId),
        m_contextId(contextId) {}

  static void resetContext(const v8::WeakCallbackInfo<WeakCallbackData>& data) {
    // InspectedContext is alive here because weak handler is still alive.
    data.GetParameter()->m_context->m_weakCallbackData = nullptr;
    data.GetParameter()->m_context->m_context.Reset();
    data.SetSecondPassCallback(&callContextCollected);
  }

  static void callContextCollected(
      const v8::WeakCallbackInfo<WeakCallbackData>& data) {
    // InspectedContext can be dead here since anything can happen between first
    // and second pass callback.
    WeakCallbackData* callbackData = data.GetParameter();
    callbackData->m_inspector->contextCollected(callbackData->m_groupId,
                                                callbackData->m_contextId);
    delete callbackData;
  }

 private:
  InspectedContext* m_context;
  V8InspectorImpl* m_inspector;
  int m_groupId;
  int m_contextId;
};

InspectedContext::InspectedContext(V8InspectorImpl* inspector,
                                   const V8ContextInfo& info, int contextId)
    : m_inspector(inspector),
      m_context(info.context->GetIsolate(), info.context),
      m_contextId(contextId),
      m_contextGroupId(info.contextGroupId),
      m_origin(toString16(info.origin)),
      m_humanReadableName(toString16(info.humanReadableName)),
      m_auxData(toString16(info.auxData)) {
  v8::debug::SetContextId(info.context, contextId);
  m_weakCallbackData =
      new WeakCallbackData(this, m_inspector, m_contextGroupId, m_contextId);
  m_context.SetWeak(m_weakCallbackData,
                    &InspectedContext::WeakCallbackData::resetContext,
                    v8::WeakCallbackType::kParameter);
  if (!info.hasMemoryOnConsole) return;
  v8::Context::Scope contextScope(info.context);
  v8::HandleScope handleScope(info.context->GetIsolate());
  v8::Local<v8::Object> global = info.context->Global();
  v8::Local<v8::Value> console;
  if (global->Get(info.context, toV8String(m_inspector->isolate(), "console"))
          .ToLocal(&console) &&
      console->IsObject()) {
    m_inspector->console()->installMemoryGetter(
        info.context, v8::Local<v8::Object>::Cast(console));
  }
}

InspectedContext::~InspectedContext() {
  // If we destory InspectedContext before weak callback is invoked then we need
  // to delete data here.
  if (!m_context.IsEmpty()) delete m_weakCallbackData;
}

// static
int InspectedContext::contextId(v8::Local<v8::Context> context) {
  return v8::debug::GetContextId(context);
}

v8::Local<v8::Context> InspectedContext::context() const {
  return m_context.Get(isolate());
}

v8::Isolate* InspectedContext::isolate() const {
  return m_inspector->isolate();
}

bool InspectedContext::isReported(int sessionId) const {
  return m_reportedSessionIds.find(sessionId) != m_reportedSessionIds.cend();
}

void InspectedContext::setReported(int sessionId, bool reported) {
  if (reported)
    m_reportedSessionIds.insert(sessionId);
  else
    m_reportedSessionIds.erase(sessionId);
}

InjectedScript* InspectedContext::getInjectedScript(int sessionId) {
  auto it = m_injectedScripts.find(sessionId);
  return it == m_injectedScripts.end() ? nullptr : it->second.get();
}

InjectedScript* InspectedContext::createInjectedScript(int sessionId) {
  std::unique_ptr<InjectedScript> injectedScript =
      v8::base::make_unique<InjectedScript>(this, sessionId);
  CHECK(m_injectedScripts.find(sessionId) == m_injectedScripts.end());
  m_injectedScripts[sessionId] = std::move(injectedScript);
  return getInjectedScript(sessionId);
}

void InspectedContext::discardInjectedScript(int sessionId) {
  m_injectedScripts.erase(sessionId);
}

bool InspectedContext::addInternalObject(v8::Local<v8::Object> object,
                                         V8InternalValueType type) {
  if (m_internalObjects.IsEmpty()) {
    m_internalObjects.Reset(isolate(), v8::debug::WeakMap::New(isolate()));
  }
  return !m_internalObjects.Get(isolate())
              ->Set(m_context.Get(isolate()), object,
                    v8::Integer::New(isolate(), static_cast<int>(type)))
              .IsEmpty();
}

V8InternalValueType InspectedContext::getInternalType(
    v8::Local<v8::Object> object) {
  if (m_internalObjects.IsEmpty()) return V8InternalValueType::kNone;
  v8::Local<v8::Value> typeValue;
  if (!m_internalObjects.Get(isolate())
           ->Get(m_context.Get(isolate()), object)
           .ToLocal(&typeValue) ||
      !typeValue->IsUint32()) {
    return V8InternalValueType::kNone;
  }
  return static_cast<V8InternalValueType>(typeValue.As<v8::Int32>()->Value());
}

}  // namespace v8_inspector
