/*
 * Copyright (C) 2011, 2013 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 "WebKeyValueStorageManager.h"

#include "SecurityOriginData.h"
#include "WebContext.h"
#include "WebSecurityOrigin.h"

using namespace WebCore;

namespace WebKit {

const char* WebKeyValueStorageManager::supplementName()
{
    return "WebKeyValueStorageManager";
}

PassRefPtr<WebKeyValueStorageManager> WebKeyValueStorageManager::create(WebContext* context)
{
    return adoptRef(new WebKeyValueStorageManager(context));
}

WebKeyValueStorageManager::WebKeyValueStorageManager(WebContext* context)
    : WebContextSupplement(context)
{
}

WebKeyValueStorageManager::~WebKeyValueStorageManager()
{
}

// WebContextSupplement

void WebKeyValueStorageManager::refWebContextSupplement()
{
    APIObject::ref();
}

void WebKeyValueStorageManager::derefWebContextSupplement()
{
    APIObject::deref();
}

static void didGetKeyValueStorageOrigins(const Vector<RefPtr<WebCore::SecurityOrigin>>& securityOrigins, void* context)
{
    RefPtr<ArrayCallback> callback = adoptRef(static_cast<ArrayCallback*>(context));

    Vector<RefPtr<APIObject>> webSecurityOrigins;
    webSecurityOrigins.reserveInitialCapacity(securityOrigins.size());

    for (unsigned i = 0; i < securityOrigins.size(); ++i)
        webSecurityOrigins.uncheckedAppend(WebSecurityOrigin::create(securityOrigins[i]));

    callback->performCallbackWithReturnValue(ImmutableArray::adopt(webSecurityOrigins).get());
}

void WebKeyValueStorageManager::getKeyValueStorageOrigins(PassRefPtr<ArrayCallback> prpCallback)
{
    context()->storageManager().getOrigins(RunLoop::main(), prpCallback.leakRef(), didGetKeyValueStorageOrigins);
}
    
void WebKeyValueStorageManager::deleteEntriesForOrigin(WebSecurityOrigin* origin)
{
    context()->storageManager().deleteEntriesForOrigin(origin->securityOrigin());
}

void WebKeyValueStorageManager::deleteAllEntries()
{
    context()->storageManager().deleteAllEntries();
}

} // namespace WebKit
