/*
 * 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-arguments.h"
#include "js-evaluatorexception.h"
#include "js-exceptionhandler.h"
#include "js-nativecall.h"

/* Internal data */
const jsString_t	JSNativeCall::className = "Call";

/* Procedures */
jsVal_t
JSNativeCall::jsConstructor(JSContext *cx, int numArgs, jsVal_t *args,
			JSFunction *ctorObj, jsBool_t inNewExpr)
{
    if (!inNewExpr) {
	cx->exceptionHandler->throwEx(
                cx,
                JSContext::reportRuntimeError(cx,
                    JSContext::getMessage(cx, "msg.only.from.new %s",
                        JSNativeCall::className)));
	/* NOT REACHED */
    }
    JSScriptRuntime::checkDeprecated(cx, "Call");

    JSNativeCall *result = new (cx) JSNativeCall();

    result->setPrototype(cx,
		getObjectPrototype(cx, (JSNativeFunction *) ctorObj));
    return JS_OBJECT_TO_VAL(result);
}

void
JSNativeCall::defineClass(JSContext *cx, JSScriptable *scope)
{
    JSScriptable *proto = new (cx) JSNativeCall();

    JSScriptableObject::defineClass(cx, scope, proto, jsConstructor, NULL);
}
JSNativeCall *
JSNativeCall::getActivation(JSNativeFunction *f)
{
    JSNativeCall *x = this;

    do {   
        if (x->funObj == f) {
            return x;
	}
        x = x->caller;
    } while (x != NULL);
    return NULL;
}
JSNativeFunction *
JSNativeCall::getFunctionObject()
{
    return funObj;
}
jsVal_t *
JSNativeCall::getOriginalArguments(int *numOriginalArgs)
{
    *numOriginalArgs = this->numOriginalArgs;
    return originalArgs;
}
JSNativeCall *
JSNativeCall::getCaller()
{
    return caller;
}
   
JSScriptable *
JSNativeCall::getThisObj()
{
    return thisObj;
}
jsBool_t 
JSNativeCall::isInstanceOf(jsString_t className)
{
    if (className == JSNativeCall::className) return TRUE;
    return JSScriptableObject::isInstanceOf(className);
}
jsString_t
JSNativeCall::getClassName(JSContext *cx)
{
    return JSNativeCall::className;
}
void
JSNativeCall::mark(JSContext *cx)
{
    JSGCHeap *gcHeap = &cx->runtime->gcHeap;
 
    if (gcHeap->isMarkObj(this)) return;

    JSScriptableObject::mark(cx);
 
    if (funObj != NULL) funObj->mark(cx);
    if (thisObj != NULL) thisObj->mark(cx);
    if (caller != NULL) caller->mark(cx);
	if (originalArgs != NULL) gcHeap->markObj(originalArgs); /* '04.05.06 Y.Tanaka */
}
void
JSNativeCall::initialize(JSContext *cx, JSScriptable *scope,
			JSNativeFunction *funObj, JSScriptable *thisObj)
{
    this->funObj = funObj;
    this->thisObj = thisObj;
  
    setParentScope(cx, scope);
    // leave prototype null
  
    // save current activation
    this->caller = cx->currentActivation;
    cx->currentActivation = this;

    numOriginalArgs = 0;
    originalArgs = NULL;
}

JSNativeCall::JSNativeCall(JSContext *cx, JSScriptable *scope,
			JSNativeFunction *funObj, JSScriptable *thisObj,
			int numArgs, jsVal_t *args)
{
    initialize(cx, scope, funObj, thisObj);
    
    cx->pushLocalVal(JS_OBJECT_TO_VAL(this)); // avoid gc in initialize args
    numOriginalArgs = numArgs;
    if (numArgs > 0) {
	originalArgs = (jsVal_t *) JS_NewGCObj(cx, sizeof (*originalArgs)
						* numArgs);
	memcpy(originalArgs, args, sizeof (*originalArgs) * numArgs);
    }

    // initialize values of arguments
    jsString_t *names = funObj->names;

    if (names != NULL) {
        for (int i = 0; i < funObj->argCount; i++) {
            jsVal_t val = i < numArgs ? args[i] : JS_VAL_VOID;

            JSScriptableObject::put(cx, names[i + 1], this, val);
        }
    }
  
    // initialize "arguments" property
    JSScriptableObject::put(cx, "arguments", this,
				JS_OBJECT_TO_VAL(
					new (cx) JSArguments(cx, this)));
    cx->popLocalVals(1);
}
JSNativeCall::JSNativeCall(JSContext *cx, JSScriptable *scope,
			JSNativeFunction *funObj, JSScriptable *thisObj)
{
    initialize(cx, scope, funObj, thisObj);
}
JSNativeCall::JSNativeCall()
{
    caller = NULL;

    funObj = NULL;
    thisObj = NULL;
  
    numOriginalArgs = 0;
    originalArgs = NULL;
}

