/****************************************************************************
  PROGRAM INFO
****************************************************************************/

#define VERSION "1.05"

/*  File      C_Source
    Purpose   Financial Calculator
    Version   A 1.05
    Author    Tony Shew
    RISC User August/September 1992
    Program   Subject to Copyright
              Not Public Domain
*/

/****************************************************************************
  #INCLUDE's
****************************************************************************/

#include "baricon.h"
#include "dbox.h"
#include "event.h"
#include "menu.h"
#include "msgs.h"
#include "os.h"
#include "res.h"
#include "resspr.h"
#include "template.h"
#include "werr.h"
#include "wimp.h"
#include "wimpt.h"
#include "win.h"

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

/****************************************************************************
  GLOBAL DATA / MACROs
****************************************************************************/

#define BEEP os_swi0(256+7)

static char *app_title     = "Finances";
static char *app_resourses = "Finances";
static char *app_baricon   = "!Finances";
static int   app_eventmask = wimp_EMPTRLEAVE|wimp_EMPTRENTER|wimp_EMNULL;

enum display_dbox { MORTGAGE, LOAN };
enum { CALC = 2, SAVE, LOAD };

static double eloan, einterest, etax, erelief, einsurance;
static double rloan, rinterest, rtax, rrelief, rterm, rinsurance;
enum { RLOAN = 5, RINTEREST, RTAX, RRELIEF, RTERM, RINSURANCE, RPAYMENT,
       ELOAN, EINTEREST, ETAX, ERELIEF, EINSURANCE, EPAYMENT };

static int cmonths;
static double cloan, cpayment, cinterest, capr, ctotal;
static double bloan, binterest, bmonths, btotal;

enum { CLOAN = 5, CPAYMENT, CINTEREST, CAPR, CMONTHS, CTOTAL, 
       BLOAN, BINTEREST, BMONTHS, BPAYMENT, BTOTAL };

/****************************************************************************
  ICON BAR MENU STRUCTURE
****************************************************************************/

static menu icon_menu;
#define icon_menu_title "Finances"
enum icon_menu_list { icon_menu_info = 1,
                      icon_menu_mortgage,
                      icon_menu_loan,
                      icon_menu_quit
                    };
#define icon_menu_items msgs_lookup("imenu:>Info,Mortgages,Loans,Quit")

/****************************************************************************
  COMMON FNs
****************************************************************************/

static double get_dbox_double(dbox d, int field)
{
  char temp[32];
  dbox_getfield(d, field, temp, 32);
  return atof(temp);
}

static void set_dbox_double(dbox d, int field, double value, int dp)
{
  char temp[32];
  sprintf(temp, "%.*f", dp, value);
  dbox_setfield(d, field, temp);
}

static double decimal_accuracy(double value, int dp)
{
  char temp[32];
  sprintf(temp, "%.*f", dp, value);
  return atof(temp);
}

/****************************************************************************
  DISPLAY LOAN DBOX
****************************************************************************/

static void loan_save_data(void)
{
  FILE *out;
  char *ps = "File: !Finances.Data.Loan";

  if ((out = res_openfile("Data.Loan", "wb")) != NULL) {
    fprintf(out, "%f %f %f\n%f %f %f\n\n%s",
                  bloan, binterest, bmonths,
                  cloan, cpayment, cinterest, ps);
    fclose(out);
  }
  else
    werr(FALSE, msgs_lookup("lfile:Unable to save data to !Finances.Data.Loan file."));
}

static void loan_load_data(void)
{
  FILE *in;

  if ((in = res_openfile("Data.Loan", "rb")) != NULL) {
    fscanf(in, "%lf %lf %lf %lf %lf %lf",
                &bloan, &binterest, &bmonths,
                &cloan, &cpayment, &cinterest);
    fclose(in);
  }
  if (!bloan) bloan = 1000;
  if (!binterest) binterest = 23.4;
  if (!bmonths) bmonths = 24;
  if (!cloan) cloan = 1000;
  if (!cpayment) cpayment = 75;
  if (!cinterest) cinterest = 2.25;
}

static double bankloan_payment(void)
{
  double nominal, payment, dtemp;
  int itemp;

  if (binterest <= 0) {
    btotal = bloan;
    payment = bloan / bmonths;
  }
  else {
    if (decimal_accuracy(binterest, 1) == decimal_accuracy(binterest, 2))
      binterest += 0.05;
    nominal = pow(1 + (binterest / 100), 0.083333) - 1;
    dtemp = ((1 - (pow((1 + nominal), -(bmonths)))) / nominal) + 0.005;
    dtemp = bloan / dtemp;
    itemp = (int)(dtemp * 100);
    payment = (double)itemp / 100;
    btotal = payment * bmonths;
  }
  return payment;
}

static void creditcard_calc(void)
{
  int months;
  double loan = cloan;
  double interest = (1 + (cinterest / 100));

  if (cinterest <= 0)
    capr = 0;
  else
    capr = (pow(1 + cinterest / 100, 12) - 1) * 100 - 0.05;

  if (cpayment <= cloan * cinterest / 100 + 1)
    cpayment = cloan * cinterest / 100 + 1;
  if (cpayment > cloan)
    cpayment = cloan;

  months = 1;
  while (loan > cpayment) {
    loan -= cpayment;
    loan *= interest;
    months++;
  }
  if (loan)
    cmonths = months;
  else
    cmonths = 0;
  ctotal = (--months * cpayment) + loan;
}

static void fillin_loan_dbox(dbox d)
{
  set_dbox_double(d, BLOAN, bloan, 2);
  set_dbox_double(d, BINTEREST, binterest, 1);
  set_dbox_double(d, BMONTHS, bmonths, 0);
  set_dbox_double(d, BPAYMENT, bankloan_payment(), 2);
  set_dbox_double(d, BTOTAL, btotal, 2);
  creditcard_calc();
  set_dbox_double(d, CLOAN, cloan, 2);
  set_dbox_double(d, CPAYMENT, cpayment, 2);
  set_dbox_double(d, CINTEREST, cinterest, 2);
  set_dbox_double(d, CAPR, capr, 1);
  dbox_setnumeric(d, CMONTHS, cmonths);
  set_dbox_double(d, CTOTAL, ctotal, 2);
}

static void read_loan_dbox(dbox d)
{
  bloan     = get_dbox_double(d, BLOAN);
  binterest = get_dbox_double(d, BINTEREST);
  bmonths   = get_dbox_double(d, BMONTHS);
  cloan     = get_dbox_double(d, CLOAN);
  cpayment  = get_dbox_double(d, CPAYMENT);
  cinterest = get_dbox_double(d, CINTEREST);
}

static void loan_dbox(void)
{
  int response;
  dbox d;

  if ((d = dbox_new("loan")) != NULL) {
    dbox_showstatic(d);
    fillin_loan_dbox(d);

    while ((response = dbox_fillin(d)) > dbox_CLOSE) {

      switch (response) {

        case CALC:
          read_loan_dbox(d);
          fillin_loan_dbox(d);
          break;

        case SAVE:
          read_loan_dbox(d);
          loan_save_data();
          break;

        case LOAD:
          loan_load_data();
          fillin_loan_dbox(d);
          break;

        case dbox_CLOSE:
          dbox_dispose(&d);
          break;
      }
      BEEP;
    }
    dbox_dispose(&d);
  }
}

/****************************************************************************
  DISPLAY MORTGAGE DBOX
****************************************************************************/

static void mort_save_data(void)
{
  FILE *out;
  char *ps = "File: !Finances.Data.Mortgage";

  if ((out = res_openfile("Data.Mortgage", "wb")) != NULL) {
    fprintf(out, "%f %f %f %f %f %f\n%f %f %f %f %f\n\n%s",
                  rloan, rinterest, rtax, rrelief, rterm, rinsurance,
                  eloan, einterest, etax, erelief, einsurance, ps);
    fclose(out);
  }
  else
    werr(FALSE, msgs_lookup("mfile:Unable to save data to !Finances.Data.Mortgage file."));
}

static void mort_load_data(void)
{
  FILE *in;

  if ((in = res_openfile("Data.Mortgage", "rb")) != NULL) {
    fscanf(in, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", 
                &rloan, &rinterest, &rtax, &rrelief, &rterm, &rinsurance,
                &eloan, &einterest, &etax, &erelief, &einsurance);
    fclose(in);
  }
  if (!rloan) rloan = 50000;
  if (!rinterest) rinterest = 11.5;
  if (!rtax) rtax = 25;
  if (!rrelief) rrelief = 30000;
  if (!rterm) rterm = 25;
  if (!eloan) eloan = 50000;
  if (!einterest) einterest = 11.5;
  if (!etax) etax = 25;
  if (!erelief) erelief = 30000;
}

static double repayment_calc_under(double tax)
{
  double interest, termcalc;
  int    temp;

  interest = rinterest / 100 * ((100 - tax) / 100);
  termcalc = pow(1 + interest, -(rterm));
  temp = (int)(((100000 / ((1 - termcalc) / interest)) / 12) + 0.5);

  return temp  * (rloan / 100000);
}

static double repayment_calc_over(void)
{
  double x, y, z, c1, c2, p1, p2, interest, ninterest;

  interest = rinterest / 100;
  ninterest = interest * (1 - (rtax / 100));
  x = rterm;
  y = 0;

  do {
    z = (x + y) / 2;
    c1 = z;
    c2 = rterm - c1;
    p1 = ((rloan-rrelief)/((1-(pow(1+interest,-(c1))))/interest))+(rrelief*ninterest);
    p2 = rrelief / ((1 - (pow(1 + ninterest, -(c2)))) / ninterest);
    p1 = decimal_accuracy(p1, 4);
    p2 = decimal_accuracy(p2, 4);
    if (p1 > p2)
      y = z;
    else if (p1 < p2)
      x = z;
  } while (p1 != p2);

  return (p1 / 12) + 0.005;
}

static double repayment_payment(void)
{
  if (rrelief < 1)
    return repayment_calc_under(0);
  else if (rloan <= rrelief)
    return repayment_calc_under(rtax);
  else
    return repayment_calc_over();
}

static double endowment_payment(void)
{
  double temp;

  if (eloan <= erelief)
    temp = ((eloan * einterest * ((100 - etax) / 100)) / 1200);
  else
    temp = ((((eloan - erelief) * einterest) + 
           (erelief * einterest * ((100 - etax) / 100))) / 1200);

  return temp + 0.005;
}

static void fillin_mort_dbox(dbox d)
{
  set_dbox_double(d, RLOAN, rloan, 2);
  set_dbox_double(d, RINTEREST, rinterest, 2);
  set_dbox_double(d, RTAX, rtax, 2);
  set_dbox_double(d, RRELIEF, rrelief, 2);
  set_dbox_double(d, RTERM, rterm, 2);
  set_dbox_double(d, RINSURANCE, rinsurance, 2);
  set_dbox_double(d, RPAYMENT, repayment_payment() + rinsurance, 2);
  set_dbox_double(d, ELOAN, eloan, 2);
  set_dbox_double(d, EINTEREST, einterest, 2);
  set_dbox_double(d, ETAX, etax, 2);
  set_dbox_double(d, ERELIEF, erelief, 2);
  set_dbox_double(d, EINSURANCE, einsurance, 2);
  set_dbox_double(d, EPAYMENT, endowment_payment() + einsurance, 2);
}

static void read_mort_dbox(dbox d)
{
  rloan      = get_dbox_double(d, RLOAN);
  rinterest  = get_dbox_double(d, RINTEREST);
  rtax       = get_dbox_double(d, RTAX);
  rrelief    = get_dbox_double(d, RRELIEF);
  rterm      = get_dbox_double(d, RTERM);
  rinsurance = get_dbox_double(d, RINSURANCE);
  eloan      = get_dbox_double(d, ELOAN);
  einterest  = get_dbox_double(d, EINTEREST);
  etax       = get_dbox_double(d, ETAX);
  erelief    = get_dbox_double(d, ERELIEF);
  einsurance = get_dbox_double(d, EINSURANCE);
}

static void mortgage_dbox(void)
{
  int response;
  dbox d;

  if ((d = dbox_new("mortgage")) != NULL) {
    dbox_showstatic(d);
    fillin_mort_dbox(d);

    while ((response = dbox_fillin(d)) > dbox_CLOSE) {

      switch (response) {

        case CALC:
          read_mort_dbox(d);
          fillin_mort_dbox(d);
          break;

        case SAVE:
          read_mort_dbox(d);
          mort_save_data();
          break;

        case LOAD:
          mort_load_data();
          fillin_mort_dbox(d);
          break;

        case dbox_CLOSE:
          dbox_dispose(&d);
          break;
      }
      BEEP;
    }
    dbox_dispose(&d);
  }
}

/****************************************************************************
  DISPLAY INFO DBOX
****************************************************************************/

static void info_dbox(void)
{
  dbox d;

  if ((d = dbox_new("progInfo")) != NULL) {
    dbox_setfield(d, 4, VERSION);
    dbox_show(d);
    dbox_fillin(d);
    dbox_dispose(&d);
  }
}

/****************************************************************************
  ICON CLICK EVENT HANDLER
****************************************************************************/

static void iconbar_click(wimp_i icon)
{
  static enum display_dbox display = MORTGAGE;

  switch (display++) {

    case MORTGAGE:
      mortgage_dbox();
      break;

    case LOAN:
      loan_dbox();
      display = 0;
      break;
  }
}

/****************************************************************************
  MENU EVENT HANDLER
****************************************************************************/

static void icon_menu_fn(void *handle, char *hit)
{
  switch (hit[0]) {

    case icon_menu_info:
      info_dbox();
      break;

    case icon_menu_mortgage:
      mortgage_dbox();
      break;

    case icon_menu_loan:
      loan_dbox();
      break;

    case icon_menu_quit:
      exit(0);

    default:
      break;
  }
}

/****************************************************************************
  INITIALISATION
****************************************************************************/

static BOOL initialise(void)
{
  wimpt_init(app_title);
  res_init(app_resourses);
  resspr_init();
  template_init();
  dbox_init();
  msgs_init();

  mort_load_data();
  loan_load_data();
  if ((icon_menu = menu_new(icon_menu_title, icon_menu_items)) == NULL)
    return FALSE;
  baricon(app_baricon, (int)resspr_area(), iconbar_click);
  if (!event_attachmenu(win_ICONBAR, icon_menu, icon_menu_fn, 0))
    return FALSE;
  event_setmask(app_eventmask);

  return TRUE;
}

/****************************************************************************
  MAIN PROGRAM
****************************************************************************/

int main()
{
  if (initialise())
    while (TRUE)
      event_process();

  return 0;
}

/****************************************************************************
  END OF FILE
****************************************************************************/
