Skip to content
This repository was archived by the owner on May 18, 2022. It is now read-only.
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.splitwise.machine.coding;

import java.util.Collection;

public class CollectionUtils<E> {

public E get(Collection<E> collection, E object) {
for (E e : collection) {
if (e.hashCode() == object.hashCode() && e.equals(object)) {
return e;
}
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.splitwise.machine.coding;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Driver {

static LedgerService ledgerService = new LedgerService();

public static void main(String[] args) {

Scanner sc = new Scanner(System.in);

while (sc.hasNext()) {
String line = sc.nextLine();
String[] inputs = line.split(" ");
String command = inputs[0];
if (command.equals("EXPENSE")) {
String payerId = inputs[1];
double amount = Double.valueOf(inputs[2]);
int users = Integer.valueOf(inputs[3]);
List<String> splitTo = new ArrayList<>(users);
int x = 0;
for (; x < users; x++) {
splitTo.add(inputs[x + 4]);
}
String expenseType = inputs[x + 4];
List<Integer> scales = new ArrayList<>();
if (!expenseType.equals("EQUAL")) {
for (int y = 0; y < users; y++) {
scales.add(Integer.valueOf((inputs[x + 4 + 1 + y])));
}
}

createUserBase();
ledgerService.splitExpenses(expenseType, payerId, amount, splitTo, scales);

}
if (command.equals("SHOW")) {
inputs = line.split(" ");
if (inputs.length > 1) {
ledgerService.getUserExpensesSheet(inputs[1]);
} else {
ledgerService.getAllUserExppenses();
}
}
}
}

private static void createUserBase() {
// Creating dummy users for now , it can be created using some file or
// some other ways.
User user1 = new User("u1", "User1", "User1@gmail.com", "123");
User user2 = new User("u2", "User2", "User2@gmail.com", "1234");
User user3 = new User("u3", "User3", "User3@gmail.com", "1235");
User user4 = new User("u4", "User4", "User4@gmail.com", "123455");
UserBase.addUser(user1);
UserBase.addUser(user2);
UserBase.addUser(user3);
UserBase.addUser(user4);

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.splitwise.machine.coding;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

public class EqualExpense implements Expense {

@Override
public List<UserExpenseProfile> splitExpense(double amount, List<String> splitTo, List<Integer> scales) {
List<UserExpenseProfile> userExpenseProfiles = new ArrayList<>();

DecimalFormat df = new DecimalFormat("#.##");
double equalAmount = Double.valueOf(df.format(amount/splitTo.size()));

for(int x=0; x< splitTo.size(); x++) {
UserExpenseProfile profile = new UserExpenseProfile(splitTo.get(x), equalAmount);
userExpenseProfiles.add(profile);
}
return userExpenseProfiles;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.splitwise.machine.coding;

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

public class ExactExpense implements Expense {

@Override
public List<UserExpenseProfile> splitExpense(double amount, List<String> splitTo, List<Integer> scales) {
List<UserExpenseProfile> userExpenseProfiles = new ArrayList<>();

for(int x=0; x< splitTo.size(); x++) {
UserExpenseProfile profile = new UserExpenseProfile(splitTo.get(x), scales.get(x));
userExpenseProfiles.add(profile);
}
return userExpenseProfiles;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.splitwise.machine.coding;

import java.util.List;

public interface Expense {

List<UserExpenseProfile> splitExpense(double amount, List<String> splitTo, List<Integer> scales);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.splitwise.machine.coding;

public class ExpenseFactory {

public static Expense getInstance(ExpenseType expenseType) {

switch (expenseType) {
case EQUAL:
return new EqualExpense();
case EXACT:
return new ExactExpense();
case PERCENT:
return new PercentExpense();

default:
break;
}
return null;
}
}

enum ExpenseType {
EQUAL,EXACT,PERCENT
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.splitwise.machine.coding;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
* @author Hakim.s
*
*/
public class LedgerBook {

private Map<String, List<UserExpenseProfile>> userExpensesProfile;

public LedgerBook() {

this.userExpensesProfile = new HashMap<>();
}

public void addExpenseEntry(String payer, UserExpenseProfile paidTo) {

UserExpenseProfile payerProfile = new UserExpenseProfile(payer, (paidTo.getExpenses() * -1));

updateExpense(payer, paidTo);

// update reverse association.
updateExpense(paidTo.getUserId(), payerProfile);

}

private void updateExpense(String payer, UserExpenseProfile paidTo) {

if (getUserExpensesProfile().containsKey(payer)) {
List<UserExpenseProfile> profiles = getUserExpensesProfile().get(payer);

if (profiles.contains(paidTo)) {
UserExpenseProfile existingProfile = new CollectionUtils<UserExpenseProfile>().get(profiles, paidTo);
existingProfile.setExpenses(existingProfile.getExpenses() + paidTo.getExpenses());
// System.out.println(existingProfile.getExpenses());
} else {
profiles.add(paidTo);
}

} else {
// Add new entry.
List<UserExpenseProfile> userExpenseProfiles = new ArrayList<>();
userExpenseProfiles.add(paidTo);
getUserExpensesProfile().put(payer, userExpenseProfiles);
}
}

public List<UserExpenseProfile> getExpensesForUser(String userId) {
return getUserExpensesProfile().get(userId);
}

public Map<String, List<UserExpenseProfile>> getAllLedgerExpenses() {

Map<String, List<UserExpenseProfile>> filteredUserExpenses = new HashMap<>();
Set<Entry<String, List<UserExpenseProfile>>> entrySet = userExpensesProfile.entrySet();
for (Entry<String, List<UserExpenseProfile>> entry : entrySet) {
List<UserExpenseProfile> value = entry.getValue();
List<UserExpenseProfile> filteredProfiles = new ArrayList<>();
for (UserExpenseProfile userExpenseProfile : value) {
if (userExpenseProfile.getExpenses() < 0) {
filteredProfiles.add(userExpenseProfile);
}
}
if(!filteredProfiles.isEmpty())
filteredUserExpenses.put(entry.getKey(), filteredProfiles);
}
return filteredUserExpenses;

}

private Map<String, List<UserExpenseProfile>> getUserExpensesProfile() {
return userExpensesProfile;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.splitwise.machine.coding;

import java.util.List;
import java.util.Map;

public class LedgerService {

LedgerBook ledgerBook = new LedgerBook();

public void splitExpenses(String expenseType, String payer, double amount, List<String> splitTo,
List<Integer> scales) {
List<UserExpenseProfile> userExpenseProfiles = null;

// Calling factory which will create a Expense Type object, we can take
// any type in future.
Expense expenseTypeInstance = ExpenseFactory.getInstance(ExpenseType.valueOf(expenseType));
userExpenseProfiles = expenseTypeInstance.splitExpense(amount, splitTo, scales);

for (UserExpenseProfile userExpenseProfile : userExpenseProfiles) {
if (!payer.equals(userExpenseProfile.getUserId())) {
ledgerBook.addExpenseEntry(payer, userExpenseProfile);
}
}

}

public void getUserExpensesSheet(String userId) {
List<UserExpenseProfile> userExpensesSheet = ledgerBook.getExpensesForUser(userId);
PrintReport.printUserBalances(userId, userExpensesSheet);
}

public void getAllUserExppenses() {
Map<String, List<UserExpenseProfile>> userExpensesSheet = ledgerBook.getAllLedgerExpenses();

PrintReport.printAllBalances(userExpensesSheet);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.splitwise.machine.coding;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

public class PercentExpense implements Expense {

@Override
public List<UserExpenseProfile> splitExpense(double amount, List<String> splitTo, List<Integer> scales) {
List<UserExpenseProfile> userExpenseProfiles = new ArrayList<>();

for (int x = 0; x < splitTo.size(); x++) {
DecimalFormat df = new DecimalFormat("#.##");
double percentAmount = Double.valueOf(df.format((amount * scales.get(x)) / 100));

UserExpenseProfile profile = new UserExpenseProfile(splitTo.get(x), percentAmount);
userExpenseProfiles.add(profile);
}
return userExpenseProfiles;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.splitwise.machine.coding;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
* @author Hakim.s
*
* Optional requirement 3 can be done using this class. A way to show
* the passbook for a user. [The entries should show all the
* transactions a user was part of. You can print in any format you
* like]
*
*/
public class PrintReport {

public static void printUserBalances(String userId, List<UserExpenseProfile> userExpensesSheet) {
if (userExpensesSheet == null || userExpensesSheet.isEmpty()) {
System.out.println("No balances");
return;
}
for (UserExpenseProfile userExpenseProfile : userExpensesSheet) {
if (userExpenseProfile.getExpenses() < 0) {
printMessage(userId, userExpenseProfile.getUserId(), userExpenseProfile.getExpenses());
} else if (userExpenseProfile.getExpenses() > 0) {
printMessage(userExpenseProfile.getUserId(), userId, userExpenseProfile.getExpenses());

}
}

}

public static void printAllBalances(Map<String, List<UserExpenseProfile>> userExpensesMap) {
if (userExpensesMap == null || userExpensesMap.isEmpty()) {
System.out.println("No balances");
return;
}
Set<Entry<String, List<UserExpenseProfile>>> entries = userExpensesMap.entrySet();
for (Entry<String, List<UserExpenseProfile>> entry : entries) {
printUserBalances(entry.getKey(), entry.getValue());
}

}

private static void printMessage(String borrower, String payer, double expenses) {
System.out.println(UserBase.getUser(borrower).getName() + " owes " + UserBase.getUser(payer).getName() + ": "
+ Math.abs(expenses));
}

}
Loading