/*
 * 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.
 */
/*
 *  JavaScript Interpreter
 *  The JavaScript Interpreter is used for executing JavaScript programs
 *  in EWB that control user events on buttons, restrict inputs on textlines
 *  and so on.
 *
 *  Developmened by: Institute of Artificial Intelligence & Robotics
 *                   of Xi'an Jiaotong University
 *
 *  Create by:      Tian Wenqiang
 *  Last modified:  2001-11-13 19:56
 */

/* JS host object class implement file */
#include "js-scriptruntime.h"
#include "js-nativehost.h"
/* #include "ewb-trace.h" */
#include "js-trace.h"

/* Class data */
const jsString_t JSNativeHost::className = "NativeHost";

/* Procedures */
jsClass_t *JSNativeHost::defaultClass()
{
    class DefaultClass {
      public:
        static jsString_t getClassName(jsContext_t context, jsObject_t object) {

            return JSNativeHost::className;
        } static jsBool_t has(jsContext_t context, jsObject_t object, jsString_t name, jsObject_t start) {
            JSContext *cx = (JSContext *) context;
            JSScriptable *_object = (JSScriptable *) object;
            JSScriptable *_start = (JSScriptable *) start;

            return ((JSNativeHost *) _object)
                    ->JSScriptableObject::has(cx, name, _start);
        }
        static jsBool_t get(jsContext_t context, jsObject_t object, jsString_t name, jsObject_t start, jsVal_t * value) {
            JSContext *cx = (JSContext *) context;
            JSScriptable *_object = (JSScriptable *) object;
            JSScriptable *_start = (JSScriptable *) start;

            return ((JSNativeHost *) _object)
                    ->JSScriptableObject::get(cx, name, _start, value);
        }
        static void put(jsContext_t context, jsObject_t object, jsString_t name, jsObject_t start, jsVal_t value) {
            JSContext *cx = (JSContext *) context;
            JSScriptable *_object = (JSScriptable *) object;
            JSScriptable *_start = (JSScriptable *) start;

            ((JSNativeHost *) _object)
                    ->JSScriptableObject::put(cx, name, _start, value);
        }
        static void del(jsContext_t context, jsObject_t object, jsString_t name) {
            JSContext *cx = (JSContext *) context;
            JSScriptable *_object = (JSScriptable *) object;

            ((JSNativeHost *) _object)->JSScriptableObject::del(cx, name);
        }
        static jsBool_t has(jsContext_t context, jsObject_t object, int index, jsObject_t start) {
            JSContext *cx = (JSContext *) context;
            JSScriptable *_object = (JSScriptable *) object;
            JSScriptable *_start = (JSScriptable *) start;

            return ((JSNativeHost *) _object)
                    ->JSScriptableObject::has(cx, index, _start);
        }
        static jsBool_t get(jsContext_t context, jsObject_t object, int index, jsObject_t start, jsVal_t * value) {
            JSContext *cx = (JSContext *) context;
            JSScriptable *_object = (JSScriptable *) object;
            JSScriptable *_start = (JSScriptable *) start;

            return ((JSNativeHost *) _object)
                    ->JSScriptableObject::get(cx, index, _start, value);
        }
        static void put(jsContext_t context, jsObject_t object, int index, jsObject_t start, jsVal_t value) {
            JSContext *cx = (JSContext *) context;
            JSScriptable *_object = (JSScriptable *) object;
            JSScriptable *_start = (JSScriptable *) start;

            ((JSNativeHost *) _object)
                    ->JSScriptableObject::put(cx, index, _start, value);
        }
        static void del(jsContext_t context, jsObject_t object, int index) {
            JSContext *cx = (JSContext *) context;
            JSScriptable *_object = (JSScriptable *) object;

            ((JSNativeHost *) _object)
                    ->JSScriptableObject::del(cx, index);

        }
        static jsObject_t getPrototype(jsContext_t context, jsObject_t object) {
            JSContext *cx = (JSContext *) context;
            JSScriptable *_object = (JSScriptable *) object;

            return ((JSNativeHost *) _object)
                    ->JSScriptableObject::getPrototype(cx);
        }
        static void setPrototype(jsContext_t context, jsObject_t object, jsObject_t proto) {
            JSContext *cx = (JSContext *) context;
            JSScriptable *_object = (JSScriptable *) object;
            JSScriptable *_proto = (JSScriptable *) proto;

            ((JSNativeHost *) _object)
                    ->JSScriptableObject::setPrototype(cx, _proto);
        }
        static jsObject_t getParentScope(jsContext_t context, jsObject_t object) {
            JSContext *cx = (JSContext *) context;
            JSScriptable *_object = (JSScriptable *) object;

            return ((JSNativeHost *) _object)
                    ->JSScriptableObject::getParentScope(cx);
        }
        static void setParentScope(jsContext_t context, jsObject_t object, jsObject_t parent) {
            JSContext *cx = (JSContext *) context;
            JSScriptable *_object = (JSScriptable *) object;
            JSScriptable *_parent = (JSScriptable *) parent;

            ((JSNativeHost *) _object)
                    ->JSScriptableObject::setParentScope(cx, _parent);
        }
        static jsVal_t *getIds(jsContext_t context, jsObject_t object, int *numIds) {
            JSContext *cx = (JSContext *) context;
            JSScriptable *_object = (JSScriptable *) object;

            return ((JSNativeHost *) _object)
                    ->JSScriptableObject::getIds(cx, numIds);
        }
        static jsVal_t getDefaultValue(jsContext_t context, jsObject_t object, jsType_t hint) {
            JSContext *cx = (JSContext *) context;
            JSScriptable *_object = (JSScriptable *) object;

            return ((JSNativeHost *) _object)
                    ->JSScriptableObject::getDefaultValue(cx, hint);
        }
        static jsBool_t hasInstance(jsContext_t context, jsObject_t object, jsObject_t instance) {
            JSContext *cx = (JSContext *) context;
            JSScriptable *_object = (JSScriptable *) object;
            JSScriptable *_instance = (JSScriptable *) object;

            return ((JSNativeHost *) _object)
                    ->JSScriptableObject::hasInstance(cx, _instance);
        }
        static void finalize(jsContext_t context, jsObject_t object) {
            JSContext *cx = (JSContext *) context;
            JSScriptable *_object = (JSScriptable *) object;

            ((JSNativeHost *) _object)
                    ->JSScriptableObject::finalize(cx);
        }
    };
    static jsClass_t clazz = {
        &DefaultClass::getClassName,
        &DefaultClass::has,
        &DefaultClass::get,
        &DefaultClass::put,
        &DefaultClass::del,
        &DefaultClass::has,
        &DefaultClass::get,
        &DefaultClass::put,
        &DefaultClass::del,
        &DefaultClass::getPrototype,
        &DefaultClass::setPrototype,
        &DefaultClass::getParentScope,
        &DefaultClass::setParentScope,
        &DefaultClass::getIds,
        &DefaultClass::getDefaultValue,
        &DefaultClass::hasInstance,
        &DefaultClass::finalize,
    };

    return &clazz;
}

void *JSNativeHost::getClosure()
{
    return closure;
}
void JSNativeHost::setClosure(void *closure)
{
    this->closure = closure;
}
jsBool_t JSNativeHost::isInstanceOf(const jsString_t className)
{
    if (className == JSNativeHost::className)
        return TRUE;
    return JSScriptableObject::isInstanceOf(className);
}

jsString_t JSNativeHost::getClassName(JSContext * cx)
{
    return clazz->getClassName((jsContext_t) cx, (jsObject_t) this);
}

jsBool_t JSNativeHost::get(JSContext * cx, jsString_t name, JSScriptable * start, jsVal_t * value)
{
    jsBool_t ret;

#ifndef SHELL
    EWBTPENT(11, "JsSerch");
#endif

    ret = clazz->get((jsContext_t) cx, (jsObject_t) this, name, (jsObject_t) start, value);

#ifndef SHELL
    EWBTPEXT(11);
#endif

    return ret;
}

jsBool_t JSNativeHost::get(JSContext * cx, int index, JSScriptable * start, jsVal_t * value)
{
    return clazz->getIndex((jsContext_t) cx, (jsObject_t) this, index, (jsObject_t) start, value);
}

jsBool_t JSNativeHost::has(JSContext * cx, jsString_t name, JSScriptable * start)
{
    jsBool_t ret;

#ifndef SHELL
    EWBTPENT(11, "JsSerch");
#endif

    ret = clazz->has((jsContext_t) cx, (jsObject_t) this, name, (jsObject_t) start);

#ifndef SHELL
    EWBTPEXT(11);
#endif

    return ret;
}

jsBool_t JSNativeHost::has(JSContext * cx, int index, JSScriptable * start)
{
    return clazz->hasIndex((jsContext_t) cx, (jsObject_t) this, index, (jsObject_t) start);
}

void JSNativeHost::put(JSContext * cx, jsString_t name, JSScriptable * start, jsVal_t value)
{

#ifndef SHELL
    EWBTPENT(11, "JsSerch");
#endif

    clazz->put((jsContext_t) cx, (jsObject_t) this, name, (jsObject_t) start, value);

#ifndef SHELL
    EWBTPEXT(11);
#endif

}

void JSNativeHost::put(JSContext * cx, int index, JSScriptable * start, jsVal_t value)
{
    clazz->putIndex((jsContext_t) cx, (jsObject_t) this, index, (jsObject_t) start, value);
}

void JSNativeHost::del(JSContext * cx, jsString_t name)
{
    clazz->del((jsContext_t) cx, (jsObject_t) this, name);
}
void JSNativeHost::del(JSContext * cx, int index)
{
    clazz->delIndex((jsContext_t) cx, (jsObject_t) this, index);
}

JSScriptable *JSNativeHost::getPrototype(JSContext * cx)
{
    return (JSScriptable *) clazz->getPrototype((jsContext_t) cx, (jsObject_t) this);
}

void JSNativeHost::setPrototype(JSContext * cx, JSScriptable * prototype)
{
    clazz->setPrototype((jsContext_t) cx, (jsObject_t) this, (jsObject_t) prototype);
}

JSScriptable *JSNativeHost::getParentScope(JSContext * cx)
{
    return (JSScriptable *) clazz->getParentScope((jsContext_t) cx, (jsObject_t) this);
}

void JSNativeHost::setParentScope(JSContext * cx, JSScriptable * parent)
{
    clazz->setParentScope((jsContext_t) cx, (jsObject_t) this, (jsObject_t) parent);
}
jsVal_t *JSNativeHost::getIds(JSContext * cx, int *numIds)
{
    return clazz->getIds((jsContext_t) cx, (jsObject_t) this, numIds);
}

jsVal_t JSNativeHost::getDefaultValue(JSContext * cx, jsType_t hint)
{
    return clazz->getDefaultValue((jsContext_t) cx, (jsObject_t) this, hint);
}

jsBool_t JSNativeHost::hasInstance(JSContext * cx, JSScriptable * instance)
{
    return clazz->hasInstance((jsContext_t) cx, (jsObject_t) this, (jsObject_t) instance);
}

jsVal_t JSNativeHost::call(JSContext * cx, JSScriptable * scope, JSScriptable * thisObj, int numArgs, jsVal_t * args)
{
    if (numArgs > 0) {
        return JSScriptRuntime::getElem(cx, JS_OBJECT_TO_VAL(this), args[0], scope);
    }
    return JS_VAL_VOID;
}

JSScriptable *JSNativeHost::construct(JSContext * cx, JSScriptable * scope, int numArgs, jsVal_t * args)
{
    return NULL;
}

void JSNativeHost::finalize(JSContext * cx)
{
    clazz->finalize((jsContext_t) cx, (jsObject_t) this);
}

JSNativeHost::JSNativeHost(jsClass_t * clazz)
{
    this->clazz = clazz;
    closure = NULL;
}

JSNativeHost::JSNativeHost(JSScriptable * proto)
{
    clazz = proto != NULL ? ((JSNativeHost *) proto)->clazz : defaultClass();
    closure = NULL;
}
