#include "AmPlugIn.h"
#include "log.h"
#include "DILog.h"


#include <iostream>
#include <fstream>
#include <sstream>

#include <stdarg.h>

using namespace std;

#define MOD_NAME "di_log"
#include "log.h"

EXPORT_LOG_FACILITY_FACTORY(DILog, MOD_NAME);
EXPORT_PLUGIN_CLASS_FACTORY(DILog, MOD_NAME);

char DILog::ring_buf[MAX_LINES][MAX_LINE_LEN] = {{0}};
int DILog::pos = 0;

DILog::DILog(const string& name) : AmLoggingFacility(name), AmDynInvokeFactory(name) {
}

DILog* DILog::_instance=0;

DILog* DILog::instance() {
  if(_instance == NULL){
    _instance = new DILog(MOD_NAME);
  }
  return _instance;
}

int DILog::onLoad() {
  DBG("DILog logging ring-buffer loaded.\n");
  return 0;
}

DILog::~DILog() { }

void DILog::invoke(const string& method, const AmArg& args, AmArg& ret) {
  if(method == "dumplog") {
    ret.push(dumpLog().c_str());
  } else if(method == "dumplogtodisk") {
    dumpLog(args.get(0).asCStr());
    ret.push("dumped to disk.\n");
  } else if(method == "help") {
    ret.push("dumplog\n"
	     "dumplogtodisk <path>\n"
	     );
  } else throw AmDynInvoke::NotImplemented(method);
}

void DILog::dumpLog(const char* path) {
  fstream fs(path, ios::out);
  int start = (pos + 1) % MAX_LINES;
  for(int i=0; i<MAX_LINES; i++) {
    fs << ring_buf[(i+start)%MAX_LINES];
  }
}

string DILog::dumpLog() {
  stringstream log;

  int start = (pos + 1) % MAX_LINES;
  for(int i=0; i<MAX_LINES; i++) {
    log << ring_buf[(i+start)%MAX_LINES];
  }
  log << endl;
  return log.str();
}

void DILog::log(int level, pid_t pid, pthread_t tid, 
		const char* func, const char* file, int line, char* msg) {
  strncpy(ring_buf[pos], msg, sizeof(ring_buf[0]));
  pos = (pos + 1) % MAX_LINES;
}

// todo: new() array on load, provide DI for resizing