#pragma hdrfile "jsdb.csm"
#include "rslib.h"
#include "jsdb.h"
#include "rs/wrap_jsdb.h"
#pragma hdrstop

#ifndef TBL_NO_SQL

#include "rs/tbl_sql.h"
#include "rs/sql.h"
/* class ODBC

var db = new ODBC('connection string');
var table = db.query('SELECT * FROM table');
var db.exec('INSERT INTO table BLAH BLAH BLAH');

*/

WRAP_HELP(ODBC,"query('SELECT * FROM ...')\nexec('INSERT INTO ...')\n");


JSBool
ODBC_JSGet(JSContext *cx, JSObject *obj, jsval id, jsval *rval)
{
 const char * c = 0;
 count_t i = 0;

 GETOBJ(DBPointer,t);

 int x = JSVAL_TO_INT(id);

 if (JSVAL_IS_INT(id))
  switch (x)
  {
   case 0: c = (*t)->DriverName; break;
   case 3: RETSTR("ODBC");
   default: return JS_FALSE;
  }
 else return JS_FALSE;

 if (c) RETSTR(c);
 RETINT(i);
}


JSBool
ODBC_ODBC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
    jsval *rval)
{
 GETENV;
 if (!Env) return JS_FALSE;

 if (!Env->TableEnv) return JS_FALSE;

 ODBCEnv* tblenv = (ODBCEnv*)Env->TableEnv->odbcenv;
 if (!tblenv) return JS_FALSE;

 JSString* j0;
 char * s0;
 GETSTRING(0);
 if (!s0) ERR_TYPE(ODBC,Exec,1,String);
 if (!*s0) ERR_TYPE(ODBC,Exec,1,String);

 DBPointer* dbp;
 TStr Error;
 try {
  dbp = new DBPointer(tblenv->OpenDatabase(s0,Error));
 }
 catch (...)
 {
  if (Env->errorOnFailure)
    return JS_FALSE;
  dbp = 0;
 }

 if (!dbp || !*dbp)
   ERR_MSG(ODBC,new,Error);

 SETPRIVATE(obj,DBPointer,dbp,true,NULL);
// JS_SetPrivate(cx,obj,dt);

 return JS_TRUE;
}

void ODBC_JSFinalize(JSContext *cx, JSObject *obj)
{
 DELPRIVATE(DBPointer);
}

static JSBool
ODBC_Close(JSContext *cx,
 JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
 CLOSEPRIVATE(DBPointer);
 RETBOOL(true);
}

static JSBool
ODBC_ToString(JSContext *cx,
 JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
 GETOBJ(DBPointer,t);
 RETSTR((*t)->DriverName);
}

static JSBool
ODBC_Exec(JSContext *cx,
 JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
 GETOBJ(DBPointer,t);
 if (!argc) ERR_COUNT(ODBC,Exec);

 JSString* j0;
 char * s0;
 GETSTRING(0);
 if (!s0) ERR_TYPE(ODBC,Exec,1,String);
 if (!*s0) ERR_TYPE(ODBC,Exec,1,String);

 TStr Error;
 bool result = (*t)->ExecDirect(s0,Error,false);
 if (!result)
 {
  *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,(char*)Error));
  JS_SetProperty(cx, obj,"error",rval);
 }
 RETBOOL(result);
}

static JSBool
ODBC_Query(JSContext *cx,
 JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
 GETOBJ(DBPointer,t);
 if (!argc) ERR_COUNT(ODBC,Exec);

 JSString* j0;
 char * s0;
 GETSTRING(0);
 if (!s0) ERR_TYPE(ODBC,Query,1,String);
 if (!*s0) ERR_TYPE(ODBC,Query,1,String);

 try {
  DataTable * table = new ODBCTable(*t,0,0,s0);
  //DBPointer handles garbage collection for ODBCDb, but we
  //also want to close all open tables if the database is
  //explicitly closed or deleted.

  //handy to pre-load the first row of the result set and to estimate
  //the result set length.
  table->GetDataC(0,0);
//  table->LoadTable();
  RETOBJ(Table_Object(cx,table,true,GETPOINTER));

 } catch (xdb& x)
 {
  TStr Error(x.why()," ", x.info());
  *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,(char*)Error));
  JS_SetProperty(cx, obj,"error",rval);
  RETOBJ(NULL);
 }
 catch(...)
 {RETOBJ(NULL);}

}

static JSPropertySpec ODBC_properties[] = {
    {"name",      0,   JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT,ODBC_JSGet},
    {"className",3, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT,ODBC_JSGet},
    {0}
};

static JSFunctionSpec ODBC_functions[] = {
    {"query",     ODBC_Query,      1},
    {"exec",    ODBC_Exec, 1},
    {"toString",ODBC_ToString,0},
    {"close",ODBC_Close,0},
    {0}
};

static JSFunctionSpec ODBC_fnstatic[] = {
    {"help",  ODBC_HELP,    0},
    {0}
};

static JSClass ODBC_class = {
    "ODBC", JSCLASS_HAS_PRIVATE,         //ODBC_JSGet
    JS_PropertyStub,  JS_PropertyStub, JS_PropertyStub,   JS_PropertyStub,
    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,ODBC_JSFinalize
};

JSObject*
ODBC_Object(JSContext *cx, DBPointer* t,bool autodelete,JSPointerBase* Parent)
{
 JSObject* obj;
 GETENV;
 MAKENEW(ODBC);
 SETPRIVATE(obj,DBPointer,t,autodelete,Parent);


 return obj;
}

JSClass* ODBC_Class() {return &ODBC_class;}

void ODBC_InitClass(JSContext *cx, JSObject *obj)
{
 GETENV;
 INITCLASS(ODBC);
}

#endif
