/***************************************************************************
 *   Copyright (C) 2006 by TAM(Teppei Tamra)                               *
 *   tam-t@par.odn.ne.jp                                                   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program 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 General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "jsproc.h"

#define XP_UNIX 1
#define SVR4 1
#define SYSV 1
#define _BSD_SOURCE 1
#define POSIX_SOURCE 1
#define DARWIN 1

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

#include <jsapi.h>
#include <string.h>

namespace Honoka {
class JSProcPriv {
public:
    JSRuntime *jsrt;
    JSContext *jsct;
    JSObject *jsobj;
};
}

JSProc::JSProc(const string &filename)
{
    jspriv = new JSProcPriv();
    jspriv->jsrt = NULL;
    jspriv->jsct = NULL;
    jspriv->jsobj = NULL;
    JSClass jscs = {
        "global",0,
        JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,
        JS_EnumerateStub,JS_ResolveStub,JS_ConvertStub,JS_FinalizeStub
    };
    
    int fd = open(filename.c_str(),O_RDONLY);
    if (fd == -1) return;
    off_t mmapsize = lseek(fd,0,SEEK_END);
    char * mmapptr = (char *)mmap(0,mmapsize,PROT_READ,MAP_PRIVATE,fd,0);
    
    jspriv->jsrt = JS_NewRuntime(64L * 1024L * 1024L);
    if (!jspriv->jsrt) return;
    jspriv->jsct = JS_NewContext(jspriv->jsrt, 8192);
    if (!jspriv->jsct) {
        JS_DestroyRuntime(jspriv->jsrt);
        jspriv->jsrt = NULL;
        return;
    }
    jspriv->jsobj = JS_NewObject(jspriv->jsct, &jscs, NULL, NULL);
    if (!jspriv->jsobj) {
        JS_DestroyContext(jspriv->jsct);
        jspriv->jsct = NULL;
        JS_DestroyRuntime(jspriv->jsrt);
        jspriv->jsrt = NULL;
        return;
    }
    if (!JS_InitStandardClasses(jspriv->jsct,jspriv->jsobj)) {
        JS_DestroyContext(jspriv->jsct);
        jspriv->jsct = NULL;
        JS_DestroyRuntime(jspriv->jsrt);
        jspriv->jsrt = NULL;
        return;
    }
    
    jsval rval;
    JSString *str;
    uintN lino;
    if (!JS_EvaluateScript(jspriv->jsct,jspriv->jsobj,mmapptr,mmapsize,"script",lino, &rval)) {
        JS_DestroyContext(jspriv->jsct);
        jspriv->jsct = NULL;
        JS_DestroyRuntime(jspriv->jsrt);
        jspriv->jsrt = NULL;
        return;
    }
    munmap(mmapptr,mmapsize);
    close(fd);
    return;
}


JSProc::~JSProc()
{
    if (jspriv->jsct) JS_DestroyContext(jspriv->jsct);
    if (jspriv->jsrt) JS_DestroyRuntime(jspriv->jsrt);
    delete jspriv;
}




/*!
    \fn JSProc::eval(const string &script)
 */
string JSProc::eval(const string &script)
{
    if (!jspriv->jsct) return string();
    jsval rval;
    JSString *str;
    uintN lino;
    if (!JS_EvaluateScript(jspriv->jsct,jspriv->jsobj,script.c_str(),strlen(script.c_str()),"script",lino, &rval)) {
        return string();
    }
    str = JS_ValueToString(jspriv->jsct,rval);
    return string(JS_GetStringBytes(str),strlen(JS_GetStringBytes(str)));
}
