/*
 * The contents of this file are subject to the Netscape Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/NPL/

 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.

 * The Original Code is Rhino code, released
 * May 6, 1999.

 * The Initial Developer of the Original Code is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1997-1999 Netscape Communications Corporation. All
 * Rights Reserved.

 * Contributor(s): 

 * Alternatively, the contents of this file may be used under the
 * terms of the GNU Public License (the "GPL"), in which case the
 * provisions of the GPL are applicable instead of those above.
 * If you wish to allow use of your version of this file only
 * under the terms of the GPL and not to allow others to use your
 * version of this file under the NPL, indicate your decision by
 * deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL.  If you do not delete
 * the provisions above, a recipient may use your version of this
 * file under either the NPL or the GPL.
 */
/* Header file */
#include "js-scriptruntime.h"
#include "js-evaluatorexception.h"
#include "js-exceptionhandler.h"
#include "js-ctorfunction.h"
#include "js-nativewith.h"

/* Internal data */
const jsString_t JSNativeWith::className = "With";

/* Procedures */
jsVal_t JSNativeWith::jsConstructor(JSContext * cx, int numArgs, jsVal_t * args, JSFunction * ctorObj, jsBool_t inNewExpr)
{
    cx->exceptionHandler->throwEx(JSContext::reportRuntimeError(cx, JSContext::getMessage(cx, "msg.cant.call.indirect %s", "With")));
    /* NOT REACHED */
    return JS_VAL_VOID;
}

void JSNativeWith::defineClass(JSContext * cx, JSScriptable * scope)
{
    JSScriptable *w = new(cx) JSNativeWith();

    w->setPrototype(cx, JSScriptableObject::getObjectPrototype(cx, scope));

    JSFunctionObject *f = new(cx) JSCtorFunction(cx, "With", className, jsConstructor, scope);

    f->addAsConstructor(cx, scope, w);
}
jsVal_t JSNativeWith::newWithSpecial(JSContext * cx, int numArgs, jsVal_t * args, JSFunction * ctorObj, jsBool_t inNewExpr)
{
    if (!inNewExpr) {
        cx->exceptionHandler->throwEx(JSContext::reportRuntimeError(cx, JSContext::getMessage(cx, "msg.only.from.new %s", "With")));
        /* NOT REACHED */
    }

    JSScriptRuntime::checkDeprecated(cx, "With");

    JSScriptable *scope = JSScriptableObject::getTopLevelScope(cx,
            (JSNativeFunction *) ctorObj);
    JSNativeWith *thisObj = new(cx) JSNativeWith();
    cx->pushLocalVal(JS_OBJECT_TO_VAL(thisObj));    // gc safe 20061124

    thisObj->setPrototype(cx, numArgs == 0 ? JSScriptableObject::getClassPrototype(cx, scope, "Object")
            : JSScriptRuntime::toObject(cx, scope, args[0]));
    thisObj->setParentScope(cx, scope);
    cx->popLocalVals(1);    // gc safe 20061124
    return JS_OBJECT_TO_VAL(thisObj);
}

jsBool_t JSNativeWith::isInstanceOf(const jsString_t className)
{
    return (className == JSNativeWith::className);
}

jsString_t JSNativeWith::getClassName(JSContext * cx)
{
    return JSNativeWith::className;
}

jsBool_t JSNativeWith::has(JSContext * cx, jsString_t id, JSScriptable * start)
{
    if (start == this) {
        start = prototype;
    }
    return prototype->has(cx, id, start);
}

jsBool_t JSNativeWith::has(JSContext * cx, int index, JSScriptable * start)
{
    if (start == this) {
        start = prototype;
    }
    return prototype->has(cx, index, start);
}

jsBool_t JSNativeWith::get(JSContext * cx, jsString_t id, JSScriptable * start, jsVal_t * value)
{
    if (start == this) {
        start = prototype;
    }
    return prototype->get(cx, id, start, value);
}

jsBool_t JSNativeWith::get(JSContext * cx, int index, JSScriptable * start, jsVal_t * value)
{
    if (start == this) {
        start = prototype;
    }
    return prototype->get(cx, index, start, value);
}

void JSNativeWith::put(JSContext * cx, jsString_t id, JSScriptable * start, jsVal_t value)
{
    if (start == this) {
        start = prototype;
    }
    prototype->put(cx, id, start, value);
}
void JSNativeWith::put(JSContext * cx, int index, JSScriptable * start, jsVal_t value)
{
    if (start == this) {
        start = prototype;
    }
    prototype->put(cx, index, start, value);
}

void JSNativeWith::del(JSContext * cx, jsString_t id)
{
    prototype->del(cx, id);
}
void JSNativeWith::del(JSContext * cx, int index)
{
    prototype->del(cx, index);
}

JSScriptable *JSNativeWith::getPrototype(JSContext * cx)
{
    return prototype;
}

void JSNativeWith::setPrototype(JSContext * cx, JSScriptable * prototype)
{
    this->prototype = prototype;
}

JSScriptable *JSNativeWith::getParentScope(JSContext * cx)
{
    return parent;
}

void JSNativeWith::setParentScope(JSContext * cx, JSScriptable * parent)
{
    this->parent = parent;
}
jsVal_t *JSNativeWith::getIds(JSContext * cx, int *numIds)
{
    return prototype->getIds(cx, numIds);
}

jsVal_t JSNativeWith::getDefaultValue(JSContext * cx, jsType_t typeHint)
{
    return prototype->getDefaultValue(cx, typeHint);
}

jsBool_t JSNativeWith::hasInstance(JSContext * cx, JSScriptable * value)
{
    return prototype->hasInstance(cx, value);
}

JSNativeWith::JSNativeWith()
{
    parent = NULL;
    prototype = NULL;

}

JSNativeWith::JSNativeWith(JSScriptable * parent, JSScriptable * prototype)
{
    this->parent = parent;
    this->prototype = prototype;
}
