

/*  Copyright (c) 1993 by Kenneth Duda <kkkken@athena.mit.edu>.  
 *  All rights reserved.
 *
 *  This program is distributed in the hope that it will be useful.
 *  Use and copying of this software and preparation of derivative works
 *  based upon this software are permitted, so long as the following
 *  conditions are met:
 *       o credit to the author is acknowledged 
 *       o no fees or compensation are charged for use, copies, or
 *         access to this software
 *       o this copyright notice is included intact.
 *  This software is made available AS IS, and no warranty is made about 
 *  the software or its performance. 
 * 
 *  Bug descriptions, use reports, comments or suggestions are welcome.
 *  Send them to <kkkken@athena.mit.edu>.
 */

#include <ctype.h>

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Viewport.h>
#include <X11/Xaw/List.h>
#include <X11/Xaw/Label.h>

#include "AsciiTty.h"

#include "games.h"
#include "users.h"
#include "kgo.h"
#include "output.h"

#define MAXUSERS 200
#define MAXENTRY 40
#define POPUP_WIDTH 430

typedef struct user {
    int state;				/* close, open, looking */
    char name[MAXUSERNAME];
    char rank[MAXRANK];
    char idle[MAXIDLE];
    char entry[MAXENTRY];
    int playing;
    int observing;
} User;

typedef struct upopup {
    Widget popup;
    Widget form;
    Widget lookingList, openList, closedList;
    Widget text;
    User *users;
    char **lookingEntries, **openEntries, **closedEntries;
    int numUsers;
} Upopup;

User theUsers[MAXUSERS];
int theNumUsers;
Upopup *usersPopup = NULL;

void ClearUsers()
{
    theNumUsers = 0;
}

void AddUser (name, rank, idle, state, observing, playing)
     char *name;
     char *rank;
     char *idle;
     int state;
     int observing;
     int playing;
{
    User *u;
    char buf[30];
    
    if (theNumUsers == MAXUSERS) return;
    u = theUsers + theNumUsers++;
    strcpy (u->name, name);
    strcpy (u->rank, rank);
    strcpy (u->idle, idle);
    u->state = state;
    u->observing = observing;
    u->playing = playing;
    
    sprintf (u->entry, "%-10s [%s] %s",
	     name, rank, idle);
    if (state == UserPlaying) 
	sprintf (buf, " P%2d", playing);
    else if (observing)
	sprintf (buf, " O%2d", observing);
    else
	buf[0] = 0;
    strcat (u->entry, buf);
}

static void UserSelected (w, closure, call_data)
     Widget w;
     XtPointer closure;
     XtPointer call_data;
{
    int n;
    char buf[20 + 2*MAXUSERNAME];
    char uname[MAXUSERNAME];
    char *c, *b;
    Upopup *up = (Upopup *) closure;
    
    XawListReturnStruct *lrs = (XawListReturnStruct *) call_data;
    c = lrs->string;
    b = uname;
    while (!isspace(*c))
	*b++ = *c++;
    *b = 0;
    SetOutputSink (up->text);
    sprintf (buf, "stats %s\n", uname);
    QueueForServer(buf);
    sprintf (buf, "results %s\n", uname);
    QueueForServer(buf);
}

static void CloseSelected (w, closure, call_data)
     Widget w;
     XtPointer closure;
     XtPointer call_data;
{
    Upopup *up = (Upopup *) closure;
    
    XtPopdown (up->popup);
    CancelOutputSink (up->text);
}
    
static void RefreshSelected (w, closure, call_data)
     Widget w;
     XtPointer closure;
     XtPointer call_data;
{
    QueueForServer("who\n");
}
    
static void SetUserFlags (w, closure, call_data)
     Widget w;
     XtPointer closure;
     XtPointer call_data;
{
    int which = (int) closure;
    int open = (which == UserOpen) || (which == UserLooking);
    int looking = (which == UserLooking);
    char buf[200];
    sprintf (buf, "toggle open %d\n", open);
    QueueForServer(buf);
    sprintf (buf, "toggle looking %d\n", looking);
    QueueForServer(buf);
}

Upopup *MakeUsersPopup()
{
    Upopup *up = (Upopup *) malloc(sizeof(Upopup));
    Widget lookingLabel, label, viewport;

    up->popup = XtCreatePopupShell("usersShell", topLevelShellWidgetClass, toplevel, 0, 0);
    up->form = XtCreateManagedWidget("usersForm", formWidgetClass, up->popup, 0, 0);
    {
	static char *foo[1] = {""};
	static Arg args[] = { XtNwidth, POPUP_WIDTH,
				  XtNnumberStrings, 1,
				  XtNlist, (XtArgVal) foo,
				  XtNcolumnSpacing, 26,
			      };
	static Arg args2[] = { XtNlabel, 0,
				   XtNfromVert, 0,
				   XtNright, XawChainLeft,
				   XtNleft, XawChainLeft,
				   XtNtop, XawChainTop,
				   XtNbottom, XawChainTop,
			       };
	static Arg args3[] = { XtNheight, 150,
				   XtNfromVert, 0,
				   XtNallowVert, TRUE,
				   XtNright, XawChainRight,
				   XtNleft, XawChainLeft,
				   XtNtop, XawChainTop,
				   XtNbottom, XawChainTop,
			       };


	args2[0].value = (XtArgVal) "Looking for a game:";
	args2[1].value = (XtArgVal) 0;
	label = XtCreateManagedWidget ("lookingLabel", commandWidgetClass, up->form, args2, XtNumber(args2));
	XtAddCallback (label, XtNcallback, SetUserFlags, (XtPointer) UserLooking);
	lookingLabel = label;
	args3[1].value = (XtArgVal) label;
	viewport = XtCreateManagedWidget ("viewport", viewportWidgetClass, up->form, args3, XtNumber(args3));
	up->lookingList = XtCreateManagedWidget ("lookingList", listWidgetClass, viewport, args, XtNumber(args));
	XtAddCallback (up->lookingList, XtNcallback, UserSelected, up);

	args2[0].value = (XtArgVal) "Open to playing:";
	args2[1].value = (XtArgVal) viewport;
	label = XtCreateManagedWidget ("openLabel", commandWidgetClass, up->form, args2, XtNumber(args2));
	XtAddCallback (label, XtNcallback, SetUserFlags, (XtPointer) UserOpen);
	args3[1].value = (XtArgVal) label;
	viewport = XtCreateManagedWidget ("viewport", viewportWidgetClass, up->form, args3, XtNumber(args3));
	up->openList = XtCreateManagedWidget ("openList", listWidgetClass, viewport, args, XtNumber(args));
	XtAddCallback (up->openList, XtNcallback, UserSelected, up);

	args2[0].value = (XtArgVal) "Not open to playing:";
	args2[1].value = (XtArgVal) viewport;
	label = XtCreateManagedWidget ("closedLabel", commandWidgetClass, up->form, args2, XtNumber(args2));
	XtAddCallback (label, XtNcallback, SetUserFlags, (XtPointer) UserClosed);
	args3[1].value = (XtArgVal) label;
	viewport = XtCreateManagedWidget ("viewport", viewportWidgetClass, up->form, args3, XtNumber(args3));
	up->closedList = XtCreateManagedWidget ("closedList", listWidgetClass, viewport, args, XtNumber(args));
	XtAddCallback (up->closedList, XtNcallback, UserSelected, up);
    }
    {
	static Arg args[] = { XtNlabel, (XtArgVal) "Close",
				  XtNfromHoriz, 0,
				  XtNleft, XawChainLeft,
				  XtNright, XawChainLeft,
				  XtNtop, XawChainTop,
				  XtNbottom, XawChainTop,
		       };
	Widget but;
	
	args[1].value = (XtArgVal) lookingLabel;
	but = XtCreateManagedWidget ("close", commandWidgetClass, up->form, args, XtNumber(args));
	XtAddCallback (but, XtNcallback, CloseSelected, up);
	args[0].value = (XtArgVal) "Refresh List";
	args[1].value = (XtArgVal) but;
	but = XtCreateManagedWidget ("refresh", commandWidgetClass, up->form, args, XtNumber(args));
	XtAddCallback (but, XtNcallback, RefreshSelected, up);
    }
    {
	static Arg args[] = { XtNheight, 150,
				  XtNwidth, POPUP_WIDTH, 
				  XtNfromVert, 0,
				  XtNscrollVertical, XawtextScrollAlways,
				  XtNscrollHorizontal, XawtextScrollWhenNeeded,
				  XtNright, XawChainRight,
				  XtNleft, XawChainLeft,
				  XtNtop, XawChainTop,
				  XtNbottom, XawChainBottom,
			      };
	args[2].value = (XtArgVal) viewport;
	up->text = XtCreateManagedWidget ("text", asciiTtyWidgetClass, up->form, args, XtNumber(args));
    }
    XtRealizeWidget (up->popup);
    up->users = NULL;
    up->lookingEntries = NULL;
    up->openEntries = NULL;
    up->closedEntries = NULL;
    up->numUsers = 0;
    return up;
}


static void SetupList (list, entries, numEntries)
     Widget list;
     char **entries;
     int numEntries;
{
    static Arg args[] = { XtNnumberStrings, 0, 
			      XtNlist, 0,
		   };
    static char *empty = "";
    if (numEntries == 0) {
	args[0].value = 1;
	args[1].value = (XtArgVal) &empty;
    } else {
	args[0].value = numEntries;
	args[1].value = (XtArgVal) entries;
    }
    XtSetValues (list, args, XtNumber(args));
    XClearArea (XtDisplay(list), XtWindow(list), 0, 0, 0, 0, True); /* Why doesn't this lamo widget refresh itself?? */
}


void SetUsers (up, users, numUsers)
     Upopup *up;
     User *users;
     int numUsers;
{
    int n, nl, no, nc;
    int numLooking = 0, numOpen = 0, numClosed = 0;
    
    for (n = 0; n < numUsers; n++) {
	switch (users[n].state) {
	  case UserLooking:
	    numLooking++; break;
	  case UserOpen:
	    numOpen++; break;
	  default:
	    numClosed++; break;
	}
    }
    
    if (up->users) free (up->users);
    if (up->lookingEntries) free (up->lookingEntries);
    if (up->openEntries) free (up->openEntries);
    if (up->closedEntries) free (up->closedEntries);

    up->numUsers = numUsers;
    up->users = numUsers ? (User *) malloc(sizeof(User) * numUsers) : NULL;
    up->lookingEntries = numLooking ? (char **) malloc(sizeof(char *) * numLooking) : NULL;
    up->openEntries = numOpen ? (char **) malloc(sizeof(char *) * numOpen) : NULL;
    up->closedEntries = numClosed ? (char **) malloc(sizeof(char *) * numClosed) : NULL;
    if (numUsers) bcopy (users, up->users, sizeof(User) * numUsers);
    for (n = 0, nl = 0, no = 0, nc = 0; n < numUsers; n++) {
	switch (up->users[n].state) {
	  case UserLooking:
	    up->lookingEntries[nl++] = up->users[n].entry; break;
	  case UserOpen:
	    up->openEntries[no++] = up->users[n].entry; break;
	  default:
	    up->closedEntries[nc++] = up->users[n].entry; break;
	}
    }
    SetupList (up->lookingList, up->lookingEntries, numLooking);
    SetupList (up->openList, up->openEntries, numOpen);
    SetupList (up->closedList, up->closedEntries, numClosed);
}


void DoneGettingUsers()
{
    if (!usersPopup)
	usersPopup = MakeUsersPopup();
    SetUsers (usersPopup, theUsers, theNumUsers);
    XtPopup (usersPopup->popup, XtGrabNone);
}
    
