diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..0548357 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..ca9c70c --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..797acea --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/mock-machine-coding-2.iml b/mock-machine-coding-2.iml new file mode 100644 index 0000000..c90834f --- /dev/null +++ b/mock-machine-coding-2.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/out/production/mock-machine-coding-2/com/gaurparas/Driver.class b/out/production/mock-machine-coding-2/com/gaurparas/Driver.class new file mode 100644 index 0000000..c99549a Binary files /dev/null and b/out/production/mock-machine-coding-2/com/gaurparas/Driver.class differ diff --git a/out/production/mock-machine-coding-2/com/gaurparas/EqualExpense.class b/out/production/mock-machine-coding-2/com/gaurparas/EqualExpense.class new file mode 100644 index 0000000..3cce4fe Binary files /dev/null and b/out/production/mock-machine-coding-2/com/gaurparas/EqualExpense.class differ diff --git a/out/production/mock-machine-coding-2/com/gaurparas/EqualSplit.class b/out/production/mock-machine-coding-2/com/gaurparas/EqualSplit.class new file mode 100644 index 0000000..92f3ca7 Binary files /dev/null and b/out/production/mock-machine-coding-2/com/gaurparas/EqualSplit.class differ diff --git a/out/production/mock-machine-coding-2/com/gaurparas/ExactExpense.class b/out/production/mock-machine-coding-2/com/gaurparas/ExactExpense.class new file mode 100644 index 0000000..b622d9c Binary files /dev/null and b/out/production/mock-machine-coding-2/com/gaurparas/ExactExpense.class differ diff --git a/out/production/mock-machine-coding-2/com/gaurparas/ExactSplit.class b/out/production/mock-machine-coding-2/com/gaurparas/ExactSplit.class new file mode 100644 index 0000000..4c4bf29 Binary files /dev/null and b/out/production/mock-machine-coding-2/com/gaurparas/ExactSplit.class differ diff --git a/out/production/mock-machine-coding-2/com/gaurparas/Expense.class b/out/production/mock-machine-coding-2/com/gaurparas/Expense.class new file mode 100644 index 0000000..33312ff Binary files /dev/null and b/out/production/mock-machine-coding-2/com/gaurparas/Expense.class differ diff --git a/out/production/mock-machine-coding-2/com/gaurparas/ExpenseManager.class b/out/production/mock-machine-coding-2/com/gaurparas/ExpenseManager.class new file mode 100644 index 0000000..c707939 Binary files /dev/null and b/out/production/mock-machine-coding-2/com/gaurparas/ExpenseManager.class differ diff --git a/out/production/mock-machine-coding-2/com/gaurparas/ExpenseMetaData.class b/out/production/mock-machine-coding-2/com/gaurparas/ExpenseMetaData.class new file mode 100644 index 0000000..55f760b Binary files /dev/null and b/out/production/mock-machine-coding-2/com/gaurparas/ExpenseMetaData.class differ diff --git a/out/production/mock-machine-coding-2/com/gaurparas/ExpenseService$1.class b/out/production/mock-machine-coding-2/com/gaurparas/ExpenseService$1.class new file mode 100644 index 0000000..222145b Binary files /dev/null and b/out/production/mock-machine-coding-2/com/gaurparas/ExpenseService$1.class differ diff --git a/out/production/mock-machine-coding-2/com/gaurparas/ExpenseService.class b/out/production/mock-machine-coding-2/com/gaurparas/ExpenseService.class new file mode 100644 index 0000000..148eac2 Binary files /dev/null and b/out/production/mock-machine-coding-2/com/gaurparas/ExpenseService.class differ diff --git a/out/production/mock-machine-coding-2/com/gaurparas/ExpenseType.class b/out/production/mock-machine-coding-2/com/gaurparas/ExpenseType.class new file mode 100644 index 0000000..37d3616 Binary files /dev/null and b/out/production/mock-machine-coding-2/com/gaurparas/ExpenseType.class differ diff --git a/out/production/mock-machine-coding-2/com/gaurparas/PercentExpense.class b/out/production/mock-machine-coding-2/com/gaurparas/PercentExpense.class new file mode 100644 index 0000000..6bc40fa Binary files /dev/null and b/out/production/mock-machine-coding-2/com/gaurparas/PercentExpense.class differ diff --git a/out/production/mock-machine-coding-2/com/gaurparas/PercentSplit.class b/out/production/mock-machine-coding-2/com/gaurparas/PercentSplit.class new file mode 100644 index 0000000..b55df7f Binary files /dev/null and b/out/production/mock-machine-coding-2/com/gaurparas/PercentSplit.class differ diff --git a/out/production/mock-machine-coding-2/com/gaurparas/Split.class b/out/production/mock-machine-coding-2/com/gaurparas/Split.class new file mode 100644 index 0000000..17208ce Binary files /dev/null and b/out/production/mock-machine-coding-2/com/gaurparas/Split.class differ diff --git a/out/production/mock-machine-coding-2/com/gaurparas/User.class b/out/production/mock-machine-coding-2/com/gaurparas/User.class new file mode 100644 index 0000000..c2b8d70 Binary files /dev/null and b/out/production/mock-machine-coding-2/com/gaurparas/User.class differ diff --git a/src/com/gaurparas/Driver.java b/src/com/gaurparas/Driver.java new file mode 100644 index 0000000..94a9721 --- /dev/null +++ b/src/com/gaurparas/Driver.java @@ -0,0 +1,61 @@ +package com.gaurparas; + +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +public class Driver { + public static void main(String... args){ + ExpenseManager expenseManager = new ExpenseManager(); + + expenseManager.addUser(new User("u1","User1","paras@gmail.com","+91-00000")); + expenseManager.addUser(new User("u2","User2","pushpendra@gmail.com","+91-00001")); + expenseManager.addUser(new User("u3","User3","abhinav@gmail.com","+91-00002")); + expenseManager.addUser(new User("u4","User4","jancy@gmail.com","+91-00003")); + + Scanner scanner = new Scanner(System.in); + while (true) { + String command = scanner.nextLine(); + String[] commands = command.split(" "); + String commandType = commands[0]; + + switch (commandType){ + case "SHOW": + if (commands.length == 1) { + expenseManager.showBalances(); + } else { + expenseManager.showBalance(commands[1]); + } + break; + case "EXPENSE": + String paidBy = commands[1]; + Double amount = Double.parseDouble(commands[2]); + int noOfUsers = Integer.parseInt(commands[3]); + String expenseType = commands[4 + noOfUsers]; + List splits = new ArrayList<>(); + switch (expenseType){ + case "EXACT": + for(int i=0;i splits, ExpenseMetaData metaData) { + super(amount, paidBy, splits, metaData); + } + + @Override + public boolean validate() { + List splits = getSplits(); + + for(Split split:splits) { + if (!(split instanceof EqualSplit)){ + return false; + } + } + + return true; + } +} diff --git a/src/com/gaurparas/EqualSplit.java b/src/com/gaurparas/EqualSplit.java new file mode 100644 index 0000000..4564b27 --- /dev/null +++ b/src/com/gaurparas/EqualSplit.java @@ -0,0 +1,8 @@ +package com.gaurparas; + +public class EqualSplit extends Split { + + public EqualSplit(User user) { + super(user); + } +} diff --git a/src/com/gaurparas/ExactExpense.java b/src/com/gaurparas/ExactExpense.java new file mode 100644 index 0000000..fad806f --- /dev/null +++ b/src/com/gaurparas/ExactExpense.java @@ -0,0 +1,25 @@ +package com.gaurparas; + +import java.util.List; + +public class ExactExpense extends Expense { + + public ExactExpense(double amount, User paidBy, List splits, ExpenseMetaData metaData) { + super(amount, paidBy, splits, metaData); + } + + @Override + public boolean validate() { + List splits = getSplits(); + double splitsAmount = 0; + + for(Split split:splits) { + if (!(split instanceof EqualSplit)){ + return false; + } + splitsAmount+=split.getAmount(); + } + + return splitsAmount == getAmount(); + } +} diff --git a/src/com/gaurparas/ExactSplit.java b/src/com/gaurparas/ExactSplit.java new file mode 100644 index 0000000..8bb1689 --- /dev/null +++ b/src/com/gaurparas/ExactSplit.java @@ -0,0 +1,9 @@ +package com.gaurparas; + +public class ExactSplit extends Split { + + public ExactSplit(User user, double amount) { + super(user); + this.amount = amount; + } +} diff --git a/src/com/gaurparas/Expense.java b/src/com/gaurparas/Expense.java new file mode 100644 index 0000000..bad742a --- /dev/null +++ b/src/com/gaurparas/Expense.java @@ -0,0 +1,60 @@ +package com.gaurparas; + +import java.util.List; + +public abstract class Expense { + private String id; + private List splits; + private User paidBy; + private double amount; + private ExpenseMetaData metaData; + + public Expense(double amount, User paidBy, List splits, ExpenseMetaData metaData) { + this.amount = amount; + this.paidBy = paidBy; + this.splits = splits; + this.metaData = metaData; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public double getAmount() { + return amount; + } + + public void setAmount(double amount) { + this.amount = amount; + } + + public User getPaidBy() { + return paidBy; + } + + public void setPaidBy(User paidBy) { + this.paidBy = paidBy; + } + + public List getSplits() { + return splits; + } + + public void setSplits(List splits) { + this.splits = splits; + } + + public ExpenseMetaData getMetadata() { + return metaData; + } + + public void setMetadata(ExpenseMetaData metaData) { + this.metaData = metaData; + } + + public abstract boolean validate(); +} diff --git a/src/com/gaurparas/ExpenseManager.java b/src/com/gaurparas/ExpenseManager.java new file mode 100644 index 0000000..dbcaed6 --- /dev/null +++ b/src/com/gaurparas/ExpenseManager.java @@ -0,0 +1,83 @@ +package com.gaurparas; + +import com.sun.deploy.cache.BaseLocalApplicationProperties; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ExpenseManager { + + List expenses; + Map userMap; + Map> balanceSheet; + + public ExpenseManager() { + expenses = new ArrayList(); + userMap = new HashMap(); + balanceSheet = new HashMap>(); + } + + public void addUser(User user) { + userMap.put(user.getId(), user); + balanceSheet.put(user.getId(), new HashMap()); + } + + public void showBalances() { + boolean isEmpty = true; + for(Map.Entry> allBalance : balanceSheet.entrySet()) { + for (Map.Entry userBalance : allBalance.getValue().entrySet()) { + if (userBalance.getValue() > 0) { + isEmpty = false; + printBalance(allBalance.getKey(), userBalance.getKey(), userBalance.getValue()); + } + } + } + if (isEmpty) { + System.out.println("No balances"); + } + } + + public void showBalance(String userId) { + boolean isEmpty = true; + for(Map.Entry userBalance : balanceSheet.get(userId).entrySet()) { + if(userBalance.getValue() != 0){ + isEmpty = false; + printBalance(userId, userBalance.getKey(), userBalance.getValue()); + } + } + if (isEmpty) { + System.out.println("No balances"); + } + } + + private void printBalance(String user1, String user2, Double amount) { + String user1Name = userMap.get(user1).getName(); + String user2Name = userMap.get(user2).getName(); + if (amount < 0) { + System.out.println(user1Name + " owes " + user2Name + ": " + Math.abs(amount)); + } else if (amount > 0) { + System.out.println(user2Name + " owes " + user1Name + ": " + Math.abs(amount)); + } + } + + public void addExpense(ExpenseType expenseType, Double amount, String paidBy, + List splits, ExpenseMetaData metaData) { + Expense expense = ExpenseService.createExpense(expenseType, amount, userMap.get(paidBy), + splits, metaData); + expenses.add(expense); + + Map userBalances = balanceSheet.get(paidBy); + for(Split split:splits) { + String oweUser = split.getUser().getId(); + double prevAmount = userBalances.getOrDefault(oweUser,0.0); + double currentAmount = split.getAmount(); + userBalances.put(oweUser,prevAmount + currentAmount); + + Map OweUserBalances = balanceSheet.get(oweUser); + prevAmount = OweUserBalances.getOrDefault(paidBy,0.0); + OweUserBalances.put(paidBy,prevAmount - currentAmount); + } + } +} diff --git a/src/com/gaurparas/ExpenseMetaData.java b/src/com/gaurparas/ExpenseMetaData.java new file mode 100644 index 0000000..61dc5ba --- /dev/null +++ b/src/com/gaurparas/ExpenseMetaData.java @@ -0,0 +1,37 @@ +package com.gaurparas; + +public class ExpenseMetaData { + private String name; + private String imgUrl; + private String notes; + + public ExpenseMetaData(String name, String imgUrl, String notes) { + this.name = name; + this.imgUrl = imgUrl; + this.notes = notes; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public String getNotes() { + return notes; + } + + public void setNotes(String notes) { + this.notes = notes; + } +} diff --git a/src/com/gaurparas/ExpenseService.java b/src/com/gaurparas/ExpenseService.java new file mode 100644 index 0000000..32738eb --- /dev/null +++ b/src/com/gaurparas/ExpenseService.java @@ -0,0 +1,29 @@ +package com.gaurparas; + +import java.util.List; + +public class ExpenseService { + public static Expense createExpense(ExpenseType expenseType, double amount, User paidBy, + List splits, ExpenseMetaData metaData) { + switch (expenseType) { + case EXACT: + return new ExactExpense(amount, paidBy, splits, metaData); + case EQUAL: + int totalSplits = splits.size(); + double splitAmount = ((double) Math.round(amount*100/totalSplits))/100.0; + for(Split split:splits){ + split.setAmount(splitAmount); + } + splits.get(0).setAmount(splitAmount + (amount-splitAmount*totalSplits)); + return new EqualExpense(amount, paidBy, splits, metaData); + case PERCENT: + for(Split split:splits){ + double percentSplit = ((PercentSplit)split).getPercent(); + split.setAmount(amount*percentSplit/100); + } + return new PercentExpense(amount, paidBy, splits, metaData); + default: + return null; + } + } +} diff --git a/src/com/gaurparas/ExpenseType.java b/src/com/gaurparas/ExpenseType.java new file mode 100644 index 0000000..6eb856c --- /dev/null +++ b/src/com/gaurparas/ExpenseType.java @@ -0,0 +1,7 @@ +package com.gaurparas; + +public enum ExpenseType { + EQUAL, + EXACT, + PERCENT +} diff --git a/src/com/gaurparas/PercentExpense.java b/src/com/gaurparas/PercentExpense.java new file mode 100644 index 0000000..a139d71 --- /dev/null +++ b/src/com/gaurparas/PercentExpense.java @@ -0,0 +1,27 @@ +package com.gaurparas; + +import java.util.List; + +public class PercentExpense extends Expense{ + + + public PercentExpense(double amount, User paidBy, List splits, ExpenseMetaData metaData) { + super(amount, paidBy, splits, metaData); + } + + @Override + public boolean validate() { + List splits = getSplits(); + double splitsPercent = 0; + double total = 100; + + for(Split split:splits) { + if (!(split instanceof PercentSplit)){ + return false; + } + splitsPercent+=((PercentSplit) split).getPercent(); + } + + return splitsPercent == total; + } +} diff --git a/src/com/gaurparas/PercentSplit.java b/src/com/gaurparas/PercentSplit.java new file mode 100644 index 0000000..c2dde93 --- /dev/null +++ b/src/com/gaurparas/PercentSplit.java @@ -0,0 +1,18 @@ +package com.gaurparas; + +public class PercentSplit extends Split { + double percent; + + public PercentSplit(User user, double percent) { + super(user); + this.percent = percent; + } + + public double getPercent() { + return percent; + } + + public void setPercent(double percent) { + this.percent = percent; + } +} diff --git a/src/com/gaurparas/Split.java b/src/com/gaurparas/Split.java new file mode 100644 index 0000000..c82b81a --- /dev/null +++ b/src/com/gaurparas/Split.java @@ -0,0 +1,26 @@ +package com.gaurparas; + +public abstract class Split { + private User user; + double amount; + + public Split(User user) { + this.user = user; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public double getAmount() { + return amount; + } + + public void setAmount(double amount) { + this.amount = amount; + } +} diff --git a/src/com/gaurparas/User.java b/src/com/gaurparas/User.java new file mode 100644 index 0000000..7e612b4 --- /dev/null +++ b/src/com/gaurparas/User.java @@ -0,0 +1,47 @@ +package com.gaurparas; + +public class User { + private String id; + private String name; + private String email; + private String phone; + + public User(String id, String name, String email, String phone) { + this.id = id; + this.name = name; + this.email = email; + this.phone = phone; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } +}