#include
#include
#include
#include
#include "contract.h"
#include "loans.h"
static int WIDTH, HEIGHT;
static int padscroll, duration;
static WINDOW *pad;
_Noreturn static void finish(int sig);
void display_custom_form(FORM *);
void print_contract(WINDOW *w, int x, int y, contract *c, double sumI,
double sumD);
int run_sim(FORM *, char **contract_subtypes);
int min(int a, int b);
int main(void) {
int ch, i;
/* setup ncurses */
signal(SIGINT, finish); /* arrange interrupts to terminate */
initscr(); /* initialize the curses library */
cbreak(); /* take input chars one at a time don't wait for CR */
noecho(); /* echo input */
nonl(); /* do not LF->CR-LF on output */
intrflush(stdscr, FALSE); /* do not flush on interrupts */
keypad(stdscr, TRUE); /* enable keyboard mapping */
getmaxyx(stdscr, HEIGHT, WIDTH);
/* create the form */
FIELD *fields[8];
FORM *form;
char *contract_types[] = {"loan", "savings", NULL};
char *contract_subtypes[] = {"bullet", "sla", "mortgage", NULL};
/* initialize fields */
fields[0] = new_field(1, 11, 4, 22, 0, 0); /* contract type */
set_field_type(fields[0], TYPE_ENUM, contract_types, FALSE, TRUE);
fields[1] = new_field(1, 11, 5, 22, 0, 0); /* contract subtype */
set_field_type(fields[1], TYPE_ENUM, contract_subtypes, FALSE, TRUE);
fields[2] = new_field(1, 11, 6, 22, 0, 0); /* contract duration */
set_field_type(fields[2], TYPE_INTEGER, 1, 0, INT_MAX);
fields[3] = new_field(1, 11, 7, 22, 0, 0); /* yearly payments */
set_field_type(fields[3], TYPE_INTEGER, 1, 0, INT_MAX);
fields[4] = new_field(1, 11, 8, 22, 0, 0); /* delay duration */
set_field_type(fields[4], TYPE_INTEGER, 1, 0, INT_MAX);
fields[5] = new_field(1, 11, 9, 22, 0, 0); /* starting amount */
set_field_type(fields[5], TYPE_NUMERIC, 2, 0.01, 0.0);
fields[6] = new_field(1, 11, 10, 22, 0, 0); /* rate */
set_field_type(fields[6], TYPE_NUMERIC, 3, 0.0, 1.0);
fields[7] = NULL;
/* configure fields */
for (i = 0; fields[i]; i++) {
/* Print a line for the option */
set_field_back(fields[i], A_UNDERLINE);
/* Don't go to next field when this field is filled up*/
field_opts_off(fields[i], O_AUTOSKIP);
}
/* create form */
form = new_form(fields);
display_custom_form(form);
refresh();
int formactive = TRUE;
/* mainloop */
while ((ch = getch()) != KEY_EXIT) {
if (formactive) {
switch (ch) {
case KEY_DOWN:
/* Go to next field */
form_driver(form, REQ_NEXT_FIELD);
/* Go to the end of the present buffer */
/* Leaves nicely at the last character */
form_driver(form, REQ_END_LINE);
break;
case KEY_UP:
form_driver(form, REQ_PREV_FIELD);
form_driver(form, REQ_END_LINE);
break;
case KEY_LEFT:
form_driver(form, REQ_PREV_CHOICE);
break;
case KEY_RIGHT:
form_driver(form, REQ_NEXT_CHOICE);
break;
case KEY_BACKSPACE:
form_driver(form, REQ_DEL_PREV);
break;
case '\r':
if ((E_OK == form_driver(form, REQ_VALIDATION)) &&
run_sim(form, contract_subtypes)) {
unpost_form(form);
formactive = FALSE;
curs_set(0);
box(stdscr, 0, 0);
padscroll = 0;
mvwprintw(stdscr, 1, 2, "Reinbursement Table");
mvwprintw(stdscr, 3, 3,
"%4s/%-4s | %12s | %10s | %10s | %10s\n", "cur",
"tot", "principal", "interest", "part",
"annuity");
refresh();
prefresh(pad, padscroll, 0, 4, 1, HEIGHT - 2, WIDTH - 1);
}
break;
default:
/* If this is a normal character, it gets printed */
form_driver(form, ch);
}
} else {
switch (ch) {
case KEY_DOWN:
padscroll += (padscroll < duration) ? 1 : 0;
pnoutrefresh(pad, padscroll, 0, 4, 1, HEIGHT - 2, WIDTH - 1);
doupdate();
break;
case KEY_UP:
padscroll -= (padscroll > 0) ? 1 : 0;
pnoutrefresh(pad, padscroll, 0, 4, 1, HEIGHT - 2, WIDTH - 1);
doupdate();
break;
case KEY_NPAGE:
padscroll += min(HEIGHT - 6, duration - padscroll);
pnoutrefresh(pad, padscroll, 0, 4, 1, HEIGHT - 2, WIDTH - 1);
doupdate();
break;
case KEY_PPAGE:
padscroll -= min(HEIGHT - 6, padscroll);
pnoutrefresh(pad, padscroll, 0, 4, 1, HEIGHT - 2, WIDTH - 1);
doupdate();
break;
case KEY_HOME:
padscroll = 0;
pnoutrefresh(pad, padscroll, 0, 4, 1, HEIGHT - 2, WIDTH - 1);
doupdate();
break;
case KEY_END:
padscroll = duration;
pnoutrefresh(pad, padscroll, 0, 4, 1, HEIGHT - 2, WIDTH - 1);
doupdate();
break;
case 'q':
display_custom_form(form);
formactive = TRUE;
curs_set(1);
break;
default:;
}
}
}
delwin(pad);
if (formactive)
unpost_form(form);
free_form(form);
for (i = 0; fields[i]; i++)
free_field(fields[i]);
finish(0);
}
_Noreturn static void finish(int sig) {
endwin();
exit(sig);
}
void display_custom_form(FORM *form) {
post_form(form);
mvprintw(2, 5, "Initialization Parameters");
mvprintw(4, 2, "Contract type:");
mvprintw(5, 2, "Contract subtype:");
mvprintw(6, 2, "Contract Duration:");
mvprintw(7, 2, "Yearly payments:");
mvprintw(8, 2, "Delay Duration:");
mvprintw(9, 2, "Starting Amount:");
mvprintw(10, 2, "Rate:");
form_driver(form, REQ_FIRST_FIELD);
}
void print_contract(WINDOW *w, int x, int y, contract *c, double sumI,
double sumD) {
mvwprintw(w, x, y,
"%4u/%-4u | %12.2f | %10.2f | %10.2f | %10.2f || %10.2f | "
"%10.2f \n",
c->k, c->n, (double)c->P, (double)c->I, (double)c->D,
(double)c->A, sumI, sumD);
}
int run_sim(FORM *form, char **contract_subtypes) {
/* loan_type type; */
int n, d, yp;
double r, p;
double sumD, sumI, sumA;
loan_type lt;
FIELD **fields = form_fields(form);
lt = read_loan_type(contract_subtypes, field_buffer(fields[1], 0));
n = atoi(field_buffer(fields[2], 0));
yp = atoi(field_buffer(fields[3], 0));
d = atoi(field_buffer(fields[4], 0));
p = atof(field_buffer(fields[5], 0));
r = atof(field_buffer(fields[6], 0));
if (!n || !yp || (p <= 0.0))
return 0;
// adapt wrt yearly payments
if (yp > 1) {
n = n * yp;
d = d * yp;
r = r / (double)yp;
}
/* setup sums */
sumA = sumD = sumI = 0.0;
/* setup pad */
pad = newpad(n + 3, WIDTH - 2);
/* run simulation */
loan l = loan_init(lt, n, d, r, p);
for (int i = 0; i <= n; i++) {
if (i) {
sumD += l.c->D;
sumI += l.c->I;
sumA += l.c->A;
}
print_contract(pad, i, 2, l.c, sumI, sumD);
loan_update(l);
}
mvwprintw(pad, n + 2, 2,
" Totals: | %10.2f | %10.2f | %10.2f\n", sumI,
sumD, sumA);
duration = n - HEIGHT + 8;
return 1;
}
int min(int a, int b) { return (a < b) ? a : b; }