#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <glob.h>
#include <sys/stat.h>
#include <lcm/lcm-cpp.hpp>
#include "lcmMessages/Event.hpp"

/**
This application runs alongside the LRAUV application, monitors 
<LogsDir>/latest/syslog for lines containing a specified tag, and publishes
those lines to LCM. Note that the latest/ directory is a symbolic link, and
the LRAUV app can sometimes point the link to a new directory which 
will contain a new syslog.
*/

#define dprintf if (debug) fprintf

/** Get inode of "latest/" subdirectory (which is a symbolic link) */
int getLatestInode(char *path, ino_t *inode);


int main(int argc, char **argv) {

  if (argc != 4) {
    fprintf(stderr, "usage: %s logsDir tag channel\n", argv[0]);
    fprintf(stderr, 
	    "Monitor logsDir/latest/syslog, publish lines that contain tag to LCM channel\n");
    return 1;
  }

  bool debug = true;

  char *logBaseDir = argv[1];
  char *lineTag = argv[2];
  char *channelName = argv[3];

  // Open LCM connection
  lcm::LCM lcm;
  if (!lcm.good()) {
    fprintf(stderr, "Error connecting to LCM\n");
    return 1;
  }

  char latestDirPath[256];
  sprintf(latestDirPath, "%s/latest", logBaseDir);

  // Get syslog path
  char syslogName[256];
  sprintf(syslogName, "%s/syslog", latestDirPath);

  // Allocate line 
  size_t nBytes = 256;
  char *line = (char *)malloc(nBytes);
  lcmMessages::Event event;

  ino_t latestInode = 0;    
  FILE *input = NULL;    
  useconds_t sleepUsec = 100000;
  if (debug) {
    sleepUsec = 1000000;
  }

  // Read each full line
  while (true) {
    int nRead = 0;
    if (input != NULL && (nRead = getline(&line, &nBytes, input)) != -1) {
      fprintf(stderr, "line: %s", line);
      // If line contains designated tag, publish full line to LCM
      if (strstr(line, lineTag) != NULL) {
	if (line[strlen(line)-1] == '\n') {
	  // Strip off ending newline
	  line[strlen(line)-1] = '\0';
	}
	fprintf(stderr, "publish \"%s\"\n", line);
	std::string str(line);
	event.epochSec = time(NULL);
	event.eventMsg = str;
	lcm.publish(channelName, &event);
      }
    }
    else {
      // sylog not opened yet or no new data in file
      if (input != NULL && nRead == -1) {
	// No new data in file
	dprintf(stderr, "no new data in %s; sleep a bit\n", syslogName);
	usleep(sleepUsec);
      }

      // Check for new "latest/" subdir
      ino_t inode;
      if (getLatestInode(latestDirPath, &inode) == 0) {

	// "latest/ exists

	if (inode != latestInode) {

	  // New latest/ subdirectory
	  latestInode = inode;

	  // Close previous sylog file input if any
	  if (input != NULL) {
	    fclose(input);
	    input = NULL;
	  }	
	}

	// Open latest syslog, if not yet open
	if (input == NULL) {

	  dprintf(stderr, "Opening latest file, \"%s\"\n", syslogName);
	  input = fopen(syslogName, "r");
	  if (input == NULL) {
	    perror(syslogName);
	    dprintf(stderr, "sleep a bit\n");
	    // Sleep a bit
	    usleep(sleepUsec);
	  }
	  else {
	    dprintf(stderr, "opened file %s\n", syslogName);
	    // Disable buffering
	    setbuf(input, NULL);
	  }
	}
      }
      else {
	dprintf(stderr, 
		"%s not found yet; sleep a bit\n", latestDirPath);
	// Sleep a bit
	usleep(sleepUsec);
      }
    }
  }
  fprintf(stderr, "Done reading %s\n", syslogName);
  return 0;
}

/** Get inode of latest/ subdirectory (which is a symbolic link) */
int getLatestInode(char *latestDirPath, ino_t *inode) {
  struct stat sbuf;
  if (stat(latestDirPath, &sbuf) != 0) {
    // Probably doesn't exist
    return -1;
  }
  *inode = sbuf.st_ino;
  return 0;
}

