#include "logging.h"

// Write the line 'str' to the relevant log file such as
// '#channel.log' or 'nickname.log'.  'ournick' is our own
// nick and is used to determine which log file to write to
// if the type is LOG_PRIVMSG.
// 'basedir' is the directory in which the 'logs' directory
// will be created in which logs are to be written.
//
// If LOG_PRIVMSG then it expects a string in the format:
// :from!bar@baz PRIVMSG to :hello world
//
// If LOG_JOINPART then it expects a string in the format:
// :nick!bar@baz JOIN :#channel
// or
// :nick!bar@baz PART #channel
//
// If LOG_TOPIC then it expects a string in the format:
// :nick!bar@baz TOPIC #channel :bla bla bla
//
// With the ":foo!bar@baz "prefix being important for either
// type.
//
// Returns 1 on success or 0 on failure.
int logline(char *str, char *ournick, char *basedir, int type) {
  // Filename to write to, gets built as we go
  char filename[MAXCHAR];

  // Log line to ultimately write, gets built as we go
  char line[MAXCHAR];

  // Variables for LOG_JOINPART (can't define directly inside switch case)
  int pos;

  // Build array of each space-separated token
  char tokens[MAXTOKENS][MAXDATASIZE];
  char *token;

  // Split out the first three space-separated parts of the string, leaving the rest.
  // If LOG_PRIVMSG:
  // This gets us the prefix (containing the "from" nick), the PRIVMSG command (not needed),
  // and the "to" nick or channel.  Plus the rest of the string intact (which is the actual
  // message).
  // If LOG_JOINPART:
  // This gets us the prefix (containing the joined/parted nick), the JOIN/PART command (not needed),
  // and the channel name.
  // If LOG_TOPIC:
  // This gets us the prefix (containing the topic setting nick), the TOPIC command (not needed),
  // the channel whose topic was set, and the rest of the string intact (which is the new topic).
  for (int i = 0; i < 3; i++) {
    // Try to split
    if ((token = strsep(&str, " ")) == NULL) {
      printf("Error splitting string for logging, exiting!\n");
      exit(1);
    }
    // Copy into the token array (strlen + 1 to get the NULL terminator)
    strncpy(tokens[i], token, strlen(token) + 1);
    debugprint("logline(): extracted '%s'.\n", tokens[i]);
  }

  switch(type) {
    case LOG_PRIVMSG:
      // Extract the username from the prefix
      extractnickfromprefix(tokens[0]);

      // Remove the leading ":" from the real message
      stripprefix(str);

      // Build the log filename
      // If the message was sent to us, then log it in the sender's log file
      if (strncmp(tokens[2], ournick, strlen(tokens[0])) == 0) {
        snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, tokens[0]);
      } else {
        // Otherwise log it in the "to" log file
        snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, tokens[2]);
      }

      debugprint("logline(): Logging PRIVMSG from '%s' to '%s' message '%s' in filename '%s'.\n", tokens[0], tokens[2], str, filename);

      break;

    case LOG_JOINPART:
      // Find the start of the channel name

      // If it's a JOIN
      if (tokens[2][0] == ':') {
        pos = 1;
      } else if (tokens[2][0] == '#') {
        // Perhaps it's a PART
        pos = 0;
      } else {
        // If not found, return 0
        return 0;
      }

      snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, tokens[2] + pos);

      debugprint("logline(): Logging JOIN/PART to/from '%s' in filename '%s'.\n", tokens[2] + pos, filename);

      // Build a friendly message (e.g. ":nick!user@host JOIN #channel" -> "nick (user@host) has joined #channel")

      // Find the bang in the prefix
      char *ret;
      int posbang;
      if ((ret = strstr(tokens[0], "!")) != NULL) {
        // Position within str of "!"
        posbang = ret - tokens[0];
      } else {
        // No idea what happened, let's abandon ship
        return 0;
      }

      // Make it a null character
      tokens[0][posbang] = '\0';

      // Swap JOINed or PARTed for a friendly word
      if (strncmp(tokens[1], "JOIN", strlen("JOIN")) == 0) {
        snprintf(tokens[1], strlen("joined") + 1, "joined");
      } else if (strncmp(tokens[1], "PART", strlen("PART")) == 0) {
        snprintf(tokens[1], strlen("left") + 1, "left");
      }

      // Copy the nick, then user@host, then whether it was a join or part, then the channel name the string to send
      snprintf(line, MAXCHAR, "%s (%s) has %s %s", tokens[0] + 1, tokens[0] + posbang + 1, tokens[1], tokens[2] + pos);

      break;

    case LOG_TOPIC:
      // Extract the username from the prefix
      extractnickfromprefix(tokens[0]);

      // Remove the leading ":" from the topic
      stripprefix(str);

      snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, tokens[2]);

      debugprint("logline(): Logging TOPIC for '%s' in filename '%s'.\n", tokens[2], filename);

      // Build a friendly message (e.g. ":nick!user@host TOPIC #channel :blah blah" -> "nick has changed the topic to: blah blah")
      snprintf(line, MAXCHAR, "%s has changed the topic to: %s", tokens[0], str);

      break;

    default :
      printf("Unknown log type '%d', returning 0.\n", type);
      return 0;
  }

  // Make sure the log directory exists
  char logdir[PATH_MAX];
  snprintf(logdir, PATH_MAX, "%s/logs/", basedir);
  struct stat st = {0};
  if (stat(logdir, &st) == -1) {
    if (mkdir(logdir, 0700)) {
      printf("Error creating log directory '%s'.\n", logdir);
      exit(1);
    } else {
      debugprint("logline(): log directory '%s'.\n", logdir);
    }
  }

  FILE *fp;

  int bytes = 0;

  fp = fopen(filename, "a");

  if (fp == NULL) {
    printf("error: could not open log file '%s' for writing.\n", filename);
    exit(1);
  }

  // Get a current time string to prepend - TODO - Make this customisable.
  time_t rawtime;
  struct tm * timeinfo;
  time(&rawtime);
  timeinfo = localtime(&rawtime);
  // Strip the trailing newline
  char timestr[MAXCHAR];
  snprintf(timestr, MAXCHAR, "%s", asctime(timeinfo));
  timestr[strlen(timestr) - 1] = '\0';

  if (type == LOG_PRIVMSG) {
    // Prepend the time string and "from" nick
    if (!snprintf(line, MAXCHAR, "%s <%s> %s", timestr, tokens[0], str)) {
      fprintf(stderr, "Error while preparing log string to write!\n");
      exit(1);
    }
  } else if (type == LOG_JOINPART || type == LOG_TOPIC) {
    // Prepend the time string
    char line2[MAXCHAR];
    if (!snprintf(line2, MAXCHAR, "%s %s", timestr, line)) {
      fprintf(stderr, "Error while preparing log string to write!\n");
      exit(1);
    }
    // Copy back to line to write
    snprintf(line, MAXCHAR, "%s", line2);
  }

  // Ensure the line finishes with CRLF
  appendcrlf(line);

  debugprint("logline(): Complete log string to write: '%s', length '%ld'.\n", line, strlen(line));

  // Write complete line to file
  if ((bytes = fprintf(fp, "%s", line)) < 0) {
    printf("error: could not write to log file.\n");
    exit(1);
  }

  fclose(fp);
  return bytes;
}