#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include "MachineInfoP.h"
#include <sys/types.h>
#include <netinet/in.h>

#ifdef PACKET_LE
#define NTOHL(x)	ntonl(x)
#else
#define NTOHL(x)	(x)
#endif

#define MIOffset(tag)	XtOffset(MachineInfoWidget, machine_info.tag)

#define MACHINE_INFO_WIDTH	200
#define TITLE_OFFSET		20
#define INTER_LINE_SKIP		5

#define MAXWHO  (1024/sizeof(struct whoent))

static XtResource resources[] = {
	{AiNtitleFont, XtCFont, XtRFontStruct, sizeof(XFontStruct*),
	 MIOffset(title_font), XtRString,
	 "-adobe-helvetica-medium-r-normal--18-180-75-75-p-98-iso8859-1",
	 },
	{AiNloadInfoFont, XtCFont, XtRFontStruct, sizeof(XFontStruct*),
	 MIOffset(load_info_font), XtRString,
	 "-adobe-helvetica-medium-r-normal--14-140-75-75-p-77-iso8859-1",
	 },
	{AiNuserInfoFont, XtCFont, XtRFontStruct, sizeof(XFontStruct*),
	 MIOffset(user_info_font), XtRString,
	 "-dec-terminal-bold-r-normal--14-140-75-75-c-80-iso8859-1",
	 },
	{AiNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
	 MIOffset(foreground), XtRString, "Black"},
	{AiNsiteInfo, AiCSiteInfo, AiRWhod, sizeof(struct whod*),
	 MIOffset(site_info), AiRWhod, NULL},
};

static void Initialize(), Redisplay(), Destroy();

MachineInfoClassRec machineInfoClassRec = {
{
/* core_class fields */	
    /* superclass	  	*/	(WidgetClass)&widgetClassRec,
    /* class_name	  	*/	"MachineInfo",
    /* widget_size	  	*/	sizeof(MachineInfoRec),
    /* class_initialize   	*/	NULL,
    /* class_part_initialize	*/	NULL,
    /* class_inited       	*/	FALSE,
    /* initialize	  	*/	Initialize,
    /* initialize_hook		*/	NULL,
    /* realize		  	*/	XtInheritRealize,
    /* actions		  	*/	NULL,
    /* num_actions	  	*/	0,
    /* resources	  	*/	resources,
    /* num_resources	  	*/	XtNumber(resources),
    /* xrm_class	  	*/	NULLQUARK,
    /* compress_motion	  	*/	TRUE,
    /* compress_exposure  	*/	TRUE,
    /* compress_enterleave	*/	TRUE,
    /* visible_interest	  	*/	FALSE,
    /* destroy		  	*/	Destroy,
    /* resize		  	*/	XtInheritResize,
    /* expose		  	*/	Redisplay,
    /* set_values	  	*/	NULL,
    /* set_values_hook		*/	NULL,
    /* set_values_almost	*/	XtInheritSetValuesAlmost,
    /* get_values_hook		*/	NULL,
    /* accept_focus	 	*/	NULL,
    /* version			*/	XtVersion,
    /* callback_private   	*/	NULL,
    /* tm_table		   	*/	NULL,
    /* query_geometry		*/	NULL,
  },
};

WidgetClass machineInfoWidgetClass = (WidgetClass)&machineInfoClassRec;

#define DOWN(w)	(time(0) - NTOHL((w)->wd_recvtime) >= MIN5)
#define	MIN5	(5*60)		/* 5 minutes in second */
#define	MIN15	(15*60)		/* 15 minutes in second */
#define HOUR1	(60*60)		/* 1 hour in second    */
#define HOUR3	(60*60*3)	/* 3 hour in second    */
#define	DAY5	(5*24*60*60)	/* 5 days in second    */

#define LINE_SKIP(f)	((f)->ascent+(f)->descent+INTER_LINE_SKIP)

#define gray_width 8
#define gray_height 8
static char gray_bits[] = {
   0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa};

static void
Initialize(request,new)
Widget request,new;
{
	XGCValues gv;
	MachineInfoWidget w = (MachineInfoWidget) new;
	MachineInfoPart *lp = &w->machine_info;
	
	gv.font = lp->title_font->fid;
	gv.foreground = lp->foreground;
	lp->title_GC = XtGetGC((Widget)w, GCFont | GCForeground, &gv);	

	gv.font = lp->load_info_font->fid;
	lp->load_info_GC = XtGetGC((Widget)w, GCFont | GCForeground, &gv);	

	gv.font = lp->user_info_font->fid;
	lp->user_info_GC = XtGetGC((Widget)w, GCFont | GCForeground, &gv);

	gv.stipple = XCreateBitmapFromData(XtDisplay(w),
					DefaultRootWindow(XtDisplay(w)),
					gray_bits,
					gray_width,
					gray_height);
	gv.fill_style = FillStippled;
	lp->user_info_gray_GC =
		XtGetGC((Widget)w,
			GCFont | GCForeground | GCStipple | GCFillStyle,
			&gv);

	w->core.width = MACHINE_INFO_WIDTH;
	if (lp->site_info) {
		int h;
		if (DOWN(lp->site_info))
			h = TITLE_OFFSET+
			    LINE_SKIP(lp->title_font)+
			    LINE_SKIP(lp->load_info_font);
		else
			h = TITLE_OFFSET+
			    LINE_SKIP(lp->title_font)+
			    LINE_SKIP(lp->load_info_font)*3+
			    LINE_SKIP(lp->user_info_font)*nusers(lp->site_info);
		w->core.height = h;
	}
	else {
		w->core.height = TITLE_OFFSET+
				 LINE_SKIP(w->machine_info.title_font)+
				 LINE_SKIP(w->machine_info.load_info_font)*3;
	}
}


int
nusers(wd)
struct whod *wd;
{
	struct outmp	*omp;
	int j;
	for (j = 0; j < MAXWHO; j++) {
		omp = &(wd->wd_we[j].we_utmp);
		if (omp->out_line[0] == '\0')
			break;
	}
	return j;
}

static void
drawTextOnCenter(w,offset,gc,fi,p,l)
Widget w;
int offset;
GC gc;
XFontStruct *fi;
char *p;
int l;
{
	int wid;
	wid = XTextWidth(fi,p,l);
	XDrawString(XtDisplay(w),XtWindow(w),gc,
		    (w->core.width-wid)/2, offset, p,l);
}

#define ONE_HOUR (60*60)	/* 1 hour in sec */

static void
Redisplay(new, eve, reg)
Widget new;
XEvent *eve;
Region reg;
{
	MachineInfoWidget w = (MachineInfoWidget)new;
	MachineInfoPart *lp = &(w->machine_info);
	int i,yo = TITLE_OFFSET;
	struct outmp	*omp;
	static
	char username[9],linename[9],msgbuf[30];
	unsigned int	alivetime;
	int		day,hour,min;
	int		num;
	Boolean		down = False;
	GC		userColor;

	drawTextOnCenter(w,yo,lp->title_GC, lp->title_font,
			 lp->site_info->wd_hostname,
			 strlen(lp->site_info->wd_hostname));
	yo += LINE_SKIP(lp->title_font);

	if (DOWN(lp->site_info)) {
		alivetime = time(0) - NTOHL(lp->site_info->wd_recvtime);
		day  = alivetime/(24*60*60);
		hour = alivetime/(60*60)-day*24;
		min  = alivetime/60-hour*60-day*(24*60);
		sprintf(msgbuf,"Sleep time %4d+%2d:%2d",day,hour,min);
		drawTextOnCenter(w,yo,
				 lp->load_info_GC,
				 lp->load_info_font,
				 msgbuf,strlen(msgbuf));
	}
	else {
		sprintf(msgbuf,"CPU load %4.2f",(double)NTOHL(lp->site_info->wd_loadav[0])/100);
		drawTextOnCenter(w,yo,
				 lp->load_info_GC,
				 lp->load_info_font,
				 msgbuf,strlen(msgbuf));
		yo += LINE_SKIP(lp->load_info_font);

		alivetime = NTOHL(lp->site_info->wd_sendtime) - NTOHL(lp->site_info->wd_boottime);
		day  = alivetime/(24*60*60);
		hour = alivetime/(60*60)-day*24;
		min  = alivetime/60-hour*60-day*(24*60);
		sprintf(msgbuf,"Alive time %4d+%2d:%2d",day,hour,min);
		drawTextOnCenter(w,yo,
				 lp->load_info_GC,
				 lp->load_info_font,
				 msgbuf,strlen(msgbuf));
		yo += LINE_SKIP(lp->load_info_font);

		switch (num = nusers(lp->site_info)) {
		case 0:
			strcpy(msgbuf,"No User");
			break;
		case 1:
			strcpy(msgbuf,"1 User");
			break;
		default:
			sprintf(msgbuf,"%d Users",num);
		}
		drawTextOnCenter(w,yo,
				 lp->load_info_GC,
				 lp->load_info_font,
				 msgbuf,strlen(msgbuf));
		yo += LINE_SKIP(lp->load_info_font);
		
		for (i = 0; i < num; i++) {
			omp = &(lp->site_info->wd_we[i].we_utmp);
			strncpy(username,omp->out_name,8);
			username[8] = '\0';
			strncpy(linename,omp->out_line,8);
			linename[8] = '\0';
			sprintf(msgbuf,"%8s on %s",username,linename);
			if (NTOHL(lp->site_info->wd_we[i].we_idle) > ONE_HOUR)
				userColor = lp->user_info_gray_GC;
			else
				userColor = lp->user_info_GC;
			XDrawString(XtDisplay(w),XtWindow(w),
				    userColor,
				    10,yo,msgbuf,strlen(msgbuf));
			yo += LINE_SKIP(lp->user_info_font);
		}
	}
	XFlush(XtDisplay(w));
}

static void
Destroy(new)
Widget new;
{
	MachineInfoWidget lw = (MachineInfoWidget)new;
	MachineInfoPart *w = &(lw->machine_info);

	XtReleaseGC(new,w->title_GC);
	XtReleaseGC(new,w->load_info_GC);
	XtReleaseGC(new,w->user_info_GC);
	XtReleaseGC(new,w->user_info_gray_GC);
}

/**** functions ****/
void
AiSetSiteData(w,wd)
MachineInfoWidget w;
struct whod *wd;
{
	int h;

	if (w->machine_info.site_info == NULL)
		w->machine_info.site_info = (struct whod*)XtMalloc(sizeof(struct whod));
	*w->machine_info.site_info = *wd;
	if (DOWN(wd))
		h = TITLE_OFFSET+
			LINE_SKIP(w->machine_info.title_font)+
			LINE_SKIP(w->machine_info.load_info_font);
	else
		h = TITLE_OFFSET+
			LINE_SKIP(w->machine_info.title_font)+
			LINE_SKIP(w->machine_info.load_info_font)*3+
			LINE_SKIP(w->machine_info.user_info_font)*nusers(wd);
	XtResizeWidget(w, w->core.width, h, w->core.border_width);
}


syntax highlighted by Code2HTML, v. 0.9.1