/*
 * 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:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  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.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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/idb_open_db_request.h"

#include <memory>

#include "base/optional.h"
#include "third_party/blink/renderer/bindings/modules/v8/idb_object_store_or_idb_index_or_idb_cursor.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_database.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_tracing.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_version_change_event.h"

namespace blink {

IDBOpenDBRequest* IDBOpenDBRequest::Create(
    ScriptState* script_state,
    IDBDatabaseCallbacks* callbacks,
    int64_t transaction_id,
    int64_t version,
    IDBRequest::AsyncTraceState metrics) {
  return MakeGarbageCollected<IDBOpenDBRequest>(
      script_state, callbacks, transaction_id, version, std::move(metrics));
}

IDBOpenDBRequest::IDBOpenDBRequest(ScriptState* script_state,
                                   IDBDatabaseCallbacks* callbacks,
                                   int64_t transaction_id,
                                   int64_t version,
                                   IDBRequest::AsyncTraceState metrics)
    : IDBRequest(script_state,
                 IDBRequest::Source(),
                 nullptr,
                 std::move(metrics)),
      database_callbacks_(callbacks),
      transaction_id_(transaction_id),
      version_(version) {
  DCHECK(!ResultAsAny());
}

IDBOpenDBRequest::~IDBOpenDBRequest() = default;

void IDBOpenDBRequest::Trace(blink::Visitor* visitor) {
  visitor->Trace(database_callbacks_);
  IDBRequest::Trace(visitor);
}

void IDBOpenDBRequest::ContextDestroyed(ExecutionContext* destroyed_context) {
  IDBRequest::ContextDestroyed(destroyed_context);
  if (database_callbacks_)
    database_callbacks_->DetachWebCallbacks();
}

const AtomicString& IDBOpenDBRequest::InterfaceName() const {
  return event_target_names::kIDBOpenDBRequest;
}

void IDBOpenDBRequest::EnqueueBlocked(int64_t old_version) {
  IDB_TRACE("IDBOpenDBRequest::onBlocked()");
  if (!ShouldEnqueueEvent())
    return;
  base::Optional<unsigned long long> new_version_nullable;
  if (version_ != IDBDatabaseMetadata::kDefaultVersion) {
    new_version_nullable = version_;
  }
  EnqueueEvent(IDBVersionChangeEvent::Create(
      event_type_names::kBlocked, old_version, new_version_nullable));
}

void IDBOpenDBRequest::EnqueueUpgradeNeeded(
    int64_t old_version,
    std::unique_ptr<WebIDBDatabase> backend,
    const IDBDatabaseMetadata& metadata,
    mojom::IDBDataLoss data_loss,
    String data_loss_message) {
  IDB_TRACE("IDBOpenDBRequest::onUpgradeNeeded()");
  if (!ShouldEnqueueEvent()) {
    metrics_.RecordAndReset();
    return;
  }

  DCHECK(database_callbacks_);

  IDBDatabase* idb_database =
      IDBDatabase::Create(GetExecutionContext(), std::move(backend),
                          database_callbacks_.Release(), isolate_);
  idb_database->SetMetadata(metadata);

  if (old_version == IDBDatabaseMetadata::kNoVersion) {
    // This database hasn't had a version before.
    old_version = IDBDatabaseMetadata::kDefaultVersion;
  }
  IDBDatabaseMetadata old_database_metadata(
      metadata.name, metadata.id, old_version, metadata.max_object_store_id);

  transaction_ = IDBTransaction::CreateVersionChange(
      GetExecutionContext(), transaction_id_, idb_database, this,
      old_database_metadata);
  SetResult(IDBAny::Create(idb_database));

  if (version_ == IDBDatabaseMetadata::kNoVersion)
    version_ = 1;
  EnqueueEvent(IDBVersionChangeEvent::Create(event_type_names::kUpgradeneeded,
                                             old_version, version_, data_loss,
                                             data_loss_message));
}

void IDBOpenDBRequest::EnqueueResponse(std::unique_ptr<WebIDBDatabase> backend,
                                       const IDBDatabaseMetadata& metadata) {
  IDB_TRACE("IDBOpenDBRequest::onSuccess()");
  if (!ShouldEnqueueEvent()) {
    metrics_.RecordAndReset();
    return;
  }

  IDBDatabase* idb_database = nullptr;
  if (ResultAsAny()) {
    // Previous OnUpgradeNeeded call delivered the backend.
    DCHECK(!backend.get());
    idb_database = ResultAsAny()->IdbDatabase();
    DCHECK(idb_database);
    DCHECK(!database_callbacks_);
  } else {
    DCHECK(backend.get());
    DCHECK(database_callbacks_);
    idb_database =
        IDBDatabase::Create(GetExecutionContext(), std::move(backend),
                            database_callbacks_.Release(), isolate_);
    SetResult(IDBAny::Create(idb_database));
  }
  idb_database->SetMetadata(metadata);
  EnqueueEvent(Event::Create(event_type_names::kSuccess));
  metrics_.RecordAndReset();
}

void IDBOpenDBRequest::EnqueueResponse(int64_t old_version) {
  IDB_TRACE("IDBOpenDBRequest::onSuccess()");
  if (!ShouldEnqueueEvent()) {
    metrics_.RecordAndReset();
    return;
  }
  if (old_version == IDBDatabaseMetadata::kNoVersion) {
    // This database hasn't had an integer version before.
    old_version = IDBDatabaseMetadata::kDefaultVersion;
  }
  SetResult(IDBAny::CreateUndefined());
  EnqueueEvent(IDBVersionChangeEvent::Create(event_type_names::kSuccess,
                                             old_version, base::nullopt));
  metrics_.RecordAndReset();
}

bool IDBOpenDBRequest::ShouldEnqueueEvent() const {
  if (!GetExecutionContext())
    return false;
  DCHECK(ready_state_ == PENDING || ready_state_ == DONE);
  if (request_aborted_)
    return false;
  return true;
}

DispatchEventResult IDBOpenDBRequest::DispatchEventInternal(Event& event) {
  // If the connection closed between onUpgradeNeeded and the delivery of the
  // "success" event, an "error" event should be fired instead.
  if (event.type() == event_type_names::kSuccess &&
      ResultAsAny()->GetType() == IDBAny::kIDBDatabaseType &&
      ResultAsAny()->IdbDatabase()->IsClosePending()) {
    SetResult(nullptr);
    HandleResponse(DOMException::Create(DOMExceptionCode::kAbortError,
                                        "The connection was closed."));
    return DispatchEventResult::kCanceledBeforeDispatch;
  }

  return IDBRequest::DispatchEventInternal(event);
}

}  // namespace blink
