/*
    This file is part of the WebKit open source project.
    This file has been generated by generate-bindings.pl. DO NOT MODIFY!

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include "config.h"

#if ENABLE(INDEXED_DATABASE)

#include "JSIDBCursorWithValue.h"

#include "JSDOMBinding.h"
#include "JSDOMConstructor.h"
#include <wtf/GetPtr.h>

using namespace JSC;

namespace WebCore {

// Attributes

JSC::EncodedJSValue jsIDBCursorWithValueValue(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
JSC::EncodedJSValue jsIDBCursorWithValueConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
bool setJSIDBCursorWithValueConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);

class JSIDBCursorWithValuePrototype : public JSC::JSNonFinalObject {
public:
    typedef JSC::JSNonFinalObject Base;
    static JSIDBCursorWithValuePrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
    {
        JSIDBCursorWithValuePrototype* ptr = new (NotNull, JSC::allocateCell<JSIDBCursorWithValuePrototype>(vm.heap)) JSIDBCursorWithValuePrototype(vm, globalObject, structure);
        ptr->finishCreation(vm);
        return ptr;
    }

    DECLARE_INFO;
    static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
    {
        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
    }

private:
    JSIDBCursorWithValuePrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure)
        : JSC::JSNonFinalObject(vm, structure)
    {
    }

    void finishCreation(JSC::VM&);
};

typedef JSDOMConstructorNotConstructable<JSIDBCursorWithValue> JSIDBCursorWithValueConstructor;

template<> JSValue JSIDBCursorWithValueConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject)
{
    return JSIDBCursor::getConstructor(vm, &globalObject);
}

template<> void JSIDBCursorWithValueConstructor::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject)
{
    putDirect(vm, vm.propertyNames->prototype, JSIDBCursorWithValue::prototype(vm, &globalObject), DontDelete | ReadOnly | DontEnum);
    putDirect(vm, vm.propertyNames->name, jsNontrivialString(&vm, String(ASCIILiteral("IDBCursorWithValue"))), ReadOnly | DontEnum);
    putDirect(vm, vm.propertyNames->length, jsNumber(0), ReadOnly | DontEnum);
}

template<> const ClassInfo JSIDBCursorWithValueConstructor::s_info = { "IDBCursorWithValue", &Base::s_info, 0, CREATE_METHOD_TABLE(JSIDBCursorWithValueConstructor) };

/* Hash table for prototype */

static const HashTableValue JSIDBCursorWithValuePrototypeTableValues[] =
{
    { "constructor", DontEnum, NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsIDBCursorWithValueConstructor), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSIDBCursorWithValueConstructor) } },
    { "value", ReadOnly | CustomAccessor, NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsIDBCursorWithValueValue), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(0) } },
};

const ClassInfo JSIDBCursorWithValuePrototype::s_info = { "IDBCursorWithValuePrototype", &Base::s_info, 0, CREATE_METHOD_TABLE(JSIDBCursorWithValuePrototype) };

void JSIDBCursorWithValuePrototype::finishCreation(VM& vm)
{
    Base::finishCreation(vm);
    reifyStaticProperties(vm, JSIDBCursorWithValuePrototypeTableValues, *this);
}

const ClassInfo JSIDBCursorWithValue::s_info = { "IDBCursorWithValue", &Base::s_info, 0, CREATE_METHOD_TABLE(JSIDBCursorWithValue) };

JSIDBCursorWithValue::JSIDBCursorWithValue(Structure* structure, JSDOMGlobalObject& globalObject, Ref<IDBCursorWithValue>&& impl)
    : JSIDBCursor(structure, globalObject, WTFMove(impl))
{
}

JSObject* JSIDBCursorWithValue::createPrototype(VM& vm, JSGlobalObject* globalObject)
{
    return JSIDBCursorWithValuePrototype::create(vm, globalObject, JSIDBCursorWithValuePrototype::createStructure(vm, globalObject, JSIDBCursor::prototype(vm, globalObject)));
}

JSObject* JSIDBCursorWithValue::prototype(VM& vm, JSGlobalObject* globalObject)
{
    return getDOMPrototype<JSIDBCursorWithValue>(vm, globalObject);
}

EncodedJSValue jsIDBCursorWithValueValue(ExecState* state, EncodedJSValue thisValue, PropertyName)
{
    VM& vm = state->vm();
    auto throwScope = DECLARE_THROW_SCOPE(vm);
    UNUSED_PARAM(throwScope);
    UNUSED_PARAM(thisValue);
    JSValue decodedThisValue = JSValue::decode(thisValue);
    auto* castedThis = jsDynamicCast<JSIDBCursorWithValue*>(decodedThisValue);
    if (UNLIKELY(!castedThis)) {
        return throwGetterTypeError(*state, throwScope, "IDBCursorWithValue", "value");
    }
    auto& impl = castedThis->wrapped();
    JSValue result = impl.value();
    return JSValue::encode(result);
}


EncodedJSValue jsIDBCursorWithValueConstructor(ExecState* state, EncodedJSValue thisValue, PropertyName)
{
    VM& vm = state->vm();
    auto throwScope = DECLARE_THROW_SCOPE(vm);
    JSIDBCursorWithValuePrototype* domObject = jsDynamicCast<JSIDBCursorWithValuePrototype*>(JSValue::decode(thisValue));
    if (UNLIKELY(!domObject))
        return throwVMTypeError(state, throwScope);
    return JSValue::encode(JSIDBCursorWithValue::getConstructor(state->vm(), domObject->globalObject()));
}

bool setJSIDBCursorWithValueConstructor(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)
{
    VM& vm = state->vm();
    auto throwScope = DECLARE_THROW_SCOPE(vm);
    JSValue value = JSValue::decode(encodedValue);
    JSIDBCursorWithValuePrototype* domObject = jsDynamicCast<JSIDBCursorWithValuePrototype*>(JSValue::decode(thisValue));
    if (UNLIKELY(!domObject)) {
        throwVMTypeError(state, throwScope);
        return false;
    }
    // Shadowing a built-in constructor
    return domObject->putDirect(state->vm(), state->propertyNames().constructor, value);
}

JSValue JSIDBCursorWithValue::getConstructor(VM& vm, const JSGlobalObject* globalObject)
{
    return getDOMConstructor<JSIDBCursorWithValueConstructor>(vm, *jsCast<const JSDOMGlobalObject*>(globalObject));
}

void JSIDBCursorWithValue::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
    auto* thisObject = jsCast<JSIDBCursorWithValue*>(cell);
    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
    Base::visitChildren(thisObject, visitor);
    thisObject->visitAdditionalChildren(visitor);
}

bool JSIDBCursorWithValueOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
{
    auto* jsIDBCursorWithValue = jsCast<JSIDBCursorWithValue*>(handle.slot()->asCell());
    if (jsIDBCursorWithValue->wrapped().hasPendingActivity())
        return true;
    UNUSED_PARAM(visitor);
    return false;
}

void JSIDBCursorWithValueOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context)
{
    auto* jsIDBCursorWithValue = jsCast<JSIDBCursorWithValue*>(handle.slot()->asCell());
    auto& world = *static_cast<DOMWrapperWorld*>(context);
    uncacheWrapper(world, &jsIDBCursorWithValue->wrapped(), jsIDBCursorWithValue);
}


}

#endif // ENABLE(INDEXED_DATABASE)
