#include "oak.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

oak_queue *queue_create(char *name, oak_list *actionlist, oak_fire *fire) {
  /* create and return a queue with the given action and fire.  it will have
     an emtpy pending message list */
  oak_queue *out;

  out=malloc(sizeof(oak_queue));
  out->name=strdup(name);
  out->fire=fire;
  out->actionlist=actionlist;
  out->msgs=NULL;
  out->msgcount=NULL;
  out->nummsgs=0;
  out->host=NULL;
  out->locktime=0;
  out->header=NULL;
  out->prescan=0;
  if (!strcmp(name, "trash")) {
    out->trashqueue=1;
    out->fire=fire_create("*2s");
  } else {
    out->trashqueue=0;
  }
  return(out);
}

char *queue_get_name(oak_queue *q) {
  /* return the name of the queue */
  return(q->name);
}

int queue_is_prescan(oak_queue *q) {
  return(q->prescan);
}

void queue_set_prescan(oak_queue *q) {
  q->prescan=1;
}

int queue_get_nummsgs(oak_queue *q) {
  /* return the number of pending messages */
  return(q->nummsgs);
}

char *queue_get_msg_n(oak_queue *q, int n) {
  /* return the nth pendning message */
  return q->msgs[n];
}

char *queue_get_host_n(oak_queue *q, int n) {
  /* return the host associcated with the nth pending message */
  return q->host[n];
}

int queue_get_msgcount_n(oak_queue *q, int n) {
  return q->msgcount[n];
}

void queue_set_header(oak_queue *q, char *header) {
  q->header=strdup(header);
}

char *queue_get_header(oak_queue *q) {
  return(q->header);
}

int queue_is_locking(oak_queue *q) {
  if (q->locktime == 0) {
    return(0);
  }
  return(1);
}

void queue_set_locktime_fromstring(oak_queue *q, char *in) {
  int foo;
  
  foo=atoi(in);
  if (!strcasecmp(in+strlen(in)-1, "h") ||
      !strcasecmp(in+strlen(in)-2, "hr")) {
    foo=foo*3600;
  } else if (!strcasecmp(in+strlen(in)-1, "m") ||
	     !strcasecmp(in+strlen(in)-3, "min")) {
    foo=foo*60;
  }
  q->locktime=foo;
}

int queue_get_locktime(oak_queue *q) {
  return(q->locktime);
}

void queue_add_msg(oak_queue *q, char *msg, char *host) {
  /* add msg to the list of pending messages.  If
     an identical message is already there just up the count
     remember to extract the host and do the right thing with it */
  int n, i, found;

  if (q->trashqueue) {
    if (DEBUG) printf("DEBUG: trashqueue tossing message\n");
    return;
  }
  
  n=queue_get_nummsgs(q);

  if (DEBUG) printf("DEBUG: trying to add line %s\n", msg);
  
  found=0;
  for (i=0; i<n; i++) {
    if (!strcmp(q->msgs[i], msg) && !strcasecmp(q->host[i], host)) {
      if (DEBUG) printf("DEBUG: Found duplicate message for queue %s\n", q->name);
      found=1;
      q->msgcount[i]++;
      break;
    }
  }

  if (!found) {
    if (DEBUG) printf("DEBUG: Found new message for queue %s\n", q->name);
    /* this needs to be optimized */
    q->msgs=realloc(q->msgs, LINE*(q->nummsgs+1) + 20);
    q->host=realloc(q->host, 256*(q->nummsgs+1) + 20);
    q->msgcount=realloc(q->msgcount, sizeof(int)*(q->nummsgs+1) + 20);
    /*    
    q->msgs=realloc(q->msgs, sizeof(q->msgs)+strlen(msg)+20);
    q->host=realloc(q->host, sizeof(q->host)+strlen(host)+20);
    q->msgcount=realloc(q->msgcount, sizeof(q->msgcount)+sizeof(int)+20);
    */
    q->msgs[n]=strdup(msg);
    q->host[n]=strdup(host);
    q->msgcount[n]=1;
    q->nummsgs++;
  }
}

void queue_delete_msgs(oak_queue *q) {
  /* delete all messages associated with q */
  int i;

  if (q->trashqueue) {
    return;
  }
      
  for (i=0; i<q->nummsgs; i++) {
    if (q->msgs[i]) free(q->msgs[i]);
    if (q->host[i]) free(q->host[i]);
    /* if (q->msgcount[i]) free(q->msgcount[i]); */  /* look at this */
  }
  if (q->msgs) {
    free(q->msgs);
    q->msgs=NULL;
  }
  if (q->host) {
    free(q->host);
    q->host=NULL;
  }
  if (q->msgcount) {
    free(q->msgcount);
    q->msgcount=NULL;
  }
  q->nummsgs=0;
}

oak_fire *queue_get_fire(oak_queue *q) {
  /* return the fire associcated with the queue */
  return(q->fire);
}

oak_list *queue_get_actionlist(oak_queue *q) {
  /* return the action associcated with the queue */
  return(q->actionlist);
}


void queue_set_fire(oak_queue *q, oak_fire *fire) {
  /* the the fire associated with the queue */
  if (q->fire) free(q->fire);
  q->fire=fire;
}

void queue_set_actionlist(oak_queue *q, oak_list *actionlist) {
  /* set the action associcated with the queue */
  if (q->actionlist) free(q->actionlist); /* not good enough */
  q->actionlist=actionlist;
}

char *queue_to_string(oak_queue *q) {
  int i, j, num, in, toomany, size;
  char host[50][512], bucket[50][100*50];
  char *out;

  num=0;
  toomany=0;
  /* sort by host */
  for (i=0; i<q->nummsgs; i++) {
    in=0;
    for (j=0; j<num; j++) {
      if (!strcasecmp(q->host[i], host[j])) {
	in=1;
	break;
      }
    }
    if (in == 0) {
      /* new bucket */
      if (num < 48) {
	char *foo;
	strcpy(host[num], q->host[i]);
	foo=strdup(q->msgs[i]);
	if ((strlen(foo)+1) > 100) { /* limit the line length */
	  foo[99]='\0';
	}
	sprintf(bucket[num], "   %i: %s\n", q->msgcount[i], foo);
	free(foo);
	num++;
      } else {
	toomany=1;
      }
    } else {
      /* append to existing bucket (j) */
      char *foo;
      foo=strdup(q->msgs[i]);
      if ((strlen(foo)+1) > 100) { /* limit the line length */
	foo[99]='\0';
      }
      sprintf(bucket[j], "%s   %i: %s\n", bucket[j], q->msgcount[i], foo);
    }
  }

  size=10;
  out=malloc(size);
  strcpy(out, "");
  for (i=0; i<num; i++) {
    size+=strlen(host[i])+strlen(bucket[i])+10;
    out=realloc(out, size);
    if (!out) {
      /* error */
    }
    strcat(out, host[i]);
    strcat(out, ":\n");
    strcat(out, bucket[i]);
    strcat(out, "\n");
  }

  return(out);
}

char *queue_to_string_truncate(oak_queue *q, int lines, int linelen, int numhosts, int hostents) {
  int i, j, numents, found, toomany, size;
  char host[numhosts][512], bucket[numhosts][linelen*hostents];
  int numlines[numhosts];
  char *out, *out2, *foo;

  /* host[n] is the hostname for an entry
   * bucket[n] is the string for that entry
   * numlines[n] is the number of lines currently queued for that entry
   */

  numents=0;
  toomany=0;
  /* sort by host */
  for (i=0; i<q->nummsgs; i++) {
    found=0;
    for (j=0; j<numents; j++) {
      if (!strcasecmp(q->host[i], host[j])) {
	found=1;
	break;
      }
    }

    if (found == 0) {
      /* too many buckets? */
      if (numents >= numhosts-2) {
	toomany=1;
	break; /* continue? */
      }

      /* create a new one */
      strcpy(host[numents], q->host[i]);
      strcpy(bucket[numents], "");
      numlines[numents]=0;
      numents++;
      
     /* now decr the counter and try again for this msg */
      i--;
      continue;
    }

    /* append to existing bucket (j) */
    if (numlines[j]<hostents) {
      foo=strdup(q->msgs[i]);
      if ((strlen(foo)+1) > linelen-3) { /* limit the line length */
	foo[linelen-4]='\0';
      }
      if (!q->locktime) {
	sprintf(bucket[j], "%s   %i: %s\n", bucket[j], q->msgcount[i], foo);
      } else {
	sprintf(bucket[j], "%s   %s\n", bucket[j], foo);
      }
      numlines[j]++;
      free(foo);
    } else if (numlines[j] == hostents) {
      strcat(bucket[j], "   ** Too many messages found for host, truncating **\n");
      numlines[j]++;
    }
  }

  size=10;
  out=malloc(size);
  strcpy(out, "");

  if (q->header) {
    size+=strlen(q->header)+20;
    out=realloc(out, size);
    strcat(out, q->header);
    strcat(out, "\n\n");
  }
  
  for (i=0; i<numents; i++) {
    size+=strlen(host[i])+strlen(bucket[i])+10;
    out=realloc(out, size);
    if (!out) {
      /* error */
    }
    strcat(out, host[i]);
    strcat(out, ":\n");
    strcat(out, bucket[i]);
    strcat(out, "\n");
  }

  out2=malloc(size);
  strcpy(out2, out);
  
  if (trim_string_by_lines(out, out2, lines)) {
    size+=100;
    out2=realloc(out2, size);
    sprintf(out2, "%s\n ** Message longer than %i lines, message has been truncated ** \n", out2, lines);
  }
  
  if (toomany) {
    size+=100;
    out2=realloc(out2, size);
    strcat(out2, "\n ** Too many hosts reporting, message has been truncated **\n");
  }

  free(out);
  return(out2);
}
