/*
 * Copyright (C) 2012 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.h"

#include <memory>
#include <utility>

#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
#include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_string_list.h"
#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/inspector/inspected_frames.h"
#include "third_party/blink/renderer/core/inspector/v8_inspector_string.h"
#include "third_party/blink/renderer/modules/indexed_db_names.h"
#include "third_party/blink/renderer/modules/indexeddb/global_indexed_db.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_cursor.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_cursor_with_value.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_database.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_factory.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_index.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key_path.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key_range.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_metadata.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_object_store.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_open_db_request.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_request.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_transaction.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_cursor.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"

using blink::protocol::Array;
using blink::protocol::IndexedDB::DatabaseWithObjectStores;
using blink::protocol::IndexedDB::DataEntry;
using blink::protocol::IndexedDB::Key;
using blink::protocol::IndexedDB::KeyPath;
using blink::protocol::IndexedDB::KeyRange;
using blink::protocol::IndexedDB::ObjectStore;
using blink::protocol::IndexedDB::ObjectStoreIndex;
using blink::protocol::Maybe;
using blink::protocol::Response;

typedef blink::protocol::IndexedDB::Backend::RequestDatabaseNamesCallback
    RequestDatabaseNamesCallback;
typedef blink::protocol::IndexedDB::Backend::RequestDatabaseCallback
    RequestDatabaseCallback;
typedef blink::protocol::IndexedDB::Backend::RequestDataCallback
    RequestDataCallback;
typedef blink::protocol::IndexedDB::Backend::DeleteObjectStoreEntriesCallback
    DeleteObjectStoreEntriesCallback;
typedef blink::protocol::IndexedDB::Backend::ClearObjectStoreCallback
    ClearObjectStoreCallback;
typedef blink::protocol::IndexedDB::Backend::
    GetKeyGeneratorCurrentNumberCallback GetKeyGeneratorCurrentNumberCallback;
typedef blink::protocol::IndexedDB::Backend::DeleteDatabaseCallback
    DeleteDatabaseCallback;

namespace blink {
namespace {

const char kIndexedDBObjectGroup[] = "indexeddb";
const char kNoDocumentError[] = "No document for given frame found";

Response AssertIDBFactory(Document* document, IDBFactory*& result) {
  LocalDOMWindow* dom_window = document->domWindow();
  if (!dom_window)
    return Response::Error("No IndexedDB factory for given frame found");
  IDBFactory* idb_factory = GlobalIndexedDB::indexedDB(*dom_window);

  if (!idb_factory)
    return Response::Error("No IndexedDB factory for given frame found");
  result = idb_factory;
  return Response::OK();
}

class GetDatabaseNamesCallback final : public NativeEventListener {
 public:
  static GetDatabaseNamesCallback* Create(
      std::unique_ptr<RequestDatabaseNamesCallback> request_callback,
      const String& security_origin) {
    return MakeGarbageCollected<GetDatabaseNamesCallback>(
        std::move(request_callback), security_origin);
  }

  GetDatabaseNamesCallback(
      std::unique_ptr<RequestDatabaseNamesCallback> request_callback,
      const String& security_origin)
      : request_callback_(std::move(request_callback)),
        security_origin_(security_origin) {}
  ~GetDatabaseNamesCallback() override = default;

  void Invoke(ExecutionContext*, Event* event) override {
    if (event->type() != event_type_names::kSuccess) {
      request_callback_->sendFailure(Response::Error("Unexpected event type."));
      return;
    }

    IDBRequest* idb_request = static_cast<IDBRequest*>(event->target());
    IDBAny* request_result = idb_request->ResultAsAny();
    if (request_result->GetType() != IDBAny::kDOMStringListType) {
      request_callback_->sendFailure(
          Response::Error("Unexpected result type."));
      return;
    }

    DOMStringList* database_names_list = request_result->DomStringList();
    std::unique_ptr<protocol::Array<String>> database_names =
        protocol::Array<String>::create();
    for (uint32_t i = 0; i < database_names_list->length(); ++i)
      database_names->addItem(database_names_list->item(i));
    request_callback_->sendSuccess(std::move(database_names));
  }

 private:
  std::unique_ptr<RequestDatabaseNamesCallback> request_callback_;
  String security_origin_;
};

class DeleteCallback final : public NativeEventListener {
 public:
  static DeleteCallback* Create(
      std::unique_ptr<DeleteDatabaseCallback> request_callback,
      const String& security_origin) {
    return MakeGarbageCollected<DeleteCallback>(std::move(request_callback),
                                                security_origin);
  }

  DeleteCallback(std::unique_ptr<DeleteDatabaseCallback> request_callback,
                 const String& security_origin)
      : request_callback_(std::move(request_callback)),
        security_origin_(security_origin) {}
  ~DeleteCallback() override = default;

  void Invoke(ExecutionContext*, Event* event) override {
    if (event->type() != event_type_names::kSuccess) {
      request_callback_->sendFailure(
          Response::Error("Failed to delete database."));
      return;
    }
    request_callback_->sendSuccess();
  }

 private:
  std::unique_ptr<DeleteDatabaseCallback> request_callback_;
  String security_origin_;
};

template <typename RequestCallback>
class OpenDatabaseCallback;
template <typename RequestCallback>
class UpgradeDatabaseCallback;

template <typename RequestCallback>
class ExecutableWithDatabase
    : public RefCounted<ExecutableWithDatabase<RequestCallback>> {
 public:
  virtual ~ExecutableWithDatabase() = default;
  virtual void Execute(IDBDatabase*, ScriptState*) = 0;
  virtual RequestCallback* GetRequestCallback() = 0;
  void Start(LocalFrame* frame, const String& database_name) {
    Document* document = frame ? frame->GetDocument() : nullptr;
    if (!document) {
      SendFailure(Response::Error(kNoDocumentError));
      return;
    }
    IDBFactory* idb_factory = nullptr;
    Response response = AssertIDBFactory(document, idb_factory);
    if (!response.isSuccess()) {
      SendFailure(response);
      return;
    }

    ScriptState* script_state = ToScriptStateForMainWorld(frame);
    if (!script_state) {
      SendFailure(Response::InternalError());
      return;
    }

    ScriptState::Scope scope(script_state);
    DoStart(idb_factory, script_state, document->GetSecurityOrigin(),
            database_name);
  }

 private:
  void DoStart(IDBFactory* idb_factory,
               ScriptState* script_state,
               const SecurityOrigin*,
               const String& database_name) {
    OpenDatabaseCallback<RequestCallback>* open_callback =
        OpenDatabaseCallback<RequestCallback>::Create(this, script_state);
    UpgradeDatabaseCallback<RequestCallback>* upgrade_callback =
        UpgradeDatabaseCallback<RequestCallback>::Create(this);
    DummyExceptionStateForTesting exception_state;
    IDBOpenDBRequest* idb_open_db_request =
        idb_factory->open(script_state, database_name, exception_state);
    if (exception_state.HadException()) {
      SendFailure(Response::Error("Could not open database."));
      return;
    }
    idb_open_db_request->addEventListener(event_type_names::kUpgradeneeded,
                                          upgrade_callback, false);
    idb_open_db_request->addEventListener(event_type_names::kSuccess,
                                          open_callback, false);
  }

  void SendFailure(Response response) {
    GetRequestCallback()->sendFailure(response);
  }
};

template <typename RequestCallback>
class OpenDatabaseCallback final : public NativeEventListener {
 public:
  static OpenDatabaseCallback* Create(
      ExecutableWithDatabase<RequestCallback>* executable_with_database,
      ScriptState* script_state) {
    return MakeGarbageCollected<OpenDatabaseCallback>(executable_with_database,
                                                      script_state);
  }

  OpenDatabaseCallback(
      ExecutableWithDatabase<RequestCallback>* executable_with_database,
      ScriptState* script_state)
      : executable_with_database_(executable_with_database),
        script_state_(script_state) {}
  ~OpenDatabaseCallback() override = default;

  void Invoke(ExecutionContext* context, Event* event) override {
    if (event->type() != event_type_names::kSuccess) {
      executable_with_database_->GetRequestCallback()->sendFailure(
          Response::Error("Unexpected event type."));
      return;
    }

    IDBOpenDBRequest* idb_open_db_request =
        static_cast<IDBOpenDBRequest*>(event->target());
    IDBAny* request_result = idb_open_db_request->ResultAsAny();
    if (request_result->GetType() != IDBAny::kIDBDatabaseType) {
      executable_with_database_->GetRequestCallback()->sendFailure(
          Response::Error("Unexpected result type."));
      return;
    }

    IDBDatabase* idb_database = request_result->IdbDatabase();
    executable_with_database_->Execute(idb_database, script_state_);
    V8PerIsolateData::From(script_state_->GetIsolate())->RunEndOfScopeTasks();
    idb_database->close();
  }

  void Trace(blink::Visitor* visitor) override {
    visitor->Trace(script_state_);
    NativeEventListener::Trace(visitor);
  }

 private:
  scoped_refptr<ExecutableWithDatabase<RequestCallback>>
      executable_with_database_;
  Member<ScriptState> script_state_;
};

template <typename RequestCallback>
class UpgradeDatabaseCallback final : public NativeEventListener {
 public:
  static UpgradeDatabaseCallback* Create(
      ExecutableWithDatabase<RequestCallback>* executable_with_database) {
    return MakeGarbageCollected<UpgradeDatabaseCallback>(
        executable_with_database);
  }

  UpgradeDatabaseCallback(
      ExecutableWithDatabase<RequestCallback>* executable_with_database)
      : executable_with_database_(executable_with_database) {}
  ~UpgradeDatabaseCallback() override = default;

  void Invoke(ExecutionContext* context, Event* event) override {
    if (event->type() != event_type_names::kUpgradeneeded) {
      executable_with_database_->GetRequestCallback()->sendFailure(
          Response::Error("Unexpected event type."));
      return;
    }

    // If an "upgradeneeded" event comes through then the database that
    // had previously been enumerated was deleted. We don't want to
    // implicitly re-create it here, so abort the transaction.
    IDBOpenDBRequest* idb_open_db_request =
        static_cast<IDBOpenDBRequest*>(event->target());
    NonThrowableExceptionState exception_state;
    idb_open_db_request->transaction()->abort(exception_state);
    executable_with_database_->GetRequestCallback()->sendFailure(
        Response::Error("Aborted upgrade."));
  }

 private:
  scoped_refptr<ExecutableWithDatabase<RequestCallback>>
      executable_with_database_;
};

IDBTransaction* TransactionForDatabase(
    ScriptState* script_state,
    IDBDatabase* idb_database,
    const String& object_store_name,
    const String& mode = indexed_db_names::kReadonly) {
  DummyExceptionStateForTesting exception_state;
  StringOrStringSequence scope;
  scope.SetString(object_store_name);
  IDBTransaction* idb_transaction =
      idb_database->transaction(script_state, scope, mode, exception_state);
  if (exception_state.HadException())
    return nullptr;
  return idb_transaction;
}

IDBObjectStore* ObjectStoreForTransaction(IDBTransaction* idb_transaction,
                                          const String& object_store_name) {
  DummyExceptionStateForTesting exception_state;
  IDBObjectStore* idb_object_store =
      idb_transaction->objectStore(object_store_name, exception_state);
  if (exception_state.HadException())
    return nullptr;
  return idb_object_store;
}

IDBIndex* IndexForObjectStore(IDBObjectStore* idb_object_store,
                              const String& index_name) {
  DummyExceptionStateForTesting exception_state;
  IDBIndex* idb_index = idb_object_store->index(index_name, exception_state);
  if (exception_state.HadException())
    return nullptr;
  return idb_index;
}

std::unique_ptr<KeyPath> KeyPathFromIDBKeyPath(const IDBKeyPath& idb_key_path) {
  std::unique_ptr<KeyPath> key_path;
  switch (idb_key_path.GetType()) {
    case mojom::IDBKeyPathType::Null:
      key_path = KeyPath::create().setType(KeyPath::TypeEnum::Null).build();
      break;
    case mojom::IDBKeyPathType::String:
      key_path = KeyPath::create()
                     .setType(KeyPath::TypeEnum::String)
                     .setString(idb_key_path.GetString())
                     .build();
      break;
    case mojom::IDBKeyPathType::Array: {
      key_path = KeyPath::create().setType(KeyPath::TypeEnum::Array).build();
      std::unique_ptr<protocol::Array<String>> array =
          protocol::Array<String>::create();
      const Vector<String>& string_array = idb_key_path.Array();
      for (wtf_size_t i = 0; i < string_array.size(); ++i)
        array->addItem(string_array[i]);
      key_path->setArray(std::move(array));
      break;
    }
    default:
      NOTREACHED();
  }

  return key_path;
}

class DatabaseLoader final
    : public ExecutableWithDatabase<RequestDatabaseCallback> {
 public:
  static scoped_refptr<DatabaseLoader> Create(
      std::unique_ptr<RequestDatabaseCallback> request_callback) {
    return base::AdoptRef(new DatabaseLoader(std::move(request_callback)));
  }

  ~DatabaseLoader() override = default;

  void Execute(IDBDatabase* idb_database, ScriptState*) override {
    const IDBDatabaseMetadata database_metadata = idb_database->Metadata();

    std::unique_ptr<protocol::Array<protocol::IndexedDB::ObjectStore>>
        object_stores =
            protocol::Array<protocol::IndexedDB::ObjectStore>::create();

    for (const auto& store_map_entry : database_metadata.object_stores) {
      const IDBObjectStoreMetadata& object_store_metadata =
          *store_map_entry.value;

      std::unique_ptr<protocol::Array<protocol::IndexedDB::ObjectStoreIndex>>
          indexes =
              protocol::Array<protocol::IndexedDB::ObjectStoreIndex>::create();

      for (const auto& metadata_map_entry : object_store_metadata.indexes) {
        const IDBIndexMetadata& index_metadata = *metadata_map_entry.value;

        std::unique_ptr<ObjectStoreIndex> object_store_index =
            ObjectStoreIndex::create()
                .setName(index_metadata.name)
                .setKeyPath(KeyPathFromIDBKeyPath(index_metadata.key_path))
                .setUnique(index_metadata.unique)
                .setMultiEntry(index_metadata.multi_entry)
                .build();
        indexes->addItem(std::move(object_store_index));
      }

      std::unique_ptr<ObjectStore> object_store =
          ObjectStore::create()
              .setName(object_store_metadata.name)
              .setKeyPath(KeyPathFromIDBKeyPath(object_store_metadata.key_path))
              .setAutoIncrement(object_store_metadata.auto_increment)
              .setIndexes(std::move(indexes))
              .build();
      object_stores->addItem(std::move(object_store));
    }
    std::unique_ptr<DatabaseWithObjectStores> result =
        DatabaseWithObjectStores::create()
            .setName(idb_database->name())
            .setVersion(idb_database->version())
            .setObjectStores(std::move(object_stores))
            .build();

    request_callback_->sendSuccess(std::move(result));
  }

  RequestDatabaseCallback* GetRequestCallback() override {
    return request_callback_.get();
  }

 private:
  DatabaseLoader(std::unique_ptr<RequestDatabaseCallback> request_callback)
      : request_callback_(std::move(request_callback)) {}
  std::unique_ptr<RequestDatabaseCallback> request_callback_;
};

static std::unique_ptr<IDBKey> IdbKeyFromInspectorObject(
    protocol::IndexedDB::Key* key) {
  std::unique_ptr<IDBKey> idb_key;

  if (!key)
    return nullptr;
  String type = key->getType();

  DEFINE_STATIC_LOCAL(String, number_type, ("number"));
  DEFINE_STATIC_LOCAL(String, string_type, ("string"));
  DEFINE_STATIC_LOCAL(String, date_type, ("date"));
  DEFINE_STATIC_LOCAL(String, array_type, ("array"));

  if (type == number_type) {
    if (!key->hasNumber())
      return nullptr;
    idb_key = IDBKey::CreateNumber(key->getNumber(0));
  } else if (type == string_type) {
    if (!key->hasString())
      return nullptr;
    idb_key = IDBKey::CreateString(key->getString(String()));
  } else if (type == date_type) {
    if (!key->hasDate())
      return nullptr;
    idb_key = IDBKey::CreateDate(key->getDate(0));
  } else if (type == array_type) {
    IDBKey::KeyArray key_array;
    auto* array = key->getArray(nullptr);
    for (size_t i = 0; array && i < array->length(); ++i)
      key_array.push_back(IdbKeyFromInspectorObject(array->get(i)));
    idb_key = IDBKey::CreateArray(std::move(key_array));
  } else {
    return nullptr;
  }

  return idb_key;
}

static IDBKeyRange* IdbKeyRangeFromKeyRange(
    protocol::IndexedDB::KeyRange* key_range) {
  std::unique_ptr<IDBKey> idb_lower =
      IdbKeyFromInspectorObject(key_range->getLower(nullptr));
  if (key_range->hasLower() && !idb_lower)
    return nullptr;

  std::unique_ptr<IDBKey> idb_upper =
      IdbKeyFromInspectorObject(key_range->getUpper(nullptr));
  if (key_range->hasUpper() && !idb_upper)
    return nullptr;

  IDBKeyRange::LowerBoundType lower_bound_type =
      key_range->getLowerOpen() ? IDBKeyRange::kLowerBoundOpen
                                : IDBKeyRange::kLowerBoundClosed;
  IDBKeyRange::UpperBoundType upper_bound_type =
      key_range->getUpperOpen() ? IDBKeyRange::kUpperBoundOpen
                                : IDBKeyRange::kUpperBoundClosed;
  return IDBKeyRange::Create(std::move(idb_lower), std::move(idb_upper),
                             lower_bound_type, upper_bound_type);
}

class DataLoader;

class OpenCursorCallback final : public NativeEventListener {
 public:
  static OpenCursorCallback* Create(
      v8_inspector::V8InspectorSession* v8_session,
      ScriptState* script_state,
      std::unique_ptr<RequestDataCallback> request_callback,
      int skip_count,
      unsigned page_size) {
    return MakeGarbageCollected<OpenCursorCallback>(v8_session, script_state,
                                                    std::move(request_callback),
                                                    skip_count, page_size);
  }

  OpenCursorCallback(v8_inspector::V8InspectorSession* v8_session,
                     ScriptState* script_state,
                     std::unique_ptr<RequestDataCallback> request_callback,
                     int skip_count,
                     unsigned page_size)
      : v8_session_(v8_session),
        script_state_(script_state),
        request_callback_(std::move(request_callback)),
        skip_count_(skip_count),
        page_size_(page_size) {
    result_ = Array<DataEntry>::create();
  }
  ~OpenCursorCallback() override = default;

  void Invoke(ExecutionContext*, Event* event) override {
    if (event->type() != event_type_names::kSuccess) {
      request_callback_->sendFailure(Response::Error("Unexpected event type."));
      return;
    }

    IDBRequest* idb_request = static_cast<IDBRequest*>(event->target());
    IDBAny* request_result = idb_request->ResultAsAny();
    if (request_result->GetType() == IDBAny::kIDBValueType) {
      end(false);
      return;
    }
    if (request_result->GetType() != IDBAny::kIDBCursorWithValueType) {
      request_callback_->sendFailure(
          Response::Error("Unexpected result type."));
      return;
    }

    IDBCursorWithValue* idb_cursor = request_result->IdbCursorWithValue();

    if (skip_count_) {
      DummyExceptionStateForTesting exception_state;
      idb_cursor->advance(skip_count_, exception_state);
      if (exception_state.HadException()) {
        request_callback_->sendFailure(
            Response::Error("Could not advance cursor."));
      }
      skip_count_ = 0;
      return;
    }

    if (result_->length() == page_size_) {
      end(true);
      return;
    }

    // Continue cursor before making injected script calls, otherwise
    // transaction might be finished.
    DummyExceptionStateForTesting exception_state;
    idb_cursor->Continue(nullptr, nullptr, IDBRequest::AsyncTraceState(),
                         exception_state);
    if (exception_state.HadException()) {
      request_callback_->sendFailure(
          Response::Error("Could not continue cursor."));
      return;
    }

    Document* document = To<Document>(ExecutionContext::From(script_state_));
    if (!document)
      return;
    ScriptState::Scope scope(script_state_);
    v8::Local<v8::Context> context = script_state_->GetContext();
    v8_inspector::StringView object_group =
        ToV8InspectorStringView(kIndexedDBObjectGroup);
    std::unique_ptr<DataEntry> data_entry =
        DataEntry::create()
            .setKey(v8_session_->wrapObject(
                context, idb_cursor->key(script_state_).V8Value(), object_group,
                true /* generatePreview */))
            .setPrimaryKey(v8_session_->wrapObject(
                context, idb_cursor->primaryKey(script_state_).V8Value(),
                object_group, true /* generatePreview */))
            .setValue(v8_session_->wrapObject(
                context, idb_cursor->value(script_state_).V8Value(),
                object_group, true /* generatePreview */))
            .build();
    result_->addItem(std::move(data_entry));
  }

  void end(bool has_more) {
    request_callback_->sendSuccess(std::move(result_), has_more);
  }

  void Trace(blink::Visitor* visitor) override {
    visitor->Trace(script_state_);
    NativeEventListener::Trace(visitor);
  }

 private:
  v8_inspector::V8InspectorSession* v8_session_;
  Member<ScriptState> script_state_;
  std::unique_ptr<RequestDataCallback> request_callback_;
  int skip_count_;
  unsigned page_size_;
  std::unique_ptr<Array<DataEntry>> result_;
};

class DataLoader final : public ExecutableWithDatabase<RequestDataCallback> {
 public:
  static scoped_refptr<DataLoader> Create(
      v8_inspector::V8InspectorSession* v8_session,
      std::unique_ptr<RequestDataCallback> request_callback,
      const String& object_store_name,
      const String& index_name,
      IDBKeyRange* idb_key_range,
      int skip_count,
      unsigned page_size) {
    return base::AdoptRef(new DataLoader(
        v8_session, std::move(request_callback), object_store_name, index_name,
        idb_key_range, skip_count, page_size));
  }

  ~DataLoader() override = default;

  void Execute(IDBDatabase* idb_database, ScriptState* script_state) override {
    IDBTransaction* idb_transaction =
        TransactionForDatabase(script_state, idb_database, object_store_name_);
    if (!idb_transaction) {
      request_callback_->sendFailure(
          Response::Error("Could not get transaction"));
      return;
    }
    IDBObjectStore* idb_object_store =
        ObjectStoreForTransaction(idb_transaction, object_store_name_);
    if (!idb_object_store) {
      request_callback_->sendFailure(
          Response::Error("Could not get object store"));
      return;
    }

    IDBRequest* idb_request;
    if (!index_name_.IsEmpty()) {
      IDBIndex* idb_index = IndexForObjectStore(idb_object_store, index_name_);
      if (!idb_index) {
        request_callback_->sendFailure(Response::Error("Could not get index"));
        return;
      }

      idb_request = idb_index->openCursor(script_state, idb_key_range_.Get(),
                                          mojom::IDBCursorDirection::Next);
    } else {
      idb_request = idb_object_store->openCursor(
          script_state, idb_key_range_.Get(), mojom::IDBCursorDirection::Next);
    }
    OpenCursorCallback* open_cursor_callback = OpenCursorCallback::Create(
        v8_session_, script_state, std::move(request_callback_), skip_count_,
        page_size_);
    idb_request->addEventListener(event_type_names::kSuccess,
                                  open_cursor_callback, false);
  }

  RequestDataCallback* GetRequestCallback() override {
    return request_callback_.get();
  }
  DataLoader(v8_inspector::V8InspectorSession* v8_session,
             std::unique_ptr<RequestDataCallback> request_callback,
             const String& object_store_name,
             const String& index_name,
             IDBKeyRange* idb_key_range,
             int skip_count,
             unsigned page_size)
      : v8_session_(v8_session),
        request_callback_(std::move(request_callback)),
        object_store_name_(object_store_name),
        index_name_(index_name),
        idb_key_range_(idb_key_range),
        skip_count_(skip_count),
        page_size_(page_size) {}

  v8_inspector::V8InspectorSession* v8_session_;
  std::unique_ptr<RequestDataCallback> request_callback_;
  String object_store_name_;
  String index_name_;
  Persistent<IDBKeyRange> idb_key_range_;
  int skip_count_;
  unsigned page_size_;
};

}  // namespace

// static
InspectorIndexedDBAgent::InspectorIndexedDBAgent(
    InspectedFrames* inspected_frames,
    v8_inspector::V8InspectorSession* v8_session)
    : inspected_frames_(inspected_frames),
      v8_session_(v8_session),
      enabled_(&agent_state_, /*default_value=*/false) {}

InspectorIndexedDBAgent::~InspectorIndexedDBAgent() = default;

void InspectorIndexedDBAgent::Restore() {
  if (enabled_.Get())
    enable();
}

void InspectorIndexedDBAgent::DidCommitLoadForLocalFrame(LocalFrame* frame) {
  if (frame == inspected_frames_->Root()) {
    v8_session_->releaseObjectGroup(
        ToV8InspectorStringView(kIndexedDBObjectGroup));
  }
}

Response InspectorIndexedDBAgent::enable() {
  enabled_.Set(true);
  return Response::OK();
}

Response InspectorIndexedDBAgent::disable() {
  enabled_.Clear();
  v8_session_->releaseObjectGroup(
      ToV8InspectorStringView(kIndexedDBObjectGroup));
  return Response::OK();
}

void InspectorIndexedDBAgent::requestDatabaseNames(
    const String& security_origin,
    std::unique_ptr<RequestDatabaseNamesCallback> request_callback) {
  LocalFrame* frame =
      inspected_frames_->FrameWithSecurityOrigin(security_origin);
  Document* document = frame ? frame->GetDocument() : nullptr;
  if (!document) {
    request_callback->sendFailure(Response::Error(kNoDocumentError));
    return;
  }
  IDBFactory* idb_factory = nullptr;
  Response response = AssertIDBFactory(document, idb_factory);
  if (!response.isSuccess()) {
    request_callback->sendFailure(response);
    return;
  }

  ScriptState* script_state = ToScriptStateForMainWorld(frame);
  if (!script_state) {
    request_callback->sendFailure(Response::InternalError());
    return;
  }
  ScriptState::Scope scope(script_state);
  DummyExceptionStateForTesting exception_state;
  IDBRequest* idb_request =
      idb_factory->GetDatabaseNames(script_state, exception_state);
  if (exception_state.HadException()) {
    request_callback->sendFailure(
        Response::Error("Could not obtain database names."));
    return;
  }
  idb_request->addEventListener(
      event_type_names::kSuccess,
      GetDatabaseNamesCallback::Create(
          std::move(request_callback),
          document->GetSecurityOrigin()->ToRawString()),
      false);
}

void InspectorIndexedDBAgent::requestDatabase(
    const String& security_origin,
    const String& database_name,
    std::unique_ptr<RequestDatabaseCallback> request_callback) {
  scoped_refptr<DatabaseLoader> database_loader =
      DatabaseLoader::Create(std::move(request_callback));
  database_loader->Start(
      inspected_frames_->FrameWithSecurityOrigin(security_origin),
      database_name);
}

void InspectorIndexedDBAgent::requestData(
    const String& security_origin,
    const String& database_name,
    const String& object_store_name,
    const String& index_name,
    int skip_count,
    int page_size,
    Maybe<protocol::IndexedDB::KeyRange> key_range,
    std::unique_ptr<RequestDataCallback> request_callback) {
  IDBKeyRange* idb_key_range =
      key_range.isJust() ? IdbKeyRangeFromKeyRange(key_range.fromJust())
                         : nullptr;
  if (key_range.isJust() && !idb_key_range) {
    request_callback->sendFailure(Response::Error("Can not parse key range."));
    return;
  }

  scoped_refptr<DataLoader> data_loader = DataLoader::Create(
      v8_session_, std::move(request_callback), object_store_name, index_name,
      idb_key_range, skip_count, page_size);

  data_loader->Start(
      inspected_frames_->FrameWithSecurityOrigin(security_origin),
      database_name);
}

class GetKeyGeneratorCurrentNumberListener final : public NativeEventListener {
 public:
  static GetKeyGeneratorCurrentNumberListener* Create(
      std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback) {
    return MakeGarbageCollected<GetKeyGeneratorCurrentNumberListener>(
        std::move(request_callback));
  }

  GetKeyGeneratorCurrentNumberListener(
      std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback)
      : request_callback_(std::move(request_callback)) {}
  ~GetKeyGeneratorCurrentNumberListener() override = default;

  void Invoke(ExecutionContext*, Event* event) override {
    if (event->type() != event_type_names::kSuccess) {
      request_callback_->sendFailure(
          Response::Error("Failed to get current number of key generator."));
      return;
    }

    IDBRequest* idb_request = static_cast<IDBRequest*>(event->target());
    IDBAny* request_result = idb_request->ResultAsAny();
    if (request_result->GetType() != IDBAny::kIntegerType) {
      request_callback_->sendFailure(
          Response::Error("Unexpected result type."));
      return;
    }
    request_callback_->sendSuccess(request_result->Integer());
  }

 private:
  std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback_;
};

class GetKeyGeneratorCurrentNumber final
    : public ExecutableWithDatabase<GetKeyGeneratorCurrentNumberCallback> {
 public:
  static scoped_refptr<GetKeyGeneratorCurrentNumber> Create(
      const String& object_store_name,
      std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback) {
    return AdoptRef(new GetKeyGeneratorCurrentNumber(
        object_store_name, std::move(request_callback)));
  }

 private:
  GetKeyGeneratorCurrentNumber(
      const String& object_store_name,
      std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback)
      : object_store_name_(object_store_name),
        request_callback_(std::move(request_callback)) {}

  void Execute(IDBDatabase* idb_database, ScriptState* script_state) override {
    IDBTransaction* idb_transaction =
        TransactionForDatabase(script_state, idb_database, object_store_name_,
                               indexed_db_names::kReadonly);
    if (!idb_transaction) {
      request_callback_->sendFailure(
          Response::Error("Could not get transaction"));
      return;
    }
    IDBObjectStore* idb_object_store =
        ObjectStoreForTransaction(idb_transaction, object_store_name_);
    if (!idb_object_store) {
      request_callback_->sendFailure(
          Response::Error("Could not get object store"));
      return;
    }
    IDBRequest* idb_request =
        idb_object_store->getKeyGeneratorCurrentNumber(script_state);
    idb_request->addEventListener(event_type_names::kSuccess,
                                  GetKeyGeneratorCurrentNumberListener::Create(
                                      std::move(request_callback_)),
                                  false);
    idb_request->addEventListener(event_type_names::kError,
                                  GetKeyGeneratorCurrentNumberListener::Create(
                                      std::move(request_callback_)),
                                  false);
  }

  GetKeyGeneratorCurrentNumberCallback* GetRequestCallback() override {
    return request_callback_.get();
  }

 private:
  const String object_store_name_;
  std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback_;
};

void InspectorIndexedDBAgent::getKeyGeneratorCurrentNumber(
    const String& security_origin,
    const String& database_name,
    const String& object_store_name,
    std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback) {
  scoped_refptr<GetKeyGeneratorCurrentNumber> get_auto_increment_number =
      GetKeyGeneratorCurrentNumber::Create(object_store_name,
                                           std::move(request_callback));
  get_auto_increment_number->Start(
      inspected_frames_->FrameWithSecurityOrigin(security_origin),
      database_name);
}

class DeleteObjectStoreEntriesListener final : public NativeEventListener {
 public:
  static DeleteObjectStoreEntriesListener* Create(
      std::unique_ptr<DeleteObjectStoreEntriesCallback> request_callback) {
    return MakeGarbageCollected<DeleteObjectStoreEntriesListener>(
        std::move(request_callback));
  }

  DeleteObjectStoreEntriesListener(
      std::unique_ptr<DeleteObjectStoreEntriesCallback> request_callback)
      : request_callback_(std::move(request_callback)) {}
  ~DeleteObjectStoreEntriesListener() override = default;

  void Invoke(ExecutionContext*, Event* event) override {
    if (event->type() != event_type_names::kSuccess) {
      request_callback_->sendFailure(
          Response::Error("Failed to delete specified entries"));
      return;
    }

    request_callback_->sendSuccess();
  }

 private:
  std::unique_ptr<DeleteObjectStoreEntriesCallback> request_callback_;
};

class DeleteObjectStoreEntries final
    : public ExecutableWithDatabase<DeleteObjectStoreEntriesCallback> {
 public:
  static scoped_refptr<DeleteObjectStoreEntries> Create(
      const String& object_store_name,
      IDBKeyRange* idb_key_range,
      std::unique_ptr<DeleteObjectStoreEntriesCallback> request_callback) {
    return AdoptRef(new DeleteObjectStoreEntries(
        object_store_name, idb_key_range, std::move(request_callback)));
  }

  DeleteObjectStoreEntries(
      const String& object_store_name,
      IDBKeyRange* idb_key_range,
      std::unique_ptr<DeleteObjectStoreEntriesCallback> request_callback)
      : object_store_name_(object_store_name),
        idb_key_range_(idb_key_range),
        request_callback_(std::move(request_callback)) {}

  void Execute(IDBDatabase* idb_database, ScriptState* script_state) override {
    IDBTransaction* idb_transaction =
        TransactionForDatabase(script_state, idb_database, object_store_name_,
                               indexed_db_names::kReadwrite);
    if (!idb_transaction) {
      request_callback_->sendFailure(
          Response::Error("Could not get transaction"));
      return;
    }
    IDBObjectStore* idb_object_store =
        ObjectStoreForTransaction(idb_transaction, object_store_name_);
    if (!idb_object_store) {
      request_callback_->sendFailure(
          Response::Error("Could not get object store"));
      return;
    }

    IDBRequest* idb_request =
        idb_object_store->deleteFunction(script_state, idb_key_range_.Get());
    idb_request->addEventListener(
        event_type_names::kSuccess,
        DeleteObjectStoreEntriesListener::Create(std::move(request_callback_)),
        false);
  }

  DeleteObjectStoreEntriesCallback* GetRequestCallback() override {
    return request_callback_.get();
  }

 private:
  const String object_store_name_;
  Persistent<IDBKeyRange> idb_key_range_;
  std::unique_ptr<DeleteObjectStoreEntriesCallback> request_callback_;
};

void InspectorIndexedDBAgent::deleteObjectStoreEntries(
    const String& security_origin,
    const String& database_name,
    const String& object_store_name,
    std::unique_ptr<protocol::IndexedDB::KeyRange> key_range,
    std::unique_ptr<DeleteObjectStoreEntriesCallback> request_callback) {
  IDBKeyRange* idb_key_range = IdbKeyRangeFromKeyRange(key_range.get());
  if (!idb_key_range) {
    request_callback->sendFailure(Response::Error("Can not parse key range"));
    return;
  }
  scoped_refptr<DeleteObjectStoreEntries> delete_object_store_entries =
      DeleteObjectStoreEntries::Create(object_store_name, idb_key_range,
                                       std::move(request_callback));
  delete_object_store_entries->Start(
      inspected_frames_->FrameWithSecurityOrigin(security_origin),
      database_name);
}

class ClearObjectStoreListener final : public NativeEventListener {
 public:
  static ClearObjectStoreListener* Create(
      std::unique_ptr<ClearObjectStoreCallback> request_callback) {
    return MakeGarbageCollected<ClearObjectStoreListener>(
        std::move(request_callback));
  }

  ClearObjectStoreListener(
      std::unique_ptr<ClearObjectStoreCallback> request_callback)
      : request_callback_(std::move(request_callback)) {}
  ~ClearObjectStoreListener() override = default;

  void Invoke(ExecutionContext*, Event* event) override {
    if (event->type() != event_type_names::kComplete) {
      request_callback_->sendFailure(Response::Error("Unexpected event type."));
      return;
    }

    request_callback_->sendSuccess();
  }

 private:
  std::unique_ptr<ClearObjectStoreCallback> request_callback_;
};

class ClearObjectStore final
    : public ExecutableWithDatabase<ClearObjectStoreCallback> {
 public:
  static scoped_refptr<ClearObjectStore> Create(
      const String& object_store_name,
      std::unique_ptr<ClearObjectStoreCallback> request_callback) {
    return base::AdoptRef(
        new ClearObjectStore(object_store_name, std::move(request_callback)));
  }

  ClearObjectStore(const String& object_store_name,
                   std::unique_ptr<ClearObjectStoreCallback> request_callback)
      : object_store_name_(object_store_name),
        request_callback_(std::move(request_callback)) {}

  void Execute(IDBDatabase* idb_database, ScriptState* script_state) override {
    IDBTransaction* idb_transaction =
        TransactionForDatabase(script_state, idb_database, object_store_name_,
                               indexed_db_names::kReadwrite);
    if (!idb_transaction) {
      request_callback_->sendFailure(
          Response::Error("Could not get transaction"));
      return;
    }
    IDBObjectStore* idb_object_store =
        ObjectStoreForTransaction(idb_transaction, object_store_name_);
    if (!idb_object_store) {
      request_callback_->sendFailure(
          Response::Error("Could not get object store"));
      return;
    }

    DummyExceptionStateForTesting exception_state;
    idb_object_store->clear(script_state, exception_state);
    DCHECK(!exception_state.HadException());
    if (exception_state.HadException()) {
      ExceptionCode ec = exception_state.Code();
      request_callback_->sendFailure(Response::Error(
          String::Format("Could not clear object store '%s': %d",
                         object_store_name_.Utf8().data(), ec)));
      return;
    }
    idb_transaction->addEventListener(
        event_type_names::kComplete,
        ClearObjectStoreListener::Create(std::move(request_callback_)), false);
  }

  ClearObjectStoreCallback* GetRequestCallback() override {
    return request_callback_.get();
  }

 private:
  const String object_store_name_;
  std::unique_ptr<ClearObjectStoreCallback> request_callback_;
};

void InspectorIndexedDBAgent::clearObjectStore(
    const String& security_origin,
    const String& database_name,
    const String& object_store_name,
    std::unique_ptr<ClearObjectStoreCallback> request_callback) {
  scoped_refptr<ClearObjectStore> clear_object_store =
      ClearObjectStore::Create(object_store_name, std::move(request_callback));
  clear_object_store->Start(
      inspected_frames_->FrameWithSecurityOrigin(security_origin),
      database_name);
}

void InspectorIndexedDBAgent::deleteDatabase(
    const String& security_origin,
    const String& database_name,
    std::unique_ptr<DeleteDatabaseCallback> request_callback) {
  LocalFrame* frame =
      inspected_frames_->FrameWithSecurityOrigin(security_origin);
  Document* document = frame ? frame->GetDocument() : nullptr;
  if (!document) {
    request_callback->sendFailure(Response::Error(kNoDocumentError));
    return;
  }
  IDBFactory* idb_factory = nullptr;
  Response response = AssertIDBFactory(document, idb_factory);
  if (!response.isSuccess()) {
    request_callback->sendFailure(response);
    return;
  }

  ScriptState* script_state = ToScriptStateForMainWorld(frame);
  if (!script_state) {
    request_callback->sendFailure(Response::InternalError());
    return;
  }
  ScriptState::Scope scope(script_state);
  DummyExceptionStateForTesting exception_state;
  IDBRequest* idb_request = idb_factory->CloseConnectionsAndDeleteDatabase(
      script_state, database_name, exception_state);
  if (exception_state.HadException()) {
    request_callback->sendFailure(
        Response::Error("Could not delete database."));
    return;
  }
  idb_request->addEventListener(
      event_type_names::kSuccess,
      DeleteCallback::Create(std::move(request_callback),
                             document->GetSecurityOrigin()->ToRawString()),
      false);
}

void InspectorIndexedDBAgent::Trace(blink::Visitor* visitor) {
  visitor->Trace(inspected_frames_);
  InspectorBaseAgent::Trace(visitor);
}

}  // namespace blink
