/*
 * 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.
 */
#ifdef NATIVE_DEBUG
/* Header file */
#include <stdio.h>
#ifdef VX
#include <vxWorks.h>
#include <taskLib.h>
#include <stdio.h>
#endif
#include "js-new.h"
#include "js-scriptruntime.h"
#include "js-exceptionhandler.h"
#include "js-scriptableobject.h"
#include "js-api.h"
#include "js-nativedebug.h"
/* #include "ewb-trace.h" */
#include "js-trace.h"
#include "js-frame.h"
#include "js-interpreterdata.h"

/* Class data */
const jsString_t JSNativeDebug::className = "Debug";

/* Procedures */
/**
 * Print the string values of its arguments.
 *
 * This method is defined as a JavaScript function.
 * Note that its arguments are of the "varargs" form, which
 * allows it to handle an arbitrary number of arguments
 * supplied to the JavaScript function.
 *
 */
#ifdef WEBUI
#if 0
#include	"ewb-sys-if.h"
#else
#define EWB_LOG_DEBUG 2
#define EWB_LOG_INFO 3
#define EWB_LOG_WARN 4
#define EWB_LOG_ERROR 5
#endif
extern "C" void EwbSetServerLog(int id, void *data);
#endif
#ifndef SHELL
extern int ewbPrintOn;
#endif

jsVal_t JSNativeDebug::print(JSContext * cx, JSScriptable * thisObj, int numArgs, jsVal_t * args, JSFunction * funObj)
{
    char buff[181];
    buff[0] = '\0';

    for (int i = 0; i < numArgs; i++) {
        if (i > 0) {
            strncat(buff, " ", sizeof(buff) - strlen(buff) - 1);
            //printf(" ");
        }

        // Convert the arbitrary JavaScript value into a string form.
        jsString_t s = cx->toString(args[i]);
        strncat(buff, s, sizeof(buff) - strlen(buff) - 1);
        //printf("%s", s);
    }
    //printf("\n");
    strncat(buff, "\n", sizeof(buff) - strlen(buff) - 1);
#ifdef WEBUI
    EwbSetServerLog(EWB_LOG_INFO, buff);
#endif
#ifndef SHELL
    if (ewbPrintOn) {
        printf("[Info]%s", buff);
    }
#endif
    return JS_VAL_VOID;
}

jsVal_t JSNativeDebug::printdbg(JSContext * cx, JSScriptable * thisObj, int numArgs, jsVal_t * args, JSFunction * funObj)
{
    char buff[181];
    buff[0] = '\0';

    for (int i = 0; i < numArgs; i++) {
        if (i > 0) {
            strncat(buff, " ", sizeof(buff) - strlen(buff) - 1);
            //printf(" ");
        }

        // Convert the arbitrary JavaScript value into a string form.
        jsString_t s = cx->toString(args[i]);
        strncat(buff, s, sizeof(buff) - strlen(buff) - 1);
        //printf("%s", s);
    }
    //printf("\n");
    strncat(buff, "\n", sizeof(buff) - strlen(buff) - 1);
#ifdef WEBUI
    EwbSetServerLog(EWB_LOG_DEBUG, buff);
#endif
#ifndef SHELL
    if (ewbPrintOn) {
        printf("[Debug]%s", buff);
    }
#endif
    return JS_VAL_VOID;
}

jsVal_t JSNativeDebug::printwarn(JSContext * cx, JSScriptable * thisObj, int numArgs, jsVal_t * args, JSFunction * funObj)
{
    char buff[181];
    buff[0] = '\0';

    for (int i = 0; i < numArgs; i++) {
        if (i > 0) {
            strncat(buff, " ", sizeof(buff) - strlen(buff) - 1);
            //printf(" ");
        }

        // Convert the arbitrary JavaScript value into a string form.
        jsString_t s = cx->toString(args[i]);
        strncat(buff, s, sizeof(buff) - strlen(buff) - 1);
        //printf("%s", s);
    }
    //printf("\n");
    strncat(buff, "\n", sizeof(buff) - strlen(buff) - 1);
#ifdef WEBUI
    EwbSetServerLog(EWB_LOG_WARN, buff);
#endif
#ifndef SHELL
    if (ewbPrintOn) {
        printf("[Warn]%s", buff);
    }
#endif
    return JS_VAL_VOID;
}

jsVal_t JSNativeDebug::printerr(JSContext * cx, JSScriptable * thisObj, int numArgs, jsVal_t * args, JSFunction * funObj)
{
    char buff[181];
    buff[0] = '\0';

    for (int i = 0; i < numArgs; i++) {
        if (i > 0) {
            strncat(buff, " ", sizeof(buff) - strlen(buff) - 1);
            //printf(" ");
        }

        // Convert the arbitrary JavaScript value into a string form.
        jsString_t s = cx->toString(args[i]);
        strncat(buff, s, sizeof(buff) - strlen(buff) - 1);
        //printf("%s", s);
    }
    //printf("\n");
    strncat(buff, "\n", sizeof(buff) - strlen(buff) - 1);
#ifdef WEBUI
    EwbSetServerLog(EWB_LOG_ERROR, buff);
#endif
#ifndef SHELL
    if (ewbPrintOn) {
        printf("[Err]%s", buff);
    }
#endif
    return JS_VAL_VOID;
}

jsVal_t JSNativeDebug::trace(JSContext * cx, JSScriptable * thisObj, int numArgs, jsVal_t * args, JSFunction * funObj)
{
    if (numArgs > 0) {

        // Convert the arbitrary JavaScript value into a string form.
#ifndef SHELL
        jsString_t s = cx->toString(args[0]);

        EWBTIME("*trace*", (char *)s);
#endif

//  printf("%s\n", s);
    }
    return JS_VAL_VOID;
}

jsVal_t JSNativeDebug::where(JSContext * cx, JSScriptable * thisObj, int numArgs, jsVal_t * args, JSFunction * funObj)
{
    int i = 0;
    JSFrame *a;
    a = (JSFrame *) lstLast(&(cx->frames));

    while (1) {
        if ((a->theData->itsName != NULL)) {
            printf("#%d %s at %s\n", i, (a->theData->itsName), (a->theData->itsSourceFile));
        }
        else {
            printf("NULL \n");
        }

        if (lstPrevious((NODE *) a) != NULL) {
            a = (JSFrame *) lstPrevious((NODE *) a);
        }
        else {
            break;
        }
        i++;
    }
    return JS_VAL_VOID;
}

void JSNativeDebug::defineClass(JSContext * cx, JSScriptable * scope)
{
    class DebugAdapter {
      public:
        static jsVal_t jsFunction_gc(JSContext * cx, JSScriptable * thisObj, int numArgs, jsVal_t * args, JSFunction * funObj) {
            JSNativeDebug::gc(cx);
            return JS_VAL_VOID;
        } static jsVal_t jsFunction_sleep(JSContext * cx, JSScriptable * thisObj, int numArgs, jsVal_t * args, JSFunction * funObj) {
            if (numArgs > 0) {
                JSNativeDebug::sleep((int)JSScriptRuntime::toNumber(cx, args[0]));
            }
            return JS_VAL_VOID;
        }
    };

    static JSScriptableObject::jsFunction_t functions[] = {
#define Item(name, length)      { #name,  name, length }
#define ItemAdapter(name, clazz, length)        \
                                { #name,  &clazz::jsFunction_##name, length }
        Item(print, -1),
        Item(printdbg, -1),
        Item(printerr, -1),
        Item(printwarn, -1),
        Item(trace, -1),
        Item(where, -1),
        ItemAdapter(gc, DebugAdapter, 0),
        ItemAdapter(sleep, DebugAdapter, 0),
#undef  ItemAdapter
#undef  Item
    };

    ((JSScriptableObject *) scope)->defineFunctionProperties(cx, className, TableSize(functions), functions, JS_PA_DontEnum);
}

void JSNativeDebug::gc(JSContext * cx)
{
    cx->runtime->gcHeap.gc();
}

#ifdef VX
extern "C" int sysClkRateGet();
#endif
void JSNativeDebug::sleep(int milliseconds)
{
#ifdef VX
    taskDelay(milliseconds * sysClkRateGet() / 1000);
#else
    struct timespec timespec;

    timespec.tv_sec = milliseconds / 1000;
    timespec.tv_nsec = (milliseconds % 1000) * 1000;
    nanosleep(&timespec, NULL);
#endif
}
#endif /* NATIVE_DEBUG */
