#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "config.h"
#include "pttstruct.h"
#include "util.h"

extern struct utmpfile_t *utmpshm;

int utmpfix(int argc, char **argv)
{
    int     i;
    char    buf[1024], *clean;
    struct  stat    st;
    if( utmpshm->busystate ){
	puts("utmpshm is busy");
	return 0;
    }
    utmpshm->busystate = 1;
    for( i = 0 ; i < USHM_SIZE ; ++i )
	if( utmpshm->uinfo[i].pid ){
	    clean = NULL;
	    if( !isalpha(utmpshm->uinfo[i].userid[0]) )
		clean = "userid error";
	    else{
		sprintf(buf, "/proc/%d", utmpshm->uinfo[i].pid);
		if( stat(buf, &st) < 0 ) 
		    clean = "process not exist";
	    }
	    
	    if( clean ){
		printf("clean %06d(%s), userid: %s\n",
		       i, clean, utmpshm->uinfo[i].userid);
		memset(&utmpshm->uinfo[i], 0, sizeof(userinfo_t));
	    }
	}
    utmpshm->busystate = 0;
    return 0;
}

char *CTIME(char *buf, time_t t)
{
    strcpy(buf, ctime(&t));
    buf[strlen(buf) - 1] = 0;
    return buf;
}

int utmpstate(int argc, char **argv)
{
    time_t  now;
    char    upbuf[64], nowbuf[64];
    now = time(NULL);
    CTIME(upbuf,  utmpshm->uptime);
    CTIME(nowbuf, time(NULL));
    printf("now:        %s\n", nowbuf);
    printf("currsorted: %d\n", utmpshm->currsorted);
    printf("uptime:     %s\n", upbuf);
    printf("number:     %d\n", utmpshm->number);
    printf("busystate:  %d\n", utmpshm->busystate);
    return 0;
}

int utmpreset(int argc, char **argv)
{
    utmpshm->busystate=0;
    utmpstate(0, NULL);
    return 0;
}

/* ulistsort */
static int cmputmpuserid(const void *i, const void *j){
    return strcasecmp((*((userinfo_t**)i))->userid,
		      (*((userinfo_t**)j))->userid);
}

static int cmputmpmode(const void *i, const void *j){
    return (*((userinfo_t**)i))->mode-
	(*((userinfo_t**)j))->mode;
} 

static int cmputmpidle(const void *i, const void *j){
    return (*((userinfo_t**)i))->lastact-
	(*((userinfo_t**)j))->lastact;
} 

static int cmputmpfrom(const void *i, const void *j){
  return strcasecmp((*((userinfo_t**)i))->from,
		    (*((userinfo_t**)j))->from);
} 

static int cmputmpfive(const void *i, const void *j){
    int type;
    if((type=(*((userinfo_t**)j))->five_win - (*((userinfo_t**)i))->five_win))
	return type;
    if((type=(*((userinfo_t**)i))->five_lose-(*((userinfo_t**)j))->five_lose))
	return type;
    return (*((userinfo_t**)i))->five_tie-(*((userinfo_t**)j))->five_tie;
} 

static int cmputmpsex(const void *i, const void *j){
    static int ladyfirst[]={1,0,1,0,1,0,3,3};
    return ladyfirst[(*((userinfo_t**)i))->sex]-
	ladyfirst[(*((userinfo_t**)j))->sex];
}
static int cmputmppid(const void *i, const void *j){
    return (*((userinfo_t**)i))->pid-(*((userinfo_t**)j))->pid;
}
static int cmputmpuid(const void *i, const void *j){
    return (*((userinfo_t**)i))->uid-(*((userinfo_t**)j))->uid;
}

int utmpsort(int argc, char **argv)
{
    time_t now=time(NULL);
    int count, i, ns;
    userinfo_t *uentp;
    
    if(now-utmpshm->uptime<60 && (now==utmpshm->uptime || utmpshm->busystate)){
	puts("lazy sort");
	//return; /* lazy sort */
    }
    utmpshm->busystate=1;
    utmpshm->uptime = now;
    ns=(utmpshm->currsorted?0:1);

    for(uentp = &utmpshm->uinfo[0], count=0, i=0;
	i< USHM_SIZE; i++,uentp = &utmpshm->uinfo[i])
	if(uentp->pid){
	    utmpshm->sorted[ns][0][count++]= uentp;
        }
    utmpshm->number = count;
    qsort(utmpshm->sorted[ns][0],count,sizeof(userinfo_t*),cmputmpuserid);
    memcpy(utmpshm->sorted[ns][1],utmpshm->sorted[ns][0],
						 sizeof(userinfo_t *)*count);
    memcpy(utmpshm->sorted[ns][2],utmpshm->sorted[ns][0],
						 sizeof(userinfo_t *)*count);
    memcpy(utmpshm->sorted[ns][3],utmpshm->sorted[ns][0],
						 sizeof(userinfo_t *)*count);
    memcpy(utmpshm->sorted[ns][4],utmpshm->sorted[ns][0],
						 sizeof(userinfo_t *)*count);
    memcpy(utmpshm->sorted[ns][5],utmpshm->sorted[ns][0],
						 sizeof(userinfo_t *)*count);
    memcpy(utmpshm->sorted[ns][6],utmpshm->sorted[ns][0],
						 sizeof(userinfo_t *)*count);
    memcpy(utmpshm->sorted[ns][7],utmpshm->sorted[ns][0],
						 sizeof(userinfo_t *)*count);
    qsort(utmpshm->sorted[ns][1], count, sizeof(userinfo_t *), cmputmpmode );
    qsort(utmpshm->sorted[ns][2], count, sizeof(userinfo_t *), cmputmpidle );
    qsort(utmpshm->sorted[ns][3], count, sizeof(userinfo_t *), cmputmpfrom );
    qsort(utmpshm->sorted[ns][4], count, sizeof(userinfo_t *), cmputmpfive );
    //qsort(utmpshm->sorted[ns][5], count, sizeof(userinfo_t *), cmputmpsex );
    qsort(utmpshm->sorted[ns][6], count, sizeof(userinfo_t *), cmputmpuid );
    qsort(utmpshm->sorted[ns][7], count, sizeof(userinfo_t *), cmputmppid );
    utmpshm->currsorted=ns;
    utmpshm->busystate=0;

    puts("new utmpstate");
    utmpstate(0, NULL);
    return 0;
}
/* end of ulistsort */

int utmpwatch(int argc, char **argv)
{
    int     i;
    while( 1 ){
	for( i = 0 ; i < 4 ; ++i ){
	    usleep(300);
	    if( !utmpshm->busystate )
		break;
	    puts("busying...");
	}
	if( i == 4 ){
	    puts("reset!");
	    utmpshm->busystate = 0;
	}
    }
    return 0;
}

struct {
    int     (*func)(int, char **);
    char    *cmd, *descript;
} cmd[] =
    { {utmpfix,   "utmpfix",   "clear dead userlist entry"},
      {utmpstate, "utmpstate", "list utmpstate"},
      {utmpreset, "utmpreset", "utmpshm->busystate=0"},
      {utmpsort,  "utmpsort",  "sort ulist"},
      {utmpwatch, "utmpwatch", "to see if busystate is always 1 then fix it"},
      {NULL, NULL, NULL} };

int main(int argc, char **argv)
{
    int     i = 0;
	
    if( argc >= 2 ){
	resolve_utmp();
	resolve_boards();
	//resolve_garbage();
	resolve_fcache();
	for( i = 0 ; cmd[i].func != NULL ; ++i )
	    if( strcmp(cmd[i].cmd, argv[1]) == 0 ){
		cmd[i].func(argc - 2, &argv[2]);
		break;
	    }
    }
    if( argc == 1 || cmd[i].func == NULL ){
	/* usage */
	printf("usage: bbsctl [command] [options]\n");
	printf("commands:\n");
	for( i = 0 ; cmd[i].func != NULL ; ++i )
	    printf("\t%-15s%s\n", cmd[i].cmd, cmd[i].descript);
    }
    return 0;
}