#ifndef lint
static char *RCSid = "$Header: /usr/brule/guest/empire/empire/emprcs/lib/commands/cons.c,v 2.0 1995/01/25 19:23:25 empire Exp $";
#endif /* not lint */

/*
 * cons.c
 *
 * consider loan or treaty
 *
 * from PSL Empire, 1985
 * pretty much entirely rewritten, 1989
 */

#include "misc.h"
#include "player.h"
#include "loan.h"
#include "nat.h"
#include "treaty.h"
#include "news.h"
#include "xy.h"
#include "nsc.h"
#include "file.h"

/*
 * Things common to a loan or treaty.
 */
struct ltcomstr {
	int	type;			/* EF_LOAN or EF_TREATY */
	int	num;			/* number */
	s_char	*name;			/* "loan" or "treaty" */
	s_char	*Name;			/* "Loan" or "Treaty" */
	natid	proposer;		/* country offering */
	natid	proposee;		/* country offered to */
	natid	mailee;			/* who gets mail about it */
	s_char	op;			/* 'a', 'd', or 'p' */
	union {
		struct	lonstr l;	/* the loan */
		struct	trtstr t;	/* the treaty */
	} u;
};

static int treaty_accept();
static int treaty_decline();
static int loan_accept();
static int loan_decline();
static int postpone();
static accpt();
static decline();
static late();
static prev_signed();

int
cons()
{
	int	rv;
	struct	ltcomstr ltc;

	rv = cons_choose(&ltc);
	if (rv != RET_OK)
		return rv;

	switch (ltc.op) {
	case 'a':
		rv = (ltc.type == EF_TREATY) ? treaty_accept(&ltc)
					     : loan_accept(&ltc);
		break;
	case 'd':
		rv = (ltc.type == EF_TREATY) ? treaty_decline(&ltc)
					     : loan_decline(&ltc);
		break;
	case 'p':
		rv = postpone(&ltc);
		break;
	default:
		pr("Bad operation %c from cons_choose; get help!\n",
			ltc.op);
		break;
	};

	return rv;
}

/*
 * Choose whether we want to accept, decline, or postpone a
 * loan or treaty.  Put all the goodies in ltcp, and return
 * RET_OK if all goes well, and anything else on error.
 */
int
cons_choose(ltcp)
	struct	ltcomstr *ltcp;
{
	s_char	*p;
	extern	int disloan();
	extern	int distrea();
	int	(*dis)();
	struct	lonstr *lp;
	struct	trtstr *tp;
	s_char	prompt[128];
	s_char	buf[1024];

	bzero((s_char *)ltcp, sizeof (*ltcp));
	if (getstarg(player->argp[1], "loan or treaty? ", buf) == 0)
		return RET_SYN;
	ltcp->type = ef_byname(buf);
	switch (ltcp->type) {
	case EF_TREATY:
		ltcp->name = "treaty";
		ltcp->Name = "Treaty";
		dis = distrea;
		break;
	case EF_LOAN:
		ltcp->name = "loan";
		ltcp->Name = "Loan";
		dis = disloan;
		break;
	default:
		pr("You must specify \"loan\" or \"treaty\".\n");
		return RET_SYN;
	}
	sprintf(prompt, "%s number? ", ltcp->Name);
	if ((ltcp->num = onearg(player->argp[2], prompt)) < 0)
		return RET_SYN;
	if (!ef_read(ltcp->type, ltcp->num, (caddr_t)&ltcp->u) ||
	    !(*dis)(ltcp->num, &ltcp->u)) {
		pr("%s #%d is not being offered to you!\n",
			ltcp->Name, ltcp->num);
		return RET_SYN;
	}
	switch (ltcp->type) {
	case EF_LOAN:
		lp = &ltcp->u.l;
		if (lp->l_status == LS_SIGNED) {
			pr("That loan has already been accepted!\n");
			return RET_FAIL;
		}
		ltcp->proposer = lp->l_loner;
		ltcp->proposee = lp->l_lonee;
		break;
	case EF_TREATY:
		tp = &ltcp->u.t;
		if (tp->trt_status == TS_SIGNED) {
			pr("That treaty has already been accepted!\n");
			return RET_FAIL;
		}
		ltcp->proposer = tp->trt_cna;
		ltcp->proposee = tp->trt_cnb;
		break;
	}
	ltcp->mailee = (ltcp->proposer == player->cnum)
		? ltcp->proposee : ltcp->proposer;
	while ((p = getstarg(player->argp[3], "Accept, decline or postpone? ", buf)) && *p) 
{
		if (*p == 'a' || *p == 'd' || *p == 'p')
			break;
		player->argp[3] = 0;
	}
	if (p == 0 || *p == 0)
		return RET_SYN;
	ltcp->op = *p;
	return RET_OK;
}

/*
 * Accept a loan.  If the offering country has too little money,
 * leave him $100 left and offer the rest.  Return RET_OK on
 * success, anything else on error.
 */
static int
loan_accept(ltcp)
	struct	ltcomstr *ltcp;
{
	struct	lonstr *lp;
	struct	natstr *lender;
	struct	nstr_item nstr;
	struct  lonstr loan;

	lp = &ltcp->u.l;
	if (ltcp->proposee != player->cnum) {
		pr("%s %d is still pending.\n", ltcp->Name, ltcp->num);
		return RET_OK;
	}
	if (!getloan(ltcp->num, (caddr_t)lp)) {
		pr("loan_accept: can't read loan; get help!\n");
		return RET_SYS;
	}
	if (lp->l_status == LS_FREE) {	/* other guy retratcted already */
		late(ltcp);
		return RET_OK;
	}
	if (lp->l_status == LS_SIGNED) { /* already signed somehow */
		prev_signed(ltcp);
		return RET_OK;
	}
	/* check to see if a loan already exists */
	snxtitem_all(&nstr, EF_LOAN);
	while (nxtitem(&nstr, (s_char *) &loan)) {
		if (loan.l_status == LS_SIGNED && loan.l_lonee == lp->l_loner
					&& (loan.l_loner == lp->l_lonee)) {
	          pr("He already owes you money - make him repay his loan!\n");
			return RET_OK;
		}
	}
	lender = getnatp(ltcp->proposer);
	if (lender->nat_money < lp->l_amtdue) {	/* other guy is poor */
		lp->l_amtdue = lender->nat_money - 100;
		pr("%s no longer has the funds.\n", cname(ltcp->proposer));
;
		if (lp->l_amtdue <= 0)
			return RET_FAIL;
		pr("You may borrow $%d at the same terms.\n",
			lp->l_amtdue);
	}
	lender->nat_money -= lp->l_amtdue;
	putnat(lender);
	player->dolcost -= lp->l_amtdue;
	lp->l_amtpaid = 0;
	(void) time(&lp->l_lastpay);
	lp->l_duedate = lp->l_ldur * 86400 + lp->l_lastpay;
	lp->l_status = LS_SIGNED;
	if (!putloan(ltcp->num, (s_char *)lp)) {
		pr("Problem writing lp->to disk; get help!\n");
		return RET_FAIL;
	}
	accpt(ltcp);
	pr("You are now $%d richer (sort of).\n", lp->l_amtdue);
	return RET_OK;
}

/*
 * Declne a loan.  Return RET_OK on success, anything else on error.
 */
static int
loan_decline(ltcp)
	struct	ltcomstr *ltcp;
{
	struct	lonstr *lp;

	lp = &ltcp->u.l;
	if (!getloan(ltcp->num, lp)) {
		pr("Decline: can't read loan; get help!\n");
		return RET_SYS;
	}
	/* loan got accepted somehow between now and last time we checked */
	if (lp->l_status == LS_SIGNED) {
		late(ltcp);
		return RET_OK;
	}
	lp->l_status = LS_FREE;
	if (!putloan(ltcp->num, lp)) {
		pr("loan_decline: can't write loan; get help!\n");
		return RET_SYS;
	}
	decline(ltcp);
	return RET_OK;
}

/*
 * Accept a treaty.  Return RET_OK on success, anything else on error.
 */
static int
treaty_accept(ltcp)
	struct	ltcomstr *ltcp;
{
	struct	trtstr *tp;

	tp = &ltcp->u.t;
	if (ltcp->proposee != player->cnum) {
		pr("%s %d is still pending.\n", ltcp->Name, ltcp->num);
		return RET_OK;
	}
	if (!gettre(ltcp->num, tp)) {
		pr("Accept: can't read treaty; get help!\n");
		return RET_SYS;
	}
	if (tp->trt_status == TS_FREE) {	/* treaty offer withdrawn */
		late(ltcp);
		return RET_OK;
	}
	if (tp->trt_status == TS_SIGNED) {	/* somehow got accepted */
		prev_signed(ltcp);
		return RET_OK;
	}
	tp->trt_status = TS_SIGNED;
	if (!puttre(ltcp->num, tp)) {
		pr("Problem saving treaty; get help!\n");
		return RET_SYS;
	}
	accpt(ltcp);
	pr("Treaty in effect until %s", ctime(&tp->trt_exp));
	return RET_OK;
}

/*
 * Decline a treaty.  Return RET_OK on success, anything else on error.
 */
static int
treaty_decline(ltcp)
	struct	ltcomstr *ltcp;
{
	struct	trtstr *tp;

	tp = &ltcp->u.t;
	if (!gettre(ltcp->num, tp)) {
		pr("Decline: can't read treaty; get help!\n");
		return RET_SYS;
	}
	/* treaty got signed somehow between now and last time we read it */
	if (tp->trt_status == TS_SIGNED) {
		late(ltcp);
		return RET_OK;
	}
	tp->trt_status = TS_FREE;
	if (!puttre(ltcp->num, tp)) {
		pr("Problem saving treaty; get help!\n");
		return RET_SYS;
	}
	decline(ltcp);
	return RET_OK;
}

/*
 * Postpone a treaty; always succeeds.
 */
static int
postpone(ltcp)
	struct	ltcomstr *ltcp;
{
	pr("%s %d is still pending.\n", ltcp->Name, ltcp->num);
	if (ltcp->proposee == player->cnum)
		wu(0, ltcp->proposer, "%s %d considered by %s\n",
			ltcp->name, ltcp->num, cname(player->cnum));
	return RET_OK;
}

/*
 * Somebody tried to accept a loan/treaty that was retracted,
 * or to decline a loan/treaty they already signed.
 */
static
late(ltcp)
	struct	ltcomstr *ltcp;
{
	pr("Too late; that %s %s!\n", ltcp->name,
		(ltcp->op == 'a') ? "is no longer being offered"
				  : "has already been accepted");
}

/*
 * Loan or treaty was previously signed.
 */
static
prev_signed(ltcp)
	struct	ltcomstr *ltcp;
{
	pr("%s #%d is already in effect.\n", ltcp->Name, ltcp->num);
}

/*
 * Post-processing after successful declination of loan or treaty.
 * Notify the folks involved.
 */
static
decline(ltcp)
	struct	ltcomstr *ltcp;
{
	if (ltcp->proposee == player->cnum) {
		wu(0, ltcp->proposer, "%s %d refused by %s\n",
			ltcp->Name, ltcp->num, cname(player->cnum));
		pr("%s %d refused.\n", ltcp->Name, ltcp->num);
	} else {
		wu(0, ltcp->proposee,
			"%s offer %d retracted by %s\n",
			ltcp->Name, ltcp->num, cname(player->cnum));
		pr("%s offer %d retracted.\n",
			ltcp->Name, ltcp->num);
	}
}

/*
 * Post-processing after successful acceptance of loan or treaty.
 * Notify the press, and the folks involved.
 * (Weird spelling is to avoid accept(2)).
 */
static
accpt(ltcp)
	struct	ltcomstr *ltcp;
{
	if (ltcp->type == EF_LOAN)
		nreport(ltcp->proposer, N_MAKE_LOAN, player->cnum, 1);
	else
		nreport(player->cnum, N_SIGN_TRE, ltcp->mailee, 1);
	wu(0, ltcp->mailee, "%s #%d accepted by %s\n",
		ltcp->Name, ltcp->num, cname(player->cnum));
}
