#ifndef FACT_InterpreterV8
#define FACT_InterpreterV8

#include <map>
#include <string>

#ifdef HAVE_V8
#include <v8.h>
#endif

class InterpreterV8
{
    static InterpreterV8 *This;

    int fThreadId;

#ifdef HAVE_V8
    bool ReportException(v8::TryCatch* try_catch);
    bool ExecuteStringNT(const v8::Handle<v8::String> &code, const v8::Handle<v8::Value>  &file);
    bool ExecuteCode(const v8::Handle<v8::String> &code, const v8::Handle<v8::Value>  &file);
    bool ExecuteCode(const std::string &code, const std::string &file="");
    bool ExecuteFile(const std::string &name);

    v8::Handle<v8::Value> FuncWait(const v8::Arguments& args);
    v8::Handle<v8::Value> FuncSend(const v8::Arguments& args);
    v8::Handle<v8::Value> FuncSleep(const v8::Arguments& args);
    v8::Handle<v8::Value> FuncPrint(const v8::Arguments& args);
    v8::Handle<v8::Value> FuncInclude(const v8::Arguments& args);
    v8::Handle<v8::Value> FuncExit(const v8::Arguments& args);

    static v8::Handle<v8::Value> FuncVersion(const v8::Arguments&);
    static v8::Handle<v8::Value> WrapInclude(const v8::Arguments &args) { if (This) return This->FuncInclude(args); else return v8::Undefined(); }
    static v8::Handle<v8::Value> WrapPrint(const v8::Arguments &args)   { if (This) return This->FuncPrint(args);   else return v8::Undefined(); }
    static v8::Handle<v8::Value> WrapWait(const v8::Arguments &args)    { if (This) return This->FuncWait(args);    else return v8::Undefined(); }
    static v8::Handle<v8::Value> WrapSend(const v8::Arguments &args)    { if (This) return This->FuncSend(args);    else return v8::Undefined(); }
    static v8::Handle<v8::Value> WrapSleep(const v8::Arguments &args)   { if (This) return This->FuncSleep(args);   else return v8::Undefined(); }
    static v8::Handle<v8::Value> WrapExit(const v8::Arguments &args)    { if (This) return This->FuncExit(args);    else return v8::Undefined(); }
#endif

public:
    InterpreterV8() : fThreadId(-1)
    {
        This = this;
    }
    virtual ~InterpreterV8()
    {
        This = 0;
        // v8::Dispose();
    }

    virtual void JsLoad(const std::string &) { }
    virtual void JsStart(const std::string &) { }
    virtual void JsEnd(const std::string &) { }
    virtual void JsPrint(const std::string &) { }
    virtual void JsResult(const std::string &) { }
    virtual void JsException(const std::string &) { }
    virtual bool JsSend(const std::string &) { return true; }
    virtual void JsSleep(uint32_t) { }
    virtual int  JsWait(const std::string &, int32_t, uint32_t) { return -1; };

    bool JsRun(const std::string &, const std::map<std::string,std::string> & = std::map<std::string,std::string>());
    static void JsStop();
};

#ifndef HAVE_V8
inline bool InterpreterV8::JsRun(const std::string &, const std::map<std::string,std::string> & = std::map<std::string,std::string>()) { return false; }
inline void InterpreterV8::JsStop() { }
#endif

#endif
