#include "DynamicWeaver.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> // open
#include <unistd.h> // fstat, getpid
#include <dlfcn.h> // dlopen
#include <signal.h>
#include <cstdio> // fprintf
#include <cstdlib>

static const char *fifo_name = "dynamicweaver.fifo";
static const int fifo_permissions = 0666;

// global instance of the dynamic weaver
DynamicWeaver weaver(29);

void weave_handler(int signal) {
  int fd;
  char buf[1024];
  int n;
  struct stat stat_buf;

  fprintf(stderr, "Aspectloader with signal(%d) now active.\n", signal);

  // open the fifo	
  if ((fd = open(fifo_name, O_RDONLY)) == -1 ) {
    perror("weave_handler, open");
    return;
  }
	
  // check if we got the filename of the fifo in the buffer
  n = read(fd, buf, sizeof (buf));
	
  // hack for handling filenames from the shell
  if(buf[n-1] == '\n')
    buf[n-1] = '\0';
	  
  if(stat(buf, &stat_buf)) {
    fprintf(stderr, "weave_handler, stat: while trying to load '%s'\n", buf);
    perror("weave_handler, stat");
    return;
  }
	
  // tell dynamic weaver to actually load the aspect object
  weaver.load_aspect(buf);
  close(fd);
}

// TODO: signal handler, actual loading and unloading of shared objects
DynamicWeaver::DynamicWeaver(int signo) 
 : _signal(signo) {

  fprintf(stderr, "DynamicWeaver starting with pid %d\n", getpid());
  // don't care for error codes for now
  unlink(fifo_name);

  if (mkfifo(fifo_name, fifo_permissions)) {
    perror("weave_hander, mkfifo");
    exit(EXIT_FAILURE);
  }

#if 1
  // based on http://gnu.edgescape.com/software/libc/manual/html_node/Sigaction-Function-Example.html
  struct sigaction new_action;
 
  new_action.sa_handler = weave_handler;
  sigemptyset (&new_action.sa_mask);
  new_action.sa_flags = SA_RESTART;
  fprintf(stderr, "sa_flags are: %d\n:", new_action.sa_flags);

  sigaction (_signal, &new_action, NULL);

#else
  // setup signal handler
  signal(_signal, weave_handler);
#endif

  fprintf(stderr, "Registered Signalhandler at signal %d.\n", _signal);

}

void DynamicWeaver::load_aspect(char *filename) {
  void *handle;

  fprintf(stderr, "loading Aspect Object %s\n", filename);
  handle = dlopen(filename, RTLD_NOW);
  if (!handle) {
    fprintf(stderr, "%s\n", dlerror());
    return;
  }
  
  dlerror(); /* clear any existing error */
  fprintf(stderr, "Done loading Aspects");

  //	_handles.push_back(handle);	
}


