/*
 * Copyright (C) 2019 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 "WebBackForwardCache.h"

#include "Logging.h"
#include "SuspendedPageProxy.h"
#include "WebBackForwardCacheEntry.h"
#include "WebBackForwardListItem.h"
#include "WebPageProxy.h"
#include "WebProcessMessages.h"
#include "WebProcessPool.h"
#include "WebProcessProxy.h"
#include "WebsiteDataStore.h"

namespace WebKit {

WebBackForwardCache::WebBackForwardCache(WebProcessPool& processPool)
    : m_processPool(processPool)
{
}

WebBackForwardCache::~WebBackForwardCache()
{
    clear();
}

inline void WebBackForwardCache::removeOldestEntry()
{
    ASSERT(!m_itemsWithCachedPage.isEmpty());
    removeEntry(*m_itemsWithCachedPage.first());
}

void WebBackForwardCache::setCapacity(unsigned capacity)
{
    if (m_capacity == capacity)
        return;

    m_capacity = capacity;
    while (size() > capacity)
        removeOldestEntry();

    m_processPool.sendToAllProcesses(Messages::WebProcess::SetBackForwardCacheCapacity(m_capacity));
}

void WebBackForwardCache::addEntry(WebBackForwardListItem& item, std::unique_ptr<WebBackForwardCacheEntry>&& backForwardCacheEntry)
{
    ASSERT(capacity());
    ASSERT(backForwardCacheEntry);

    if (item.backForwardCacheEntry()) {
        ASSERT(m_itemsWithCachedPage.contains(&item));
        m_itemsWithCachedPage.removeFirst(&item);
    }

    item.setBackForwardCacheEntry(WTFMove(backForwardCacheEntry));
    m_itemsWithCachedPage.append(&item);

    if (size() > capacity())
        removeOldestEntry();
    ASSERT(size() <= capacity());

    RELEASE_LOG(BackForwardCache, "WebBackForwardCache::addEntry: item: %s, hasSuspendedPage: %d, size: %u / %u", item.itemID().string().utf8().data(), !!item.suspendedPage(), size(), capacity());
}

void WebBackForwardCache::addEntry(WebBackForwardListItem& item, std::unique_ptr<SuspendedPageProxy>&& suspendedPage)
{
    addEntry(item, makeUnique<WebBackForwardCacheEntry>(*this, item.itemID(), suspendedPage->process().coreProcessIdentifier(), WTFMove(suspendedPage)));
}

void WebBackForwardCache::addEntry(WebBackForwardListItem& item, WebCore::ProcessIdentifier processIdentifier)
{
    addEntry(item, makeUnique<WebBackForwardCacheEntry>(*this, item.itemID(), WTFMove(processIdentifier)));
}

void WebBackForwardCache::removeEntry(WebBackForwardListItem& item)
{
    ASSERT(m_itemsWithCachedPage.contains(&item));
    m_itemsWithCachedPage.removeFirst(&item);
    item.setBackForwardCacheEntry(nullptr);
    RELEASE_LOG(BackForwardCache, "WebBackForwardCache::removeEntry: item: %s, size: %u / %u", item.itemID().string().utf8().data(), size(), capacity());
}

void WebBackForwardCache::removeEntry(SuspendedPageProxy& suspendedPage)
{
    removeEntriesMatching([&suspendedPage](auto& item) {
        return item.suspendedPage() == &suspendedPage;
    });
}

std::unique_ptr<SuspendedPageProxy> WebBackForwardCache::takeSuspendedPage(WebBackForwardListItem& item)
{
    RELEASE_LOG(BackForwardCache, "WebBackForwardCache::takeSuspendedPage: item: %s", item.itemID().string().utf8().data());

    ASSERT(m_itemsWithCachedPage.contains(&item));
    ASSERT(item.backForwardCacheEntry());
    auto suspendedPage = item.backForwardCacheEntry()->takeSuspendedPage();
    ASSERT(suspendedPage);
    removeEntry(item);
    return suspendedPage;
}

void WebBackForwardCache::removeEntriesForProcess(WebProcessProxy& process)
{
    removeEntriesMatching([processIdentifier = process.coreProcessIdentifier()](auto& entry) {
        ASSERT(entry.backForwardCacheEntry());
        return entry.backForwardCacheEntry()->processIdentifier() == processIdentifier;
    });
}

void WebBackForwardCache::removeEntriesForSession(PAL::SessionID sessionID)
{
    removeEntriesMatching([sessionID](auto& item) {
        return item.backForwardCacheEntry()->process().websiteDataStore().sessionID() == sessionID;
    });
}

void WebBackForwardCache::removeEntriesForPage(WebPageProxy& page)
{
    removeEntriesMatching([pageID = page.identifier()](auto& item) {
        return item.pageID() == pageID;
    });
}

void WebBackForwardCache::removeEntriesMatching(const Function<bool(WebBackForwardListItem&)>& matches)
{
    m_itemsWithCachedPage.removeAllMatching([&](auto* item) {
        if (matches(*item)) {
            item->setBackForwardCacheEntry(nullptr);
            return true;
        }
        return false;
    });
}

void WebBackForwardCache::clear()
{
    RELEASE_LOG(BackForwardCache, "WebBackForwardCache::clear");
    auto itemsWithCachedPage = WTFMove(m_itemsWithCachedPage);
    for (auto* item : itemsWithCachedPage)
        item->setBackForwardCacheEntry(nullptr);
}

void WebBackForwardCache::pruneToSize(unsigned newSize)
{
    RELEASE_LOG(BackForwardCache, "WebBackForwardCache::pruneToSize(%u)", newSize);
    while (size() > newSize)
        removeOldestEntry();
}

} // namespace WebKit.
