/*
 * Copyright (C) 2015, 2016 Apple 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 INC. 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 INC. 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 "config.h"
#include "IDBDatabase.h"

#include "DOMStringList.h"
#include "EventNames.h"
#include "IDBConnectionProxy.h"
#include "IDBConnectionToServer.h"
#include "IDBIndex.h"
#include "IDBObjectStore.h"
#include "IDBOpenDBRequest.h"
#include "IDBResultData.h"
#include "IDBTransaction.h"
#include "IDBVersionChangeEvent.h"
#include "Logging.h"
#include "ScriptExecutionContext.h"
#include <JavaScriptCore/HeapInlines.h>
#include <wtf/IsoMallocInlines.h>

namespace WebCore {

WTF_MAKE_ISO_ALLOCATED_IMPL(IDBDatabase);

static Vector<String> sortAndRemoveDuplicates(Vector<String>&& vector)
{
    std::sort(vector.begin(), vector.end(), WTF::codePointCompareLessThan);
    removeRepeatedElements(vector);
    return WTFMove(vector);
}

Ref<IDBDatabase> IDBDatabase::create(ScriptExecutionContext& context, IDBClient::IDBConnectionProxy& connectionProxy, const IDBResultData& resultData)
{
    auto database = adoptRef(*new IDBDatabase(context, connectionProxy, resultData));
    database->suspendIfNeeded();
    return database;
}

IDBDatabase::IDBDatabase(ScriptExecutionContext& context, IDBClient::IDBConnectionProxy& connectionProxy, const IDBResultData& resultData)
    : IDBActiveDOMObject(&context)
    , m_connectionProxy(connectionProxy)
    , m_info(resultData.databaseInfo())
    , m_databaseConnectionIdentifier(resultData.databaseConnectionIdentifier())
    , m_eventNames(eventNames())
{
    LOG(IndexedDB, "IDBDatabase::IDBDatabase - Creating database %s with version %" PRIu64 " connection %" PRIu64 " (%p)", m_info.name().utf8().data(), m_info.version(), m_databaseConnectionIdentifier, this);
    m_connectionProxy->registerDatabaseConnection(*this);
}

IDBDatabase::~IDBDatabase()
{
    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));

    if (!m_closedInServer)
        m_connectionProxy->databaseConnectionClosed(*this);

    m_connectionProxy->unregisterDatabaseConnection(*this);
}

bool IDBDatabase::virtualHasPendingActivity() const
{
    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()) || Thread::mayBeGCThread());

    if (m_closedInServer)
        return false;

    if (!m_activeTransactions.isEmpty() || !m_committingTransactions.isEmpty() || !m_abortingTransactions.isEmpty())
        return true;

    return hasEventListeners(m_eventNames.abortEvent) || hasEventListeners(m_eventNames.errorEvent) || hasEventListeners(m_eventNames.versionchangeEvent);
}

const String IDBDatabase::name() const
{
    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));
    return m_info.name();
}

uint64_t IDBDatabase::version() const
{
    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));
    return m_info.version();
}

Ref<DOMStringList> IDBDatabase::objectStoreNames() const
{
    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));

    auto objectStoreNames = DOMStringList::create(m_info.objectStoreNames());
    objectStoreNames->sort();
    return objectStoreNames;
}

void IDBDatabase::renameObjectStore(IDBObjectStore& objectStore, const String& newName)
{
    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));
    ASSERT(m_versionChangeTransaction);
    ASSERT(m_info.hasObjectStore(objectStore.info().name()));

    m_info.renameObjectStore(objectStore.info().identifier(), newName);

    m_versionChangeTransaction->renameObjectStore(objectStore, newName);
}

void IDBDatabase::renameIndex(IDBIndex& index, const String& newName)
{
    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));
    ASSERT(m_versionChangeTransaction);
    ASSERT(m_info.hasObjectStore(index.objectStore().info().name()));
    ASSERT(m_info.infoForExistingObjectStore(index.objectStore().info().name())->hasIndex(index.info().name()));

    m_info.infoForExistingObjectStore(index.objectStore().info().name())->infoForExistingIndex(index.info().identifier())->rename(newName);

    m_versionChangeTransaction->renameIndex(index, newName);
}

ExceptionOr<Ref<IDBObjectStore>> IDBDatabase::createObjectStore(const String& name, ObjectStoreParameters&& parameters)
{
    LOG(IndexedDB, "IDBDatabase::createObjectStore - (%s %s)", m_info.name().utf8().data(), name.utf8().data());

    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));
    ASSERT(!m_versionChangeTransaction || m_versionChangeTransaction->isVersionChange());

    if (!m_versionChangeTransaction)
        return Exception { InvalidStateError, "Failed to execute 'createObjectStore' on 'IDBDatabase': The database is not running a version change transaction."_s };

    if (!m_versionChangeTransaction->isActive())
        return Exception { TransactionInactiveError };

    auto& keyPath = parameters.keyPath;
    if (keyPath && !isIDBKeyPathValid(keyPath.value()))
        return Exception { SyntaxError, "Failed to execute 'createObjectStore' on 'IDBDatabase': The keyPath option is not a valid key path."_s };

    if (m_info.hasObjectStore(name))
        return Exception { ConstraintError, "Failed to execute 'createObjectStore' on 'IDBDatabase': An object store with the specified name already exists."_s };

    if (keyPath && parameters.autoIncrement && ((std::holds_alternative<String>(keyPath.value()) && std::get<String>(keyPath.value()).isEmpty()) || std::holds_alternative<Vector<String>>(keyPath.value())))
        return Exception { InvalidAccessError, "Failed to execute 'createObjectStore' on 'IDBDatabase': The autoIncrement option was set but the keyPath option was empty or an array."_s };

    // Install the new ObjectStore into the connection's metadata.
    auto info = m_info.createNewObjectStore(name, WTFMove(keyPath), parameters.autoIncrement);

    // Create the actual IDBObjectStore from the transaction, which also schedules the operation server side.
    return m_versionChangeTransaction->createObjectStore(info);
}

ExceptionOr<Ref<IDBTransaction>> IDBDatabase::transaction(StringOrVectorOfStrings&& storeNames, IDBTransactionMode mode, TransactionOptions options)
{
    LOG(IndexedDB, "IDBDatabase::transaction");

    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));

    if (m_versionChangeTransaction && !m_versionChangeTransaction->isFinishedOrFinishing())
        return Exception { InvalidStateError, "Failed to execute 'transaction' on 'IDBDatabase': A version change transaction is running."_s };

    if (m_closePending)
        return Exception { InvalidStateError, "Failed to execute 'transaction' on 'IDBDatabase': The database connection is closing."_s };

    Vector<String> objectStores;
    if (std::holds_alternative<Vector<String>>(storeNames)) {
        // It is valid for JavaScript to pass in a list of object store names with the same name listed twice,
        // so we need to drop the duplicates.
        objectStores = sortAndRemoveDuplicates(std::get<Vector<String>>(WTFMove(storeNames)));
    } else
        objectStores = { std::get<String>(WTFMove(storeNames)) };

    for (auto& objectStoreName : objectStores) {
        if (m_info.hasObjectStore(objectStoreName))
            continue;
        return Exception { NotFoundError, "Failed to execute 'transaction' on 'IDBDatabase': One of the specified object stores was not found."_s };
    }

    if (objectStores.isEmpty())
        return Exception { InvalidAccessError, "Failed to execute 'transaction' on 'IDBDatabase': The storeNames parameter was empty."_s };

    if (mode != IDBTransactionMode::Readonly && mode != IDBTransactionMode::Readwrite)
        return Exception { TypeError };

    auto info = IDBTransactionInfo::clientTransaction(m_connectionProxy.get(), objectStores, mode, options.durability);

    LOG(IndexedDBOperations, "IDB creating transaction: %s", info.loggingString().utf8().data());
    auto transaction = IDBTransaction::create(*this, info);

    LOG(IndexedDB, "IDBDatabase::transaction - Added active transaction %s", info.identifier().loggingString().utf8().data());

    m_activeTransactions.set(info.identifier(), transaction.ptr());

    return transaction;
}

ExceptionOr<void> IDBDatabase::deleteObjectStore(const String& objectStoreName)
{
    LOG(IndexedDB, "IDBDatabase::deleteObjectStore");

    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));

    if (!m_versionChangeTransaction)
        return Exception { InvalidStateError, "Failed to execute 'deleteObjectStore' on 'IDBDatabase': The database is not running a version change transaction."_s };

    if (!m_versionChangeTransaction->isActive())
        return Exception { TransactionInactiveError };

    if (!m_info.hasObjectStore(objectStoreName))
        return Exception { NotFoundError, "Failed to execute 'deleteObjectStore' on 'IDBDatabase': The specified object store was not found."_s };

    m_info.deleteObjectStore(objectStoreName);
    m_versionChangeTransaction->deleteObjectStore(objectStoreName);

    return { };
}

void IDBDatabase::close()
{
    LOG(IndexedDB, "IDBDatabase::close - %" PRIu64, m_databaseConnectionIdentifier);

    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));

    if (!m_closePending) {
        m_closePending = true;
        m_connectionProxy->databaseConnectionPendingClose(*this);
    }

    maybeCloseInServer();
}

void IDBDatabase::didCloseFromServer(const IDBError& error)
{
    LOG(IndexedDB, "IDBDatabase::didCloseFromServer - %" PRIu64, m_databaseConnectionIdentifier);

    connectionToServerLost(error);
}

void IDBDatabase::connectionToServerLost(const IDBError& error)
{
    LOG(IndexedDB, "IDBDatabase::connectionToServerLost - %" PRIu64, m_databaseConnectionIdentifier);

    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));

    m_closePending = true;
    m_closedInServer = true;

    auto activeTransactions = copyToVector(m_activeTransactions.values());
    for (auto& transaction : activeTransactions)
        transaction->connectionClosedFromServer(error);
    
    auto committingTransactions = copyToVector(m_committingTransactions.values());
    for (auto& transaction : committingTransactions)
        transaction->connectionClosedFromServer(error);

    auto errorEvent = Event::create(m_eventNames.errorEvent, Event::CanBubble::Yes, Event::IsCancelable::No);
    errorEvent->setTarget(this);

    if (scriptExecutionContext())
        queueTaskToDispatchEvent(*this, TaskSource::DatabaseAccess, WTFMove(errorEvent));

    auto closeEvent = Event::create(m_eventNames.closeEvent, Event::CanBubble::Yes, Event::IsCancelable::No);
    closeEvent->setTarget(this);

    if (scriptExecutionContext())
        queueTaskToDispatchEvent(*this, TaskSource::DatabaseAccess, WTFMove(closeEvent));
}

void IDBDatabase::maybeCloseInServer()
{
    LOG(IndexedDB, "IDBDatabase::maybeCloseInServer - %" PRIu64, m_databaseConnectionIdentifier);

    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));

    if (m_closedInServer)
        return;

    // 3.3.9 Database closing steps
    // Wait for all transactions created using this connection to complete.
    // Once they are complete, this connection is closed.
    if (!m_activeTransactions.isEmpty() || !m_committingTransactions.isEmpty())
        return;

    m_closedInServer = true;
    m_connectionProxy->databaseConnectionClosed(*this);
}

const char* IDBDatabase::activeDOMObjectName() const
{
    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));
    return "IDBDatabase";
}

void IDBDatabase::stop()
{
    LOG(IndexedDB, "IDBDatabase::stop - %" PRIu64, m_databaseConnectionIdentifier);

    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));

    removeAllEventListeners();

    for (auto& id : copyToVector(m_activeTransactions.keys())) {
        if (auto* transaction = m_activeTransactions.get(id))
            transaction->stop();
    }

    close();
}

Ref<IDBTransaction> IDBDatabase::startVersionChangeTransaction(const IDBTransactionInfo& info, IDBOpenDBRequest& request)
{
    LOG(IndexedDB, "IDBDatabase::startVersionChangeTransaction %s", info.identifier().loggingString().utf8().data());

    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));
    ASSERT(!m_versionChangeTransaction);
    ASSERT(info.mode() == IDBTransactionMode::Versionchange);
    ASSERT(!m_closePending);
    ASSERT(scriptExecutionContext());

    Ref<IDBTransaction> transaction = IDBTransaction::create(*this, info, request);
    m_versionChangeTransaction = &transaction.get();

    m_activeTransactions.set(transaction->info().identifier(), &transaction.get());

    return transaction;
}

void IDBDatabase::didStartTransaction(IDBTransaction& transaction)
{
    LOG(IndexedDB, "IDBDatabase::didStartTransaction %s", transaction.info().identifier().loggingString().utf8().data());
    ASSERT(!m_versionChangeTransaction);
    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));

    // It is possible for the client to have aborted or committed a transaction
    // before the server replies back that it has started.
    if (m_abortingTransactions.contains(transaction.info().identifier()) || m_committingTransactions.contains(transaction.info().identifier()))
        return;

    m_activeTransactions.set(transaction.info().identifier(), &transaction);
}

void IDBDatabase::willCommitTransaction(IDBTransaction& transaction)
{
    LOG(IndexedDB, "IDBDatabase::willCommitTransaction %s", transaction.info().identifier().loggingString().utf8().data());

    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));

    auto refTransaction = m_activeTransactions.take(transaction.info().identifier());
    ASSERT(refTransaction);
    m_committingTransactions.set(transaction.info().identifier(), WTFMove(refTransaction));
}

void IDBDatabase::didCommitTransaction(IDBTransaction& transaction)
{
    LOG(IndexedDB, "IDBDatabase::didCommitTransaction %s", transaction.info().identifier().loggingString().utf8().data());

    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));

    if (m_versionChangeTransaction == &transaction)
        m_info.setVersion(transaction.info().newVersion());

    didCommitOrAbortTransaction(transaction);
}

void IDBDatabase::willAbortTransaction(IDBTransaction& transaction)
{
    LOG(IndexedDB, "IDBDatabase::willAbortTransaction %s", transaction.info().identifier().loggingString().utf8().data());

    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));

    auto refTransaction = m_activeTransactions.take(transaction.info().identifier());
    if (!refTransaction)
        refTransaction = m_committingTransactions.take(transaction.info().identifier());

    ASSERT(refTransaction);
    m_abortingTransactions.set(transaction.info().identifier(), WTFMove(refTransaction));

    if (transaction.isVersionChange()) {
        ASSERT(transaction.originalDatabaseInfo());
        m_info = *transaction.originalDatabaseInfo();
        m_closePending = true;
    }
}

void IDBDatabase::didAbortTransaction(IDBTransaction& transaction)
{
    LOG(IndexedDB, "IDBDatabase::didAbortTransaction %s", transaction.info().identifier().loggingString().utf8().data());

    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));

    if (transaction.isVersionChange()) {
        ASSERT(transaction.originalDatabaseInfo());
        ASSERT(m_info.version() == transaction.originalDatabaseInfo()->version());
        m_closePending = true;
        maybeCloseInServer();
    }

    didCommitOrAbortTransaction(transaction);
}

void IDBDatabase::didCommitOrAbortTransaction(IDBTransaction& transaction)
{
    LOG(IndexedDB, "IDBDatabase::didCommitOrAbortTransaction %s", transaction.info().identifier().loggingString().utf8().data());

    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));

    if (m_versionChangeTransaction == &transaction)
        m_versionChangeTransaction = nullptr;

#ifndef NDBEBUG
    unsigned count = 0;
    if (m_activeTransactions.contains(transaction.info().identifier()))
        ++count;
    if (m_committingTransactions.contains(transaction.info().identifier()))
        ++count;
    if (m_abortingTransactions.contains(transaction.info().identifier()))
        ++count;

    ASSERT(count == 1);
#endif

    m_activeTransactions.remove(transaction.info().identifier());
    m_committingTransactions.remove(transaction.info().identifier());
    m_abortingTransactions.remove(transaction.info().identifier());

    if (m_closePending)
        maybeCloseInServer();
}

void IDBDatabase::fireVersionChangeEvent(const IDBResourceIdentifier& requestIdentifier, uint64_t requestedVersion)
{
    uint64_t currentVersion = m_info.version();
    LOG(IndexedDB, "IDBDatabase::fireVersionChangeEvent - current version %" PRIu64 ", requested version %" PRIu64 ", connection %" PRIu64 " (%p)", currentVersion, requestedVersion, m_databaseConnectionIdentifier, this);

    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));

    if (!scriptExecutionContext() || m_closePending) {
        connectionProxy().didFireVersionChangeEvent(m_databaseConnectionIdentifier, requestIdentifier);
        return;
    }
    
    Ref<Event> event = IDBVersionChangeEvent::create(requestIdentifier, currentVersion, requestedVersion, m_eventNames.versionchangeEvent);
    queueTaskToDispatchEvent(*this, TaskSource::DatabaseAccess, WTFMove(event));
}

void IDBDatabase::dispatchEvent(Event& event)
{
    LOG(IndexedDB, "IDBDatabase::dispatchEvent (%" PRIu64 ") (%p)", m_databaseConnectionIdentifier, this);
    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));

    Ref protectedThis { *this };

    EventTargetWithInlineData::dispatchEvent(event);

    if (event.isVersionChangeEvent() && event.type() == m_eventNames.versionchangeEvent)
        m_connectionProxy->didFireVersionChangeEvent(m_databaseConnectionIdentifier, downcast<IDBVersionChangeEvent>(event).requestIdentifier());
}

void IDBDatabase::didCreateIndexInfo(const IDBIndexInfo& info)
{
    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));

    auto* objectStore = m_info.infoForExistingObjectStore(info.objectStoreIdentifier());
    ASSERT(objectStore);
    objectStore->addExistingIndex(info);
}

void IDBDatabase::didDeleteIndexInfo(const IDBIndexInfo& info)
{
    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));

    auto* objectStore = m_info.infoForExistingObjectStore(info.objectStoreIdentifier());
    ASSERT(objectStore);
    objectStore->deleteIndex(info.name());
}

} // namespace WebCore
