#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <zephyr/zephyr.h>
#include "xznol.h"
#include "mymalloc.h"
#include "util.h"
#include "file.h"

XtResource tabres[] = {
   {"file", "File", XtRString, sizeof(String),
       XtOffset(table *, file), XtRString, "~/.anyone"},
   {"recheckDelay", "RecheckDelay", XtRInt, sizeof(int),
       XtOffset(table *, recheck), XtRImmediate, (XtPointer) 0},
};

#define tabres_cnt sizeof(tabres)/sizeof(XtResource)

char *table_file(table *t)
{
   return(t->file);
}

int table_recheck(table *t)
{
   return(t->recheck);
}

void locate_table(table *t)
{
   int i;

   if (!t) return;

   for (i=0; i<t->nusers; i++) {
      process_xinput();
      locate_user(t->users[i].u);
   }
}

void sub_table(table *t)
{
   int i;

   if (!t) return;

   for (i=0; i<t->nusers; i++) {
      process_xinput();
      sub_user(t->users[i].u);
   }
}

void table_init_line(XawTableLine *l)
{
   l->nelem = LINE_TABLEBASE;
   l->element = (XawTableElement *) mymalloc(LINE_TABLEBASE*
					     sizeof(XawTableElement));
}

static XContext tables = 0;

/* This work's 'cause Widget and XID are the same size.  Otherwise, I
need another hack, since I don't have the Window ID at this point.  I
suppose if I need to, I can replace widget_to_table with a list walk,
and keep a list of tables. */

table *widget_to_table(Widget w)
{
   caddr_t data;

   if (XFindContext(XtDisplay(w), (XID) w, tables, &data))
      return(NULL);

   return((table *) data);
}

Widget table_constructor(Widget parent, char *name)
{
   table *t;
   int i;

   t = (table *) mymalloc(sizeof(table));

   t->w = XtCreateManagedWidget(name, tableWidgetClass, parent, NULL, 0);

   if (tables == 0)
      tables = XUniqueContext();

   if (XSaveContext(XtDisplay(t->w), (XID) t->w, tables, (caddr_t) t))
      abort();

   t->nusers = 0;
   t->ausers = 4;
   t->users = (peruser *) mymalloc(t->ausers*sizeof(peruser));

   t->nlines = 0;
   t->alines = 4;
   t->lines = (XawTableLine *) mymalloc(t->alines*sizeof(XawTableLine));
   for (i=0; i<t->alines; i++)
      table_init_line(t->lines+i);

   XtGetSubresources(t->w, (XtPointer) t, "znol", "Znol",
		     tabres, tabres_cnt, NULL, 0);

   t->file = expand_file_name(t->file);

   load_file(t);

   return(t->w);
}

void add_user_to_table(table *t, user *u, char *info)
{
   t->nusers++;
   if (t->nusers >= t->ausers) {
      t->ausers = t->ausers?2*t->ausers:4;
      t->users = (peruser *) myrealloc(t->users, t->ausers*sizeof(peruser));
   }
   t->users[t->nusers-1].u = u;
   t->users[t->nusers-1].info = info;
}

/*ARGSUSED*/
void delete_user_from_table(table *t, user *u)
{
   /* noop for now */
}

char *get_user_info_from_table(table *t, user *u)
{
   int i;

   for (i=0; i<t->nusers; i++)
      if (t->users[i].u == u)
	 return(t->users[i].info);

   return(NULL);
}

void redisplay_table(table *t)
{
   XawTableChange(t->w, t->lines, t->nlines, 0, True);
}

int login_user_in_table(table *t, char **l, ZLocations_t *zloc)
{
   int i;

   for (i=0; i<t->nlines; i++)
      if ((strcmp(t->lines[i].element[LINE_USER], l[LINE_USER]) == 0) &&
	  (strcasecmp(t->lines[i].element[LINE_HOST], zloc->host) == 0) &&
	  (strcmp(t->lines[i].element[LINE_TTY], zloc->tty) == 0))
	 return(0);

   t->nlines++;
   if (t->nlines >= t->alines) {
      t->alines = t->alines?2*t->alines:4;
      t->lines = (XawTableLine *) myrealloc(t->lines,
					    t->alines*sizeof(XawTableLine));
      for (i=t->nlines; i<t->alines; i++)
	 table_init_line(t->lines+i);
   }

   for (i=0; i<LINE_USERBASE; i++)
      t->lines[t->nlines-1].element[i] = l[i];
   t->lines[t->nlines-1].element[LINE_HOST] = strdup(zloc->host);
   t->lines[t->nlines-1].element[LINE_TIME] = strdup(zloc->time);
   t->lines[t->nlines-1].element[LINE_TTY] = strdup(zloc->tty);

   return(1);
}

int logout_user_in_table(table *t, char **l, ZLocations_t *zloc)
{
   int i, j;
   XawTableLine tl;
   int changed = 0;

   for (i=0; i<t->nlines; i++)
      if ((strcmp(t->lines[i].element[LINE_USER], l[LINE_USER]) == 0) &&
	  ((zloc == NULL) ||
	   ((strcasecmp(t->lines[i].element[LINE_HOST], zloc->host) == 0) &&
	    (strcmp(t->lines[i].element[LINE_TTY], zloc->tty) == 0)))) {

	 tl = t->lines[i];
	 t->lines[i] = t->lines[t->nlines-1];
	 t->lines[t->nlines-1] = tl;

	 t->nlines--;

	 for (j=LINE_USERBASE; j<LINE_TABLEBASE; j++)
	    myfree(t->lines[t->nlines].element[j]);

	 if (zloc) return(1);  /* There can be only one */
	 changed++;
      }

   return(changed);
}

int replace_user_in_table(table *t, char **l, ZLocations_t *zloc,
			  int nzloc)
{
   int i;
   int changed = 0;

   changed += logout_user_in_table(t, l, NULL);

   for (i=0; i<nzloc; i++)
      changed += login_user_in_table(t, l, zloc+i);

   return(changed);
}
