/*
    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 "JSStyleMedia.h"

#include "KURL.h"
#include "StyleMedia.h"
#include <runtime/Error.h>
#include <runtime/JSString.h>
#include <wtf/GetPtr.h>

using namespace JSC;

namespace WebCore {

ASSERT_CLASS_FITS_IN_CELL(JSStyleMedia);

/* Hash table */

static const HashTableValue JSStyleMediaTableValues[3] =
{
    { "type", DontDelete|ReadOnly, (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsStyleMediaType), (intptr_t)0 },
    { "constructor", DontEnum|ReadOnly, (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsStyleMediaConstructor), (intptr_t)0 },
    { 0, 0, 0, 0 }
};

static JSC_CONST_HASHTABLE HashTable JSStyleMediaTable =
#if ENABLE(PERFECT_HASH_SIZE)
    { 3, JSStyleMediaTableValues, 0 };
#else
    { 4, 3, JSStyleMediaTableValues, 0 };
#endif

/* Hash table for constructor */

static const HashTableValue JSStyleMediaConstructorTableValues[1] =
{
    { 0, 0, 0, 0 }
};

static JSC_CONST_HASHTABLE HashTable JSStyleMediaConstructorTable =
#if ENABLE(PERFECT_HASH_SIZE)
    { 0, JSStyleMediaConstructorTableValues, 0 };
#else
    { 1, 0, JSStyleMediaConstructorTableValues, 0 };
#endif

class JSStyleMediaConstructor : public DOMConstructorObject {
public:
    JSStyleMediaConstructor(ExecState* exec, JSDOMGlobalObject* globalObject)
        : DOMConstructorObject(JSStyleMediaConstructor::createStructure(globalObject->objectPrototype()), globalObject)
    {
        putDirect(exec->propertyNames().prototype, JSStyleMediaPrototype::self(exec, globalObject), None);
    }
    virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
    virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
    virtual const ClassInfo* classInfo() const { return &s_info; }
    static const ClassInfo s_info;

    static PassRefPtr<Structure> createStructure(JSValue proto) 
    { 
        return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); 
    }
    
protected:
    static const unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | DOMConstructorObject::StructureFlags;
};

const ClassInfo JSStyleMediaConstructor::s_info = { "StyleMediaConstructor", 0, &JSStyleMediaConstructorTable, 0 };

bool JSStyleMediaConstructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
    return getStaticValueSlot<JSStyleMediaConstructor, DOMObject>(exec, &JSStyleMediaConstructorTable, this, propertyName, slot);
}

bool JSStyleMediaConstructor::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
    return getStaticValueDescriptor<JSStyleMediaConstructor, DOMObject>(exec, &JSStyleMediaConstructorTable, this, propertyName, descriptor);
}

/* Hash table for prototype */

static const HashTableValue JSStyleMediaPrototypeTableValues[2] =
{
    { "matchMedium", DontDelete|Function, (intptr_t)static_cast<NativeFunction>(jsStyleMediaPrototypeFunctionMatchMedium), (intptr_t)1 },
    { 0, 0, 0, 0 }
};

static JSC_CONST_HASHTABLE HashTable JSStyleMediaPrototypeTable =
#if ENABLE(PERFECT_HASH_SIZE)
    { 0, JSStyleMediaPrototypeTableValues, 0 };
#else
    { 2, 1, JSStyleMediaPrototypeTableValues, 0 };
#endif

const ClassInfo JSStyleMediaPrototype::s_info = { "StyleMediaPrototype", 0, &JSStyleMediaPrototypeTable, 0 };

JSObject* JSStyleMediaPrototype::self(ExecState* exec, JSGlobalObject* globalObject)
{
    return getDOMPrototype<JSStyleMedia>(exec, globalObject);
}

bool JSStyleMediaPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
    return getStaticFunctionSlot<JSObject>(exec, &JSStyleMediaPrototypeTable, this, propertyName, slot);
}

bool JSStyleMediaPrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
    return getStaticFunctionDescriptor<JSObject>(exec, &JSStyleMediaPrototypeTable, this, propertyName, descriptor);
}

const ClassInfo JSStyleMedia::s_info = { "StyleMedia", 0, &JSStyleMediaTable, 0 };

JSStyleMedia::JSStyleMedia(NonNullPassRefPtr<Structure> structure, JSDOMGlobalObject* globalObject, PassRefPtr<StyleMedia> impl)
    : DOMObjectWithGlobalPointer(structure, globalObject)
    , m_impl(impl)
{
}

JSStyleMedia::~JSStyleMedia()
{
    forgetDOMObject(this, impl());
}

JSObject* JSStyleMedia::createPrototype(ExecState* exec, JSGlobalObject* globalObject)
{
    return new (exec) JSStyleMediaPrototype(JSStyleMediaPrototype::createStructure(globalObject->objectPrototype()));
}

bool JSStyleMedia::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
    return getStaticValueSlot<JSStyleMedia, Base>(exec, &JSStyleMediaTable, this, propertyName, slot);
}

bool JSStyleMedia::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
    return getStaticValueDescriptor<JSStyleMedia, Base>(exec, &JSStyleMediaTable, this, propertyName, descriptor);
}

JSValue jsStyleMediaType(ExecState* exec, JSValue slotBase, const Identifier&)
{
    JSStyleMedia* castedThis = static_cast<JSStyleMedia*>(asObject(slotBase));
    UNUSED_PARAM(exec);
    StyleMedia* imp = static_cast<StyleMedia*>(castedThis->impl());
    JSValue result = jsString(exec, imp->type());
    return result;
}

JSValue jsStyleMediaConstructor(ExecState* exec, JSValue slotBase, const Identifier&)
{
    JSStyleMedia* domObject = static_cast<JSStyleMedia*>(asObject(slotBase));
    return JSStyleMedia::getConstructor(exec, domObject->globalObject());
}
JSValue JSStyleMedia::getConstructor(ExecState* exec, JSGlobalObject* globalObject)
{
    return getDOMConstructor<JSStyleMediaConstructor>(exec, static_cast<JSDOMGlobalObject*>(globalObject));
}

JSValue JSC_HOST_CALL jsStyleMediaPrototypeFunctionMatchMedium(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
{
    UNUSED_PARAM(args);
    if (!thisValue.inherits(&JSStyleMedia::s_info))
        return throwError(exec, TypeError);
    JSStyleMedia* castedThisObj = static_cast<JSStyleMedia*>(asObject(thisValue));
    StyleMedia* imp = static_cast<StyleMedia*>(castedThisObj->impl());
    const UString& mediaquery = args.at(0).toString(exec);


    JSC::JSValue result = jsBoolean(imp->matchMedium(mediaquery));
    return result;
}

JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, StyleMedia* object)
{
    return getDOMObjectWrapper<JSStyleMedia>(exec, globalObject, object);
}
StyleMedia* toStyleMedia(JSC::JSValue value)
{
    return value.inherits(&JSStyleMedia::s_info) ? static_cast<JSStyleMedia*>(asObject(value))->impl() : 0;
}

}
