#!/bin/bash

# carpymnt.sh  Friday 3rd December 2004

# A script created by Ross Drummond of West Finance Ltd to calculate payments in a hire purchase contract
# Adapted from script in Advanced Bash Guide
# To run, this script requires;
#	bash, a linux/unix/apple OSX shell
#	bc, a floating point maths program. The bash shell cannot do floating point arithmetic.
#	perl, a scripting language required by showtable.
#	showtable, a perl module to display output in a neat text based table.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, you can either send email to this
# program's maintainer or write to: The Free Software Foundation,
# Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA.

function ShowPeriods 
	{
		echo -e "\t Years \t Months \t Fortnights \t Weeks \n \t ½ \t 6 \t 13 \t 26 \n \t 1 \t 12 \t 26 \t 52 \n \t 1 ½ \t 18 \t 39 \t 78 \n \t 2 \t 24 \t 52 \t 104 \n \t 2 ½ \t 30 \t 65 \t 130 \n \t 3 \t 36 \t 78 \t 156 \n Payments per year \t 1 \t 12 \t 26 \t 52"|showtable -t=1 ;
	}
	
function isdigit
	{	# Test if number is digit & not null.
		 if [ -z "$1" ] ; then
    			echo "You didn't enter anything. Enter 0 (zero) at least." 
			return 1
  		fi
		
		# Strip digits with sed. If the nodigits variable is filled then non digits have been passed, thus an error.
		local nodigits="$(echo $1 | sed 's/[[:digit:]]//g')"
		
		if [ ! -z "$nodigits" ] ; then
    			echo "Invalid number format! Only whole numbers, no commas, spaces, decimal points, etc." 
    			return 1
  		fi
		return 0
	}
	

# Lets test to see if either bc or showtable is installed.
# Test code borrowed from Volker Kuhlmann. http://cantua.canterbury.ac.nz/~vku10/  Thanks Volker.
type bc >/dev/null 2>&1 || { echo "Oops - Can't find bc. Install it first!"; exit; }
type showtable >/dev/null 2>&1 || { echo "Oops - Can't find showtable. Install it first!"; exit; }

echo -e "Welcome to this bash script that calculates payments for a hire purchase contract. \nPlease follow the prompts. \nIt will return the figures required to write up the contract. \n******Important; Enter whole dollars only and zero for empty fields.******\n"

echo -e "Do you wish to view a table of payment periods? (y/n)"
read ViewTable

if [[ "$ViewTable" = [yY] ]]; then
	ShowPeriods
fi

echo -e "Enter the purchase price."
read PurchasePrice

isdigit $PurchasePrice

# If isdigit function returns anything other than zero we have an error.
if [ $? -ne 0 ];then
	exit
fi


echo "Enter the PPI premium."
read PPI

isdigit $PPI

if [ $? -ne 0 ];then
	exit
fi

echo "Enter other charges."
read OtherCharges

isdigit $OtherCharges

if [ $? -ne 0 ];then
	exit
fi

echo "Enter deposit."
read Deposit

isdigit $Deposit

if [ $? -ne 0 ];then
	exit
fi

(( $Deposit >= $PurchasePrice )) && {
	echo "deposit greater than or equal to Purchase price" >&2
	exit 
}

echo "Enter trade in allowance."
read TradeIn

isdigit $TradeIn

if [ $? -ne 0 ];then
	exit
fi

(( $TradeIn >= $PurchasePrice )) && {
	echo "Trade in greater than or equal to Purchase price" >&2
	exit 
}

echo "Enter the number of payments over the term of the loan"
read NumPayments

isdigit $NumPayments

if [ $? -ne 0 ];then
	exit
fi

echo "Enter the number of payments in a year"
read AnnualPayments

isdigit $AnnualPayments

if [ $? -ne 0 ];then
	exit
fi

echo -e "Enter interest rate. If 12.5%, enter \"12.5\", not \".125\"."
read InterestRate

echo "Enter documentation fee."
read DocumentationFee

isdigit $DocumentationFee

if [ $? -ne 0 ];then
	exit
fi

echo "Enter other fixed charges."
read OtherFixedCharges

isdigit $OtherFixedCharges

if [ $? -ne 0 ];then
	exit
fi

# date is really annal about the format of any dates.
echo -e "Enter the date of first payment. \nPlease use the following format yyyymmdd ie 20041231 for 31/12/2004."
read FirstPaymentDate


TotalGrossCost=$(($PurchasePrice + $PPI + $OtherCharges))
TotalDeposit=$(($TradeIn + $Deposit))
AmountFinanced=$(($TotalGrossCost - $TotalDeposit))
TotalFixedCharges=$(($DocumentationFee + $OtherFixedCharges))

interest_r=$(echo "scale=9; $InterestRate/100.0" |bc)


interest_rat=$(echo "scale=9; $interest_r/$AnnualPayments + 1.0" | bc)

top=$(echo "scale=9; $AmountFinanced*$interest_rat^$NumPayments" | bc)

months=$(($NumPayments - 1)) # bad choice of variable name

#This is the part that calculates the payments.
#for ((x=$months; x > 0; x--))
# do
#   bot=$(echo "scale=9; $interest_rat^$x" | bc)
#   bottom=$(echo "scale=9; $bottom+$bot" | bc)
# done

# This line below replaces the commented out for loop above. Executes the for loop in bc rather than bash. Is more efficient.

 bottom=$(echo -e "r=$interest_rat; b=1.0; for(x=$months; x > 0; x--){c=r ^ x; b=b + c}; b " |bc -w)
 
 payment=$(echo "scale=2; $top/$bottom" | bc)
  
FixedCostsPerInstallment=$(echo "scale=2; $TotalFixedCharges/$NumPayments" | bc)
InstallmentAmount=$(echo "scale=2; $FixedCostsPerInstallment + $payment" | bc)
BalancePayable=$(echo "scale=2; $InstallmentAmount * $NumPayments" | bc)
CostofCredit=$(echo "scale=2;  $BalancePayable - $AmountFinanced" | bc)
InterestCharged=$(echo "scale=2; $CostofCredit - $TotalFixedCharges" | bc)

# This block of code extracts payment interval from number of payments in year. Required for date arithmetic in date command.
unset Dateunits
case "$AnnualPayments" in
	1 ) Dateunits=years;;
	12 ) Dateunits=months;;
	26 ) Dateunits=fortnights;;
	52 ) Dateunits=weeks;;
	*) Dateunits="Not calculated";; # Difficult to calculate final payment date for unusual payment intervals.
esac

if [ "$Dateunits" = "Not calculated" ]
	then
		LastPaymentDate=$Dateunits # We are not going to calculate the final payment date
	else 
		# Adjust the number of payments by minus one as we are calculating the last payment from the first payment 
		# date, not the start of the loan.
		NumPaymentsAdj=$(($NumPayments - 1))
		globbb=`echo -e "$FirstPaymentDate $NumPaymentsAdj $Dateunits\c"` #date seems unable to digest arguments unless in this form.
		LastPaymentDate=`date --date="$globbb" +'%A %d %B %Y'`
fi

Formatted1stPaymentDate=`date  -d $FirstPaymentDate +'%A %d %B %Y'` # Pretty it up for the table

# printf "%'i" formats numbers with comma seperators for thousands etc.
echo -e "What \t Amount\nTotal gross cost (A) \t \$`printf "%'i" $TotalGrossCost` \nTotal deposit (B) \t \$`printf "%'i" $TotalDeposit` \nAmount financed (C) \t \$`printf "%'i" $AmountFinanced` \nNumber of Installments \t $NumPayments \nInterest rate \t $InterestRate% \nInstalment amount \t \$`printf "%'1.2f" $InstallmentAmount`\nInterest charged \t \$`printf "%'1.2f" $InterestCharged` \nCost of credit \t \$`printf "%'1.2f" $CostofCredit` \nBalance payable \t \$`printf "%'1.2f" $BalancePayable` \nFirst payment date \t $Formatted1stPaymentDate \nLast payment date \t $LastPaymentDate"|showtable -t=1