/**********************************************************************
 * loan.cpp
 * Tom Kelliher
 *  CS17
 *
 * This program prints a loan repayment schedule.  The inputs are the
 * loan amount, the annual interest rate, and the monthly payment.
 * The program validates that the payment is greater than the monthly
 * interest on the first month, guaranteeing that the debt is 
 * eventually retired.
 *
 * Input is from the keyboard, output to the monitor.
 **********************************************************************/


// Library files.

#include <iostream.h>
#include <iomanip.h>


// Constants.

const int FIELD_WIDTH = 12;


// Function prototypes.

void getInputs(double& balance, double& apr, double& payment);
void printHeadings(void);
double calcInt(double balance, double apr);
double calcPrin(double payment, double intPay);
void printLine(double bBal, double payment, double iPay, double pPay,
               double eBal);
void printFmtStr(char str[]);
void printFmtNum(double value);


/**********************************************************************
 * main
 **********************************************************************/

int main()
{
   double balance;   // Balance at beginning of month.
   double apr;       // Annual percentage rate (interest rate).
   double payment;   // Monthly payment.
   double intPay;    // Payment on the interest.
   double prinPay;   // Payment on the principal.

   getInputs(balance, apr, payment);

   printHeadings();

   // Print the monthly payment information.
   while (balance > payment)
   {
      intPay = calcInt(balance, apr);
      prinPay = calcPrin(payment, intPay);

      // Last parameter is balance at the end of the month.
      printLine(balance, payment, intPay, prinPay, balance - prinPay);

      balance -= prinPay;
   }

   /*
   Balance is now less than payment.  Payment is reduced to the
   balance, no payment on the interest is needed.  We've completely
   payed off the principal.
   */
   printLine(balance, balance, 0.0, balance, 0.0);

   return 0;
}


/**********************************************************************
 * getInputs --- Prompt for and get loan amount, apr, and monthly
 * payment.
 *
 * Preconditions: none.
 *
 * Postconditions: returns the loan amount (balance), apr, any monthly
 * payment.  The monthly payment is greater than the first month's
 * interest charge.
 *
 * Note the use of reference parameters to return values through the
 * actual parameters themselves, rather than the function name.
 **********************************************************************/

void getInputs(double& balance, double& apr, double& payment)
{
   double intDue;   // Interest payment due the first month.

   cout << "Enter loan amount: ";
   cin >> balance;

   cout << "Enter annual interest rate as a percentage: ";
   cin >> apr;
   apr /= 100.0;

   intDue = balance * apr / 12.0;

   cout << "Enter the monthly payment: ";
   cin >> payment;

   while (payment <= intDue)
   {
      cout << "***> Monthly payment too small.\n";
      cout << "Enter the monthly payment: ";
      cin >> payment;
   }
}


/**********************************************************************
 * printHeadings --- Print headings for each of the columns of the
 * output.
 *
 * Preconditions: None.
 *
 * Postconditions: Prints headings for each of the columns of the
 * output.  Each column is FIELD_WIDTH characters wide.
 **********************************************************************/

void printHeadings(void)
{
   int i;

   // Print first line.
   cout << endl << endl;
   printFmtStr("Beginning");
   printFmtStr("Payment");
   printFmtStr("Interest");
   printFmtStr("Principal");
   printFmtStr("Ending");
   cout << endl;

   // Print second line.
   printFmtStr("Balance");
   printFmtStr("");
   printFmtStr("");
   printFmtStr("");
   printFmtStr("Balance");
   cout << endl;

   // Print a separator row.
   i = 5;
   while (i > 0)
   {
      printFmtStr("----------");
      --i;
   }
   cout << endl;
}


/**********************************************************************
 * calcInt --- Calculate the monthly interest payment.
 *
 * Preconditions: balance is the amount of the loan balance and is
 * greater than 0.0.  apr is the annual interest rate, again greater
 * than 0.0.
 *
 * Postconditions: Returns the monthly interest payment.
 **********************************************************************/

double calcInt(double balance, double apr)
{
   return balance * apr / 12.0;
}


/**********************************************************************
 * calcPrin --- Calculate the monthly principal payment.
 *
 * Preconditions: payment is the monthly payment and is greater than
 * 0.0.  intPay is the monthly interest payment, and is greater than
 * 0.0.
 *
 * Postconditions: Returns the monthly principal payment.
 **********************************************************************/

double calcPrin(double payment, double intPay)
{
   return payment - intPay;
}


/**********************************************************************
 * printLine --- Print the month's payment information.
 *
 * Preconditions: bBal is the balance at the beginning of the month,
 * payment is the monthly payment, iPay is the interest payment, pPay
 * is the principal payment, and eBal is the balance at the end of the
 * month.  All values are assumed to be positive.
 *
 * Postconditions: Prints the five values, properly formatted in
 * fields FIELD_WIDTH characters wide.
 **********************************************************************/

void printLine(double bBal, double payment, double iPay, double pPay,
               double eBal)
{
   printFmtNum(bBal);
   printFmtNum(payment);
   printFmtNum(iPay);
   printFmtNum(pPay);
   printFmtNum(eBal);
   cout << endl;
}


/**********************************************************************
 * printFmtStr --- Prints a literal string.
 *
 * Preconditions: str is a '\0' terminated character string whose 
 * length is <= FIELD_WIDTH.
 *
 * Postconditions: Prints str right justified in a field of width
 * FIELD_WIDTH.
 **********************************************************************/

void printFmtStr(char str[])
{
   cout << setw(FIELD_WIDTH) << setiosflags(ios::right) << str;
}


/**********************************************************************
 * printFmtNum --- Prints a value formatted as a dollar amount.
 *
 * Preconditons: value is printable in FIELD_WIDTH digits.
 *
 * Postconditons: value is printed right justified as a dollar amount
 * in a field of width FIELD_WIDTH.
 **********************************************************************/

void printFmtNum(double value)
{
   cout << setw(FIELD_WIDTH) << setprecision(2) 
        << setiosflags(ios::showpoint) << setiosflags(ios::fixed)
        << setiosflags(ios::right) << value;

   // Reset some of the formatting to "default" values.
   cout << setprecision(6) << resetiosflags(ios::showpoint)
        << resetiosflags(ios::fixed);
}
