/*
 * Copyright (C) 2010 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.
 */

#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_INDEX_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_INDEX_H_

#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_cursor.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_request.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_cursor.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_database.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"

namespace blink {

class ExceptionState;
class IDBObjectStore;

class IDBIndex final : public ScriptWrappable {
  DEFINE_WRAPPERTYPEINFO();

 public:
  static IDBIndex* Create(scoped_refptr<IDBIndexMetadata> metadata,
                          IDBObjectStore* object_store,
                          IDBTransaction* transaction) {
    return new IDBIndex(std::move(metadata), object_store, transaction);
  }
  ~IDBIndex() override;
  void Trace(blink::Visitor*) override;

  // Implement the IDL
  const String& name() const { return Metadata().name; }
  void setName(const String& name, ExceptionState&);
  IDBObjectStore* objectStore() const { return object_store_.Get(); }
  ScriptValue keyPath(ScriptState*) const;
  bool unique() const { return Metadata().unique; }
  bool multiEntry() const { return Metadata().multi_entry; }

  IDBRequest* openCursor(ScriptState*,
                         const ScriptValue& key,
                         const String& direction,
                         ExceptionState&);
  IDBRequest* openKeyCursor(ScriptState*,
                            const ScriptValue& range,
                            const String& direction,
                            ExceptionState&);
  IDBRequest* count(ScriptState*, const ScriptValue& range, ExceptionState&);
  IDBRequest* get(ScriptState*, const ScriptValue& key, ExceptionState&);
  IDBRequest* getAll(ScriptState*, const ScriptValue& range, ExceptionState&);
  IDBRequest* getAll(ScriptState*,
                     const ScriptValue& range,
                     unsigned long max_count,
                     ExceptionState&);
  IDBRequest* getKey(ScriptState*, const ScriptValue& key, ExceptionState&);
  IDBRequest* getAllKeys(ScriptState*,
                         const ScriptValue& range,
                         ExceptionState&);
  IDBRequest* getAllKeys(ScriptState*,
                         const ScriptValue& range,
                         uint32_t max_count,
                         ExceptionState&);

  void MarkDeleted() {
    DCHECK(transaction_->IsVersionChange())
        << "Index deleted outside versionchange transaction.";
    deleted_ = true;
  }
  bool IsDeleted() const { return deleted_; }
  int64_t Id() const { return Metadata().id; }

  // True if this index was created in its associated transaction.
  // Only valid if the index's associated transaction is a versionchange.
  bool IsNewlyCreated(
      const IDBObjectStoreMetadata& old_object_store_metadata) const {
    DCHECK(transaction_->IsVersionChange());

    // Index IDs are allocated sequentially, so we can tell if an index was
    // created in this transaction by comparing its ID against the object
    // store's maximum index ID at the time when the transaction was started.
    return Id() > old_object_store_metadata.max_index_id;
  }

  void RevertMetadata(scoped_refptr<IDBIndexMetadata> old_metadata);

  // Used internally and by InspectorIndexedDBAgent:
  IDBRequest* openCursor(
      ScriptState*,
      IDBKeyRange*,
      WebIDBCursorDirection,
      IDBRequest::AsyncTraceState = IDBRequest::AsyncTraceState());

  WebIDBDatabase* BackendDB() const;

 private:
  IDBIndex(scoped_refptr<IDBIndexMetadata>, IDBObjectStore*, IDBTransaction*);

  const IDBIndexMetadata& Metadata() const { return *metadata_; }

  IDBRequest* GetInternal(ScriptState*,
                          const ScriptValue& key,
                          ExceptionState&,
                          bool key_only,
                          IDBRequest::AsyncTraceState metrics);
  IDBRequest* GetAllInternal(ScriptState*,
                             const ScriptValue& range,
                             unsigned long max_count,
                             ExceptionState&,
                             bool key_only,
                             IDBRequest::AsyncTraceState metrics);

  scoped_refptr<IDBIndexMetadata> metadata_;
  Member<IDBObjectStore> object_store_;
  Member<IDBTransaction> transaction_;
  bool deleted_ = false;
};

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_INDEX_H_
