/*
  This is a module which implements output of the log to a sqlite database. 
  The database is much easier for searching the log

  copyright: see file COPYRIGHT

  Mark Koennecke, February 2016
*/

#include <stdio.h>
#include <logv2.h>
#include <sqlite3.h>
#include <sicsutil.h>
#include <sics.h>

static sqlite3 *db = NULL;
static char sqliteFile[1024];
static unsigned int lineCount = 0;
static unsigned int sqlActive = 0;

/*----------------------------------------------------------------------------------*/
static  void SqlFlush(void)
{
  char *err;

  if(sqlActive == 1 && db != NULL){
    sqlite3_exec(db,"END TRANSACTION",NULL,NULL,&err);
    lineCount = 0;
  }
}
/*----------------------------------------------------------------------------------
  The callback function for entering data into the log
  ------------------------------------------------------------------------------------*/
static void SqliteCallback(unsigned int severity, const char *timeStamp, 
			    const char *subsystem, 
			    const char *message, void *userData)
{
  double tVal = DoubleTime();
  char sql[2024];
  int status;
  char *err;

  if(logFilter(severity,subsystem,message) == 1) {
    return;
  }
  
  if(lineCount == 0){
    sqlite3_exec(db,"BEGIN TRANSACTION",NULL,NULL,&err);
  }

  sqlite3_snprintf(sizeof(sql),sql,"INSERT into log VALUES(%f,\"%s\",%d,\"%s\",\"%w\")",
	   tVal,timeStamp,severity,subsystem,message);
  status = sqlite3_exec(db,sql,NULL,NULL,&err);
  if(status != SQLITE_OK){
    printf("Sqlite logging error: %s from %s\n", err, sql);
    sqlite3_free(err);
  }
  lineCount++;

  if(lineCount >= 1000){
    SqlFlush();
  }
}
/*-----------------------------------------------------------------------------------*/
static void SqlClose(void *data)
{
  char *err;

  if(sqlActive == 1 && db != NULL){
       sqlite3_exec(db,"END TRANSACTION",NULL,NULL,&err);
       sqlite3_close(db);
       RemoveLogCallback(SqliteCallback);
       sqlActive = 0;
  }
}
/*------------------------------------------------------------------------------------*/
static int SQLLogConfigAction(SConnection * pCon, SicsInterp * pSics,
                            void *pData, int argc, char *argv[])
{
  int status;

  if(argc < 2) {
    SCWrite(pCon,"ERROR: need keyword", eError);
    return 0;  
  }

   strtolower(argv[1]);
   if(strcmp(argv[1],"open") == 0){
     if(argc < 3){
       SCWrite(pCon,"ERROR: need dbfilename parameter for open",eError);
       return 0;
     }
     strncpy(sqliteFile,argv[2],sizeof(sqliteFile));
     status = sqlite3_open(sqliteFile,&db);
     if(status){
       SCPrintf(pCon,eError,"ERROR: failed to open database %s", argv[2]);
       sqlite3_close(db);
       return 0;
     } else {
       RegisterLogCallback(SqliteCallback,NULL);
       sqlActive = 1;
       SCSendOK(pCon);
     }
   } else if(strcmp(argv[1],"close") == 0) {
       SqlClose(NULL);
       SCSendOK(pCon);
   } else if(strcmp(argv[1],"flush") == 0) {
       SqlFlush();
       SCSendOK(pCon);
   } else if(strcmp(argv[1],"filename") == 0) {
     SCPrintf(pCon,eValue,"sqlitedb = %s", sqliteFile);
   } else {
     SCPrintf(pCon,eError,"ERROR: keyword %s not recognised", argv[1]);
     return 0;
   }
   return 1;
}
/*-----------------------------------------------------------------------------*/
void SqliteLogInit(void)
{
  AddCommand(pServ->pSics,"sqlconfig", SQLLogConfigAction,
               SqlClose, NULL);
}

