Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial changes by Sudhanshu Garg. #94

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 88 additions & 58 deletions src/main/java/com/abc/Account.java
Original file line number Diff line number Diff line change
@@ -1,73 +1,103 @@
package com.abc;

import static java.lang.Math.abs;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;

public class Account {

public static final int CHECKING = 0;
public static final int SAVINGS = 1;
public static final int MAXI_SAVINGS = 2;

private final int accountType;
public List<Transaction> transactions;
public abstract class Account {
protected static final double DEFAULT_RATE = 0.001;
protected static final int DAYS_IN_YEAR = 365;

private List<Transaction> transactions = Collections.synchronizedList( new ArrayList<Transaction>() );

public Account(int accountType) {
this.accountType = accountType;
this.transactions = new ArrayList<Transaction>();
}

public void deposit(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("amount must be greater than zero");
} else {
transactions.add(new Transaction(amount));
}
}
public void deposit(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("amount must be greater than zero");
} else {
transactions.add(new Transaction(amount));
}
}

public void withdraw(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("amount must be greater than zero");
} else {
transactions.add(new Transaction(-amount));
}
}
public void withdraw(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("amount must be greater than zero");
}
synchronized(this) {
if (amount > sumTransactions()) {
throw new IllegalArgumentException("insufficient funds");
} else {
transactions.add(new Transaction(-amount));
}
}
}

public synchronized double interestEarned() {
double principal = 0.0;
double interest = 0.0;
Instant latestWidtdrawalOn = Instant.MIN;
ListIterator<Transaction> i = transactions.listIterator();
while(i.hasNext()) {
Transaction t = i.next();
Instant interestStartingOn = t.getTransactionDate().toInstant().truncatedTo(ChronoUnit.DAYS);
principal += t.getAmount();

if(t.getAmount() < 0) { latestWidtdrawalOn = interestStartingOn; }

Instant interstUntil = DateProvider.getInstance().now().toInstant().truncatedTo(ChronoUnit.DAYS); //default: interest until today

//continue over all transaction on the same day
while(i.hasNext()) {
Transaction t1 = i.next();
Instant d1 = t1.getTransactionDate().toInstant().truncatedTo(ChronoUnit.DAYS);
if(d1.isAfter(interestStartingOn)) {
interstUntil = d1;
i.previous();
break;
} else {
if(t1.getAmount() < 0) { latestWidtdrawalOn = d1; }
principal += t1.getAmount();
}
}

interest += interestEarnedInPeriod(principal, interestStartingOn, interstUntil, latestWidtdrawalOn);
}
return interest;
}

public double interestEarnedInPeriod(double onAmount, Instant start, Instant end, Instant latestWidtdrawalOn) {
return interestEarnedIn(ChronoUnit.DAYS.between(start, end), onAmount);
}

public abstract double interestEarnedIn(long days, double onAmount);

public synchronized String statementForAccount() {
String s = statementHeading() + "\n";

public double interestEarned() {
double amount = sumTransactions();
switch(accountType){
case SAVINGS:
if (amount <= 1000)
return amount * 0.001;
else
return 1 + (amount-1000) * 0.002;
// case SUPER_SAVINGS:
// if (amount <= 4000)
// return 20;
case MAXI_SAVINGS:
if (amount <= 1000)
return amount * 0.02;
if (amount <= 2000)
return 20 + (amount-1000) * 0.05;
return 70 + (amount-2000) * 0.1;
default:
return amount * 0.001;
//Now total up all the transactions
double total = 0.0;
for (Transaction t : transactions) {
s += " " + (t.getAmount() < 0 ? "withdrawal" : "deposit") + " " + toDollars(t.getAmount()) + "\n";
total += t.getAmount();
}
s += "Total " + toDollars(total);
return s;
}

public double sumTransactions() {
return checkIfTransactionsExist(true);
private String toDollars(double d){
return String.format("$%,.2f", abs(d));
}

private double checkIfTransactionsExist(boolean checkAll) {
double amount = 0.0;
for (Transaction t: transactions)
amount += t.amount;
return amount;
}

public int getAccountType() {
return accountType;
}
public synchronized double sumTransactions() {
double amount = 0.0;
for (Transaction t : transactions)
amount += t.getAmount();
return amount;
}

public abstract String statementHeading();
}
11 changes: 11 additions & 0 deletions src/main/java/com/abc/AccountChecking.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.abc;

public class AccountChecking extends Account {
public double interestEarnedIn(long days, double onAmount) {
return onAmount * days / DAYS_IN_YEAR * DEFAULT_RATE;
}

public String statementHeading() {
return "Checking Account";
}
}
21 changes: 21 additions & 0 deletions src/main/java/com/abc/AccountMaxiSavings.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.abc;

public class AccountMaxiSavings extends Account {
private static final double RATE1 = 0.02;
private static final double RATE2 = 0.05;
private static final double RATE3 = 0.10;

public double interestEarnedIn(long days, double onAmount) {
double daysFrac = (double) days / DAYS_IN_YEAR;
if (onAmount <= 1000)
return (onAmount * daysFrac) * RATE1;
else if (onAmount <= 2000)
return (1000.0d * daysFrac) * RATE1 + ((onAmount - 1000) * daysFrac) * RATE2;
else
return (1000.0d * daysFrac) * RATE1 + (1000.0d * daysFrac) * RATE2 + ((onAmount - 2000) * daysFrac) * RATE3;
}

public String statementHeading() {
return "Maxi Savings Account";
}
}
17 changes: 17 additions & 0 deletions src/main/java/com/abc/AccountSavings.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.abc;

public class AccountSavings extends Account {
private static final double RATE = 0.002;

public double interestEarnedIn(long days, double onAmount) {
double daysFrac = (double) days / DAYS_IN_YEAR;
if (onAmount <= 1000)
return (onAmount * daysFrac) * DEFAULT_RATE;
else
return (1000.0d * daysFrac) * DEFAULT_RATE + ((onAmount - 1000) * daysFrac) * RATE;
}

public String statementHeading() {
return "Savings Account";
}
}
43 changes: 43 additions & 0 deletions src/main/java/com/abc/AccountSuperSavings.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.abc;

import java.time.Instant;
import java.time.temporal.ChronoUnit;

public class AccountSuperSavings extends Account {
private static final double RATE = 0.05;
private static final int noWithdrawalPeriod = 10; //No withdrawals means extra savings

public double interestEarnedIn(long days, double onAmount) {
return onAmount * days / DAYS_IN_YEAR * DEFAULT_RATE;
}

public double interestEarnedIn(long days, double onAmount, boolean didWithdrawInBlackoutPeriod) {
return onAmount * days / DAYS_IN_YEAR * (didWithdrawInBlackoutPeriod ? DEFAULT_RATE : RATE);
}

public String statementHeading() {
return "Super Savings Account";
}

public double interestEarnedInPeriod(double onAmount, Instant start, Instant end, Instant latestWidtdrawalOn) {
double interest = 0.0;
Instant widthdrawalPlus10 = latestWidtdrawalOn.plus(noWithdrawalPeriod, ChronoUnit.DAYS);
long daysWorse = 0; //inside the withdrawal window
long daysBetter = 0; //outside of the withdrawal window
if(widthdrawalPlus10.isBefore(start)) {
daysBetter = ChronoUnit.DAYS.between(start, end);
} else if (widthdrawalPlus10.isAfter(end)) {
daysWorse = ChronoUnit.DAYS.between(start, end);
} else {
daysWorse = ChronoUnit.DAYS.between(start, widthdrawalPlus10);
daysBetter = ChronoUnit.DAYS.between(widthdrawalPlus10, end);
}
if(daysWorse > 0) {
interest += interestEarnedIn(daysWorse, onAmount, true);
}
if(daysBetter > 0) {
interest += interestEarnedIn(daysBetter, onAmount, false);
}
return interest;
}
}
19 changes: 5 additions & 14 deletions src/main/java/com/abc/Bank.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
package com.abc;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Bank {
private List<Customer> customers;

public Bank() {
customers = new ArrayList<Customer>();
customers = Collections.synchronizedList( new ArrayList<Customer>() );
}

public void addCustomer(Customer customer) {
customers.add(customer);
}

public String customerSummary() {
public synchronized String customerSummary() {
String summary = "Customer Summary";
for (Customer c : customers)
summary += "\n - " + c.getName() + " (" + format(c.getNumberOfAccounts(), "account") + ")";
Expand All @@ -27,20 +28,10 @@ private String format(int number, String word) {
return number + " " + (number == 1 ? word : word + "s");
}

public double totalInterestPaid() {
public synchronized double totalInterestPaid() {
double total = 0;
for(Customer c: customers)
for(Customer c : customers)
total += c.totalInterestEarned();
return total;
}

public String getFirstCustomer() {
try {
customers = null;
return customers.get(0).getName();
} catch (Exception e){
e.printStackTrace();
return "Error";
}
}
}
56 changes: 19 additions & 37 deletions src/main/java/com/abc/Customer.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package com.abc;

import static java.lang.Math.abs;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static java.lang.Math.abs;

public class Customer {
private String name;
private List<Account> accounts;

public Customer(String name) {
this.name = name;
this.accounts = new ArrayList<Account>();
this.accounts = Collections.synchronizedList(new ArrayList<Account>());
}

public String getName() {
Expand All @@ -22,57 +23,38 @@ public Customer openAccount(Account account) {
accounts.add(account);
return this;
}

public void transfer(double amount, Account from, Account to) {
if(accounts.contains(from) && accounts.contains(to) && from != to) {
synchronized(this) {
from.withdraw(amount);
to.deposit(amount);
}
} else {
throw new IllegalArgumentException("Both accounts must belong to the same customer, and cannot be same.");
}
}

public int getNumberOfAccounts() {
return accounts.size();
}

public double totalInterestEarned() {
public synchronized double totalInterestEarned() {
double total = 0;
for (Account a : accounts)
total += a.interestEarned();
return total;
}

public String getStatement() {
public synchronized String getStatement() {
String statement = null;
statement = "Statement for " + name + "\n";
double total = 0.0;
for (Account a : accounts) {
statement += "\n" + statementForAccount(a) + "\n";
statement += "\n" + a.statementForAccount() + "\n";
total += a.sumTransactions();
}
statement += "\nTotal In All Accounts " + toDollars(total);
statement += "\nTotal In All Accounts " + String.format("$%,.2f", abs(total));
return statement;
}

private String statementForAccount(Account a) {
String s = "";

//Translate to pretty account type
switch(a.getAccountType()){
case Account.CHECKING:
s += "Checking Account\n";
break;
case Account.SAVINGS:
s += "Savings Account\n";
break;
case Account.MAXI_SAVINGS:
s += "Maxi Savings Account\n";
break;
}

//Now total up all the transactions
double total = 0.0;
for (Transaction t : a.transactions) {
s += " " + (t.amount < 0 ? "withdrawal" : "deposit") + " " + toDollars(t.amount) + "\n";
total += t.amount;
}
s += "Total " + toDollars(total);
return s;
}

private String toDollars(double d){
return String.format("$%,.2f", abs(d));
}
}
Loading