/*
    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"
#include "JSDedicatedWorkerGlobalScope.h"

#include "DedicatedWorkerGlobalScope.h"
#include "EventNames.h"
#include "JSDOMBinding.h"
#include "JSDOMConstructor.h"
#include "JSDedicatedWorkerGlobalScope.h"
#include "JSEventListener.h"
#include <runtime/Error.h>
#include <wtf/GetPtr.h>

using namespace JSC;

namespace WebCore {

// Functions

JSC::EncodedJSValue JSC_HOST_CALL jsDedicatedWorkerGlobalScopeInstanceFunctionPostMessage(JSC::ExecState*);

// Attributes

JSC::EncodedJSValue jsDedicatedWorkerGlobalScopeOnmessage(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
bool setJSDedicatedWorkerGlobalScopeOnmessage(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);
JSC::EncodedJSValue jsDedicatedWorkerGlobalScopeDedicatedWorkerGlobalScopeConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
bool setJSDedicatedWorkerGlobalScopeDedicatedWorkerGlobalScopeConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);
JSC::EncodedJSValue jsDedicatedWorkerGlobalScopeConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
bool setJSDedicatedWorkerGlobalScopeConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);

typedef JSDOMConstructorNotConstructable<JSDedicatedWorkerGlobalScope> JSDedicatedWorkerGlobalScopeConstructor;

/* Hash table */

static const struct CompactHashIndex JSDedicatedWorkerGlobalScopeTableIndex[8] = {
    { -1, -1 },
    { 2, -1 },
    { -1, -1 },
    { 1, -1 },
    { 0, -1 },
    { -1, -1 },
    { -1, -1 },
    { -1, -1 },
};


static const HashTableValue JSDedicatedWorkerGlobalScopeTableValues[] =
{
    { "onmessage", CustomAccessor, NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsDedicatedWorkerGlobalScopeOnmessage), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSDedicatedWorkerGlobalScopeOnmessage) } },
    { "DedicatedWorkerGlobalScope", DontEnum, NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsDedicatedWorkerGlobalScopeDedicatedWorkerGlobalScopeConstructor), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSDedicatedWorkerGlobalScopeDedicatedWorkerGlobalScopeConstructor) } },
    { "postMessage", JSC::Function, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsDedicatedWorkerGlobalScopeInstanceFunctionPostMessage), (intptr_t) (1) } },
};

static const HashTable JSDedicatedWorkerGlobalScopeTable = { 3, 7, true, JSDedicatedWorkerGlobalScopeTableValues, JSDedicatedWorkerGlobalScopeTableIndex };
template<> JSValue JSDedicatedWorkerGlobalScopeConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject)
{
    return JSWorkerGlobalScope::getConstructor(vm, &globalObject);
}

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

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

/* Hash table for prototype */

static const struct CompactHashIndex JSDedicatedWorkerGlobalScopePrototypeTableIndex[2] = {
    { -1, -1 },
    { 0, -1 },
};


static const HashTableValue JSDedicatedWorkerGlobalScopePrototypeTableValues[] =
{
    { "constructor", DontEnum, NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsDedicatedWorkerGlobalScopeConstructor), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSDedicatedWorkerGlobalScopeConstructor) } },
};

static const HashTable JSDedicatedWorkerGlobalScopePrototypeTable = { 1, 1, true, JSDedicatedWorkerGlobalScopePrototypeTableValues, JSDedicatedWorkerGlobalScopePrototypeTableIndex };
const ClassInfo JSDedicatedWorkerGlobalScopePrototype::s_info = { "DedicatedWorkerGlobalScopePrototype", &Base::s_info, &JSDedicatedWorkerGlobalScopePrototypeTable, CREATE_METHOD_TABLE(JSDedicatedWorkerGlobalScopePrototype) };

const ClassInfo JSDedicatedWorkerGlobalScope::s_info = { "DedicatedWorkerGlobalScope", &Base::s_info, &JSDedicatedWorkerGlobalScopeTable, CREATE_METHOD_TABLE(JSDedicatedWorkerGlobalScope) };

JSDedicatedWorkerGlobalScope::JSDedicatedWorkerGlobalScope(VM& vm, Structure* structure, Ref<DedicatedWorkerGlobalScope>&& impl)
    : JSWorkerGlobalScope(vm, structure, WTFMove(impl))
{
}

void JSDedicatedWorkerGlobalScope::finishCreation(VM& vm, JSProxy* proxy)
{
    Base::finishCreation(vm, proxy);

}

EncodedJSValue jsDedicatedWorkerGlobalScopeOnmessage(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 = toJSDedicatedWorkerGlobalScope(decodedThisValue);
    if (UNLIKELY(!castedThis)) {
        return throwGetterTypeError(*state, throwScope, "DedicatedWorkerGlobalScope", "onmessage");
    }
    UNUSED_PARAM(state);
    return JSValue::encode(eventHandlerAttribute(castedThis->wrapped(), eventNames().messageEvent));
}


EncodedJSValue jsDedicatedWorkerGlobalScopeDedicatedWorkerGlobalScopeConstructor(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 = toJSDedicatedWorkerGlobalScope(decodedThisValue);
    if (UNLIKELY(!castedThis)) {
        return throwGetterTypeError(*state, throwScope, "DedicatedWorkerGlobalScope", "DedicatedWorkerGlobalScope");
    }
    return JSValue::encode(JSDedicatedWorkerGlobalScope::getConstructor(state->vm(), castedThis->globalObject()));
}


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

bool setJSDedicatedWorkerGlobalScopeConstructor(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)
{
    VM& vm = state->vm();
    auto throwScope = DECLARE_THROW_SCOPE(vm);
    JSValue value = JSValue::decode(encodedValue);
    JSDedicatedWorkerGlobalScopePrototype* domObject = jsDynamicCast<JSDedicatedWorkerGlobalScopePrototype*>(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);
}

bool setJSDedicatedWorkerGlobalScopeOnmessage(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)
{
    VM& vm = state->vm();
    auto throwScope = DECLARE_THROW_SCOPE(vm);
    UNUSED_PARAM(throwScope);
    JSValue value = JSValue::decode(encodedValue);
    UNUSED_PARAM(thisValue);
    JSDedicatedWorkerGlobalScope* castedThis = toJSDedicatedWorkerGlobalScope(JSValue::decode(thisValue));
    if (UNLIKELY(!castedThis)) {
        return throwSetterTypeError(*state, throwScope, "DedicatedWorkerGlobalScope", "onmessage");
    }
    setEventHandlerAttribute(*state, *castedThis, castedThis->wrapped(), eventNames().messageEvent, value);
    return true;
}


bool setJSDedicatedWorkerGlobalScopeDedicatedWorkerGlobalScopeConstructor(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)
{
    VM& vm = state->vm();
    auto throwScope = DECLARE_THROW_SCOPE(vm);
    UNUSED_PARAM(throwScope);
    JSValue value = JSValue::decode(encodedValue);
    UNUSED_PARAM(thisValue);
    JSDedicatedWorkerGlobalScope* castedThis = toJSDedicatedWorkerGlobalScope(JSValue::decode(thisValue));
    if (UNLIKELY(!castedThis)) {
        return throwSetterTypeError(*state, throwScope, "DedicatedWorkerGlobalScope", "DedicatedWorkerGlobalScope");
    }
    // Shadowing a built-in constructor.
    return castedThis->putDirect(state->vm(), Identifier::fromString(state, "DedicatedWorkerGlobalScope"), value);
}


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

EncodedJSValue JSC_HOST_CALL jsDedicatedWorkerGlobalScopeInstanceFunctionPostMessage(ExecState* state)
{
    VM& vm = state->vm();
    auto throwScope = DECLARE_THROW_SCOPE(vm);
    UNUSED_PARAM(throwScope);
    JSDedicatedWorkerGlobalScope* castedThis = toJSDedicatedWorkerGlobalScope(state->thisValue().toThis(state, NotStrictMode));
    if (UNLIKELY(!castedThis))
        return throwVMTypeError(state, throwScope);
    ASSERT_GC_OBJECT_INHERITS(castedThis, JSDedicatedWorkerGlobalScope::info());
    return JSValue::encode(castedThis->postMessage(*state));
}

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

DedicatedWorkerGlobalScope* JSDedicatedWorkerGlobalScope::toWrapped(JSC::JSValue value)
{
    if (auto* wrapper = jsDynamicCast<JSDedicatedWorkerGlobalScope*>(value))
        return &wrapper->wrapped();
    return nullptr;
}

}
