/* quota.c -- quota management commands */

#include "autoconf.h"
#include "copyright.h"
#ifndef	lint
static char *RCSid = "$Id: quota.c,v 1.7 1995/03/21 00:01:05 ambar Exp $";
USE(RCSid);
#endif

#include "interface.h"
#include "file_c.h"
#include "match.h"
#include "command.h"
#include "attrs.h"


/* ---------------------------------------------------------------------------
 * load_quota: Load a quota into an array. Expects A_QUOTA or A_QUOTA.
 */

void load_quota(q_list, player, qtype)
     int q_list[];
     dbref player;
     int qtype;
{
    int i, aowner, aflags;
    char *quota_str, *p;

    quota_str = atr_get(player, qtype, &aowner, &aflags);

    /* This should never be null, but just in case. */
    if (!quota_str || !*quota_str) {
	for (i = 0; i < 5; i++)
	    q_list[i] = 0;
	if (quota_str)
	    free_lbuf(quota_str);
	return;
    }

    for (p = (char *) strtok(quota_str, " "), i = 0;
	 p && (i < 5);
	 p = (char *) strtok(NULL, " "), i++) {
	q_list[i] = atoi(p);
    }

    free_lbuf(quota_str);
}

/* ---------------------------------------------------------------------------
 * save_quota: turns a quota array into an attribute.
 */
void save_quota(q_list, player, qtype)
     int q_list[];
     dbref player;
     int qtype;
{
    char buf[32];
    sprintf(buf, "%d %d %d %d %d", q_list[0], q_list[1], q_list[2],
	    q_list[3], q_list[4]);
    atr_add_raw(player, qtype, buf);
}

/* ---------------------------------------------------------------------------
 * count_quota, mung_quota, show_quota, do_quota: Manage quotas.
 */

static int
count_quota(player, key)
    dbref player;
    int key;
{
    register int i, q = 0, what;

    if (key & QUOTA_ROOM) {
	what = TYPE_ROOM;
    } else if (key & QUOTA_EXIT) {
	what = TYPE_EXIT;
    } else if (key & QUOTA_THING) {
	what = TYPE_THING;
    } else if (key & QUOTA_PLAYER) {
	what = TYPE_PLAYER;
    } else {
	what = NOTYPE;		/* Add 'em all up */
    }

    DO_WHOLE_DB(i) {
	if (Owner(i) != player)
	    continue;
	if (Going(i) && (!isRoom(i)))
	    continue;
	if ((Typeof(i) == what) || what == NOTYPE) {
	    switch (Typeof(i)) {
	    case TYPE_EXIT:
		q += mudconf.exit_quota;
		break;
	    case TYPE_ROOM:
		q += mudconf.room_quota;
		break;
	    case TYPE_THING:
		q += mudconf.thing_quota;
		break;
	    case TYPE_PLAYER:
		q += mudconf.player_quota;
		break;
	    }
	}
    }
    return q;
}

static void
count_objquota(player, aq, rq, eq, tq, pq)
    dbref player;
    int *aq, *rq, *eq, *tq, *pq;
{
    register int a, r, e, t, p, i;

    a = r = e = t = p = 0;

    DO_WHOLE_DB(i) {
	if ((Owner(i) != player) || (Going(i) && !isRoom(i)))
	    continue;
	switch (Typeof(i)) {
	case TYPE_ROOM:
	    a += mudconf.room_quota;
	    r++;
	    break;
	case TYPE_EXIT:
	    a += mudconf.exit_quota;
	    e++;
	    break;
	case TYPE_THING:
	    a += mudconf.thing_quota;
	    t++;
	    break;
	case TYPE_PLAYER:
	    a += mudconf.player_quota;
	    p++;
	    break;
	}
    }
    *aq = a;
    *rq = r;
    *eq = e;
    *tq = t;
    *pq = p;
}


static void
adjust_quota(player, qtype, value, key)
    dbref player;
    int qtype, value, key;
{
    char *buff;
    dbref aowner;
    int aflags;
    register int aq, rq;
    int q_list[5], rq_list[5];

    load_quota(q_list, player, A_QUOTA);
    load_quota(rq_list, player, A_RQUOTA);

    aq = q_list[qtype];
    rq = rq_list[qtype];

    /* Adjust values */

    if (key & QUOTA_REM) {
	aq += (value - rq);
	rq = value;
    } else {
	rq += (value - aq);
	aq = value;
    }

    /* Set both abs and relative quota */

    q_list[qtype] = aq;
    rq_list[qtype] = rq;
    save_quota(q_list, player, A_QUOTA);
    save_quota(rq_list, player, A_RQUOTA);
}


static void
mung_quotas(player, key, value)
    dbref player;
    int key, value;
{
    dbref aowner;
    register int aq, rq;
    int xq, aflags, rooms, exits, things, players;
    int q_list[5], rq_list[5];
    char *buff;

    if (key & QUOTA_FIX) {

	/* Get value of stuff owned and good value, set other values
	 * from that. */

	count_objquota(player, &xq, &rooms, &exits, &things, &players);
	if (key & QUOTA_TOT) {
	    load_quota(rq_list, player, A_RQUOTA);
	    rq_list[QTYPE_ALL] += xq;
	    save_quota(rq_list, player, A_QUOTA);
	} else {
	    load_quota(q_list, player, A_QUOTA);
	    q_list[QTYPE_ALL] -= xq;
	    q_list[QTYPE_ROOM] -= rooms;
	    q_list[QTYPE_EXIT] -= exits;
	    q_list[QTYPE_THING] -= things;
	    q_list[QTYPE_PLAYER] -= players;
	    save_quota(q_list, player, A_RQUOTA);
	}
    } else if (key & QUOTA_ROOM) {
	adjust_quota(player, QTYPE_ROOM, value, key);
    } else if (key & QUOTA_EXIT) {
	adjust_quota(player, QTYPE_EXIT, value, key);
    } else if (key & QUOTA_THING) {
	adjust_quota(player, QTYPE_THING, value, key);
    } else if (key & QUOTA_PLAYER) {
	adjust_quota(player, QTYPE_PLAYER, value, key);
    } else {
	adjust_quota(player, QTYPE_ALL, value, key);
    }
}

static void
print_objquota(player, victim, tstr)
    dbref player, victim;
    const char *tstr;
{
    int q_list[5], rq_list[5], dq_list[5], i;

    load_quota(q_list, victim, A_QUOTA);
    load_quota(rq_list, victim, A_RQUOTA);

    for (i = 0; i < 5; i++)
	dq_list[i] = q_list[i] - rq_list[i];

    if (Wizard(victim))
	notify_quiet(player,
		     tprintf("%-16s: %4d - N/A  %4d - N/A  %4d - N/A  %4d - N/A  %4d - N/A",
			     Name(victim), dq_list[QTYPE_ALL],
			     dq_list[QTYPE_ROOM], dq_list[QTYPE_EXIT],
			     dq_list[QTYPE_THING], dq_list[QTYPE_PLAYER]));
    else
	notify_quiet(player, 
		     tprintf("%-16s: %4d - %3d  %4d - %3d  %4d - %3d  %4d - %3d  %4d - %3d",
			     Name(victim),
			     dq_list[QTYPE_ALL], q_list[QTYPE_ALL],
			     dq_list[QTYPE_ROOM], q_list[QTYPE_ROOM],
			     dq_list[QTYPE_EXIT], q_list[QTYPE_EXIT],
			     dq_list[QTYPE_THING], q_list[QTYPE_THING],
			     dq_list[QTYPE_PLAYER], q_list[QTYPE_PLAYER]));
}

static void
show_quota(player, victim)
    dbref player, victim;
{
    print_objquota(player, victim, "Quota");
}

static void
show_quota_header(player)
    dbref player;
{
    notify_quiet(player, "Name            : Quot - Lim  Room - Lim  Exit - Lim  Thin - Lim  Play - Lim");
}

void
do_quota(player, cause, key, arg1, arg2)
    dbref player, cause;
    int key;
    char *arg1, *arg2;
{
    dbref who;
    register int set = 0, value = 0, i;

    if (!(mudconf.quotas | Wizard(player))) {
	notify_quiet(player, "Quotas are not enabled.");
	return;
    }
    if ((key & QUOTA_TOT) && (key & QUOTA_REM)) {
	notify_quiet(player, "Illegal combination of switches.");
	return;
    }
    /* Show or set all quotas if requested */

    if (key & QUOTA_ALL) {
	if (arg1 && *arg1) {
	    value = atoi(arg1);
	    set = 1;
	} else if (key & (QUOTA_SET | QUOTA_FIX)) {
	    value = 0;
	    set = 1;
	}
	if (set) {
	    STARTLOG(LOG_WIZARD, "WIZ", "QUOTA")
		log_name(player);
	    log_text((char *) " changed everyone's quota.");
	    ENDLOG
	}
	show_quota_header(player);
	DO_WHOLE_DB(i) {
	    if (isPlayer(i)) {
		if (set)
		    mung_quotas(i, key, value);
		show_quota(player, i);
	    }
	}
	return;
    }
    /* Find out whose quota to show or set */

    if (!arg1 || *arg1 == '\0') {
	who = Owner(player);
    } else {
	who = lookup_player(player, arg1, 1);
	if (!Good_obj(who)) {
	    notify_quiet(player, "Not found.");
	    return;
	}
    }

    /* Make sure we have permission to do it */

    if (!Wizard(player)) {
	if (arg2 && *arg2) {
	    notify_quiet(player, "Permission denied.");
	    return;
	}
	if (Owner(player) != who) {
	    notify_quiet(player, "Permission denied.");
	    return;
	}
    }
    if (arg2 && *arg2) {
	set = 1;
	value = atoi(arg2);
    } else if (key & QUOTA_FIX) {
	set = 1;
	value = 0;
    }
    if (set) {
	STARTLOG(LOG_WIZARD, "WIZ", "QUOTA")
	    log_name(player);
	log_text((char *) " changed the quota of ");
	log_name(who);
	ENDLOG
	    mung_quotas(who, key, value);
    }
    show_quota_header(player);
    show_quota(player, who);
}
