diff --git a/README.md b/README.md
index 11da620..fb76197 100755
--- a/README.md
+++ b/README.md
@@ -1,3 +1,43 @@
+# **High Level Design for SplitWise**
+## Functional Requirements
+~ Users Can be sign up/ sign in to your system
+~ Users can add thier contacts in the system by email or phone
+~ Users can add Expense in the System with multiple contacts
+~ Users can create groups and can add group expense with the group members
+~ System has to show balance report of all users
+~ System can show balance report of particular User
+~ System can show balance report of all and particular group
+
+## Non Functional Requirements
+~The system should be highly available.Because if the service is down , no user will be able to access it.
+
+## Extended Requirements
+~System can simplyfy debts
+~System can show passbook to user.The entries should show all the transactions a user was part of
+
+## Capacity Estimation
+Read will be more than writes in this system.Lets assume if each user has 20 contacts . So read vs write ratio will be 20:1.
+## Traffic estimates
+Lets assume we have 20M new users per month with 20:1 read and write then we can expect 20*20M =>400M read
+#### Queries per Second (QPS) will be 20M / (30 days * 24 hours * 3600 sec) ~= 7.71 write/sec
+#### Consedering 20:1 read to write request 20 * 7.71 ~= 154.2 read/sec
+
+## Storage Estimates
+Lets assume we are saving the expense over the year of 5 years then 20M write request every month, total number of obects we
+expect to store will be : 20M * 5years * 30 months ~= 3Billion
+if each object stored take 500 Byte . Total storage we need is ~= 3B * 500 ~= 1.5TB
+
+## BandWidth estimates
+For Write Request
+Since there are 7.7 write request every sec , so total incoming data for our service will be : 7.7 * 500Bytes =~ 3.75 Kb/sec
+For Read Request
+Since there are 154.2 read request every sec , so total outgoing data for our service will be : 154.2 * 500Bytes =~ 75.29 Kb/sec
+
+## Basic System Design
+
+
+
+
# mock-machine-coding-2
Welcome to the 2nd Mock Machine Coding Round by [workat.tech](http://workat.tech).
diff --git a/SplitWise_low_level_uml.png b/SplitWise_low_level_uml.png
new file mode 100644
index 0000000..66b1646
Binary files /dev/null and b/SplitWise_low_level_uml.png differ
diff --git a/Splitwise.uml b/Splitwise.uml
new file mode 100644
index 0000000..8c72544
--- /dev/null
+++ b/Splitwise.uml
@@ -0,0 +1,234 @@
+
+
+ JAVA
+ com.splitwise.driver
+
+ com.splitwise.model.User
+ com.splitwise.splitStrategy.impl.SplitByExact
+ com.splitwise.splitStrategy.impl.SplitByEqual
+ com.splitwise.model.UserRegistry
+ com.splitwise.model.ExpenseTransactionInfo
+ com.splitwise.transactionFactory.ExpenseTransaction
+ com.splitwise.process.TransactionProcesser
+ com.splitwise.transactionFactory.BalanceTransaction
+ com.splitwise.transactionFactory.Transaction
+ com.splitwise.io.InputTxtReader
+ com.splitwise.driver.SplitwiseDriver
+ com.splitwise.model.Expense
+ com.splitwise.splitStrategy.impl.SplitByPercent
+ com.splitwise.splitStrategy.SplitStartegy
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Fields
+ Methods
+ Properties
+
+ All
+ private
+
+
diff --git a/input.txt b/input.txt
new file mode 100644
index 0000000..30eb7da
--- /dev/null
+++ b/input.txt
@@ -0,0 +1,8 @@
+EXPENSE u1 1000 4 u1 u2 u3 u4 EQUAL
+SHOW u4
+SHOW u1
+EXPENSE u1 1250 2 u2 u3 EXACT 370 880
+SHOW
+EXPENSE u4 1200 4 u1 u2 u3 u4 PERCENT 40 20 20 20
+SHOW u1
+SHOW
\ No newline at end of file
diff --git a/src/main/java/com/splitwise/driver/SplitwiseDriver.java b/src/main/java/com/splitwise/driver/SplitwiseDriver.java
new file mode 100644
index 0000000..dec3225
--- /dev/null
+++ b/src/main/java/com/splitwise/driver/SplitwiseDriver.java
@@ -0,0 +1,34 @@
+package com.splitwise.driver;
+
+
+import com.splitwise.io.InputTxtReader;
+import com.splitwise.model.User;
+import com.splitwise.model.UserRegistry;
+
+public class SplitwiseDriver{
+ private static UserRegistry userRegistry;
+
+ public static UserRegistry getUserRegistry(){
+ return userRegistry;
+ }
+ public static void main(String[] args) {
+ User u1 = new User("u1","88888888881","u1@abc.com");
+ User u2 = new User("u2","88888888882","u3@abc.com");
+ User u3 = new User("u3","88888888883","u2@abc.com");
+ User u4 = new User("u4","88888888884","u4@abc.com");
+ User u5 = new User("u5","88888888885","u5@abc.com");
+
+
+ userRegistry = new UserRegistry();
+ userRegistry.getUserRegistry().add(u1);
+ userRegistry.getUserRegistry().add(u2);
+ userRegistry.getUserRegistry().add(u3);
+ userRegistry.getUserRegistry().add(u4);
+ userRegistry.getUserRegistry().add(u5);
+
+ InputTxtReader reader = new InputTxtReader();
+ reader.readInputTxtFile("input.txt");
+
+
+ }
+ }
\ No newline at end of file
diff --git a/src/main/java/com/splitwise/io/InputTxtReader.java b/src/main/java/com/splitwise/io/InputTxtReader.java
new file mode 100644
index 0000000..4a21be5
--- /dev/null
+++ b/src/main/java/com/splitwise/io/InputTxtReader.java
@@ -0,0 +1,32 @@
+package com.splitwise.io;
+
+
+import com.splitwise.process.TransactionProcesser;
+
+import java.io.*;
+
+public class InputTxtReader {
+ TransactionProcesser processor;
+ public InputTxtReader(){
+ processor = new TransactionProcesser();
+ }
+ public void readInputTxtFile(String fileName) {
+ if(fileName==null && fileName.isEmpty()){
+ System.err.println("FileName is empty or Null . Aborting!!!");
+ return;
+ }
+ try {
+ File file = new File(fileName);
+ BufferedReader br = new BufferedReader(new FileReader(file));
+ String st;
+ while ((st = br.readLine()) != null) {
+ //System.out.println(st);
+ processor.process(st);
+ }
+ }catch(Exception e){
+ System.err.println("Exception while reading a file"+e);
+ }
+ }
+
+}
+
diff --git a/src/main/java/com/splitwise/model/Expense.java b/src/main/java/com/splitwise/model/Expense.java
new file mode 100644
index 0000000..eb020de
--- /dev/null
+++ b/src/main/java/com/splitwise/model/Expense.java
@@ -0,0 +1,12 @@
+package com.splitwise.model;
+
+import java.util.List;
+
+public class Expense {
+
+ private User paidByUser;
+ private int amount;
+ private int noOfPeopleInExpense;
+ List usersInExpense;
+
+}
diff --git a/src/main/java/com/splitwise/model/ExpenseTransactionInfo.java b/src/main/java/com/splitwise/model/ExpenseTransactionInfo.java
new file mode 100644
index 0000000..5e5a16c
--- /dev/null
+++ b/src/main/java/com/splitwise/model/ExpenseTransactionInfo.java
@@ -0,0 +1,68 @@
+package com.splitwise.model;
+
+import java.util.List;
+
+public class ExpenseTransactionInfo {
+ private double amount;
+ private int noOfPeopleInTxn;
+ private List usersInTxn;
+ private String splitType;
+ private User paidByUser;
+ private List args;
+ public double getAmount() {
+ return amount;
+ }
+
+ public void setAmount(double amount) {
+ this.amount = amount;
+ }
+
+ public int getNoOfPeopleInTxn() {
+ return noOfPeopleInTxn;
+ }
+
+ public void setNoOfPeopleInTxn(int noOfPeopleInTxn) {
+ this.noOfPeopleInTxn = noOfPeopleInTxn;
+ }
+
+ public List getUsersInTxn() {
+ return usersInTxn;
+ }
+
+ public void setUsersInTxn(List usersInTxn) {
+ this.usersInTxn = usersInTxn;
+ }
+
+ public String getSplitType() {
+ return splitType;
+ }
+
+ public void setSplitType(String splitType) {
+ this.splitType = splitType;
+ }
+
+ public User getPaidByUser() {
+ return paidByUser;
+ }
+
+ public void setPaidByUser(User paidByUser) {
+ this.paidByUser = paidByUser;
+ }
+
+ public List getArgs() {
+ return args;
+ }
+
+ public void setArgs(List args) {
+ this.args = args;
+ }
+
+ public ExpenseTransactionInfo(double amount, int noOfPeopleInTxn, List usersInTxn, User paidByUser, List args) {
+ this.amount = amount;
+ this.noOfPeopleInTxn = noOfPeopleInTxn;
+ this.usersInTxn = usersInTxn;
+
+ this.paidByUser = paidByUser;
+ this.args = args;
+ }
+}
diff --git a/src/main/java/com/splitwise/model/User.java b/src/main/java/com/splitwise/model/User.java
new file mode 100644
index 0000000..5ecd166
--- /dev/null
+++ b/src/main/java/com/splitwise/model/User.java
@@ -0,0 +1,97 @@
+package com.splitwise.model;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+public class User {
+
+ private static int U_ID=0;
+ private int userId;
+ private String name;
+ private String phoneNo;
+ private String email;
+ private int balance;
+ private Map expenseKeepingBook;
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ User user = (User) o;
+ return userId == user.userId;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(userId);
+ }
+
+ public User(String name, String phoneNo, String email) {
+ this.userId = U_ID++;
+ this.name = name;
+ this.phoneNo = phoneNo;
+ this.email = email;
+ expenseKeepingBook= new HashMap<>();
+ }
+
+ public static int getuId() {
+ return U_ID;
+ }
+
+ public int getUserId() {
+ return userId;
+ }
+
+ public void setUserId(int userId) {
+ this.userId = userId;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getPhoneNo() {
+ return phoneNo;
+ }
+
+ public void setPhoneNo(String phoneNo) {
+ this.phoneNo = phoneNo;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public int getBalance() {
+ return balance;
+ }
+
+ public void setBalance(int balance) {
+ this.balance = balance;
+ }
+
+ public Map getExpenseKeepingBook() {
+ return expenseKeepingBook;
+ }
+
+ public void setExpenseKeepingBook(Map expenseKeepingBook) {
+ this.expenseKeepingBook = expenseKeepingBook;
+ }
+
+ public static void setuId(int uId) {
+ U_ID = uId;
+ }
+}
diff --git a/src/main/java/com/splitwise/model/UserRegistry.java b/src/main/java/com/splitwise/model/UserRegistry.java
new file mode 100644
index 0000000..fe69a74
--- /dev/null
+++ b/src/main/java/com/splitwise/model/UserRegistry.java
@@ -0,0 +1,26 @@
+package com.splitwise.model;
+
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+
+public class UserRegistry {
+ public Set getUserRegistry() {
+ return userRegistry;
+ }
+
+ public void setUserRegistry(Set userRegistry) {
+ this.userRegistry = userRegistry;
+ }
+
+ private Set userRegistry = new HashSet();
+
+ public Optional searchUserFromRegistry(String userName){
+ for(User user : userRegistry){
+ if (user.getName().equalsIgnoreCase(userName)){
+ return Optional.of(user);
+ }
+ }
+ return Optional.empty();
+ }
+}
diff --git a/src/main/java/com/splitwise/process/TransactionProcesser.java b/src/main/java/com/splitwise/process/TransactionProcesser.java
new file mode 100644
index 0000000..4a545ad
--- /dev/null
+++ b/src/main/java/com/splitwise/process/TransactionProcesser.java
@@ -0,0 +1,28 @@
+package com.splitwise.process;
+
+import com.splitwise.transactionFactory.BalanceTransaction;
+import com.splitwise.transactionFactory.ExpenseTransaction;
+import com.splitwise.transactionFactory.Transaction;
+
+import java.security.BasicPermission;
+
+public class TransactionProcesser {
+ Transaction expenseProcessor;
+ Transaction balanceProcessor;
+ public TransactionProcesser(){
+ expenseProcessor = new ExpenseTransaction();
+ balanceProcessor = new BalanceTransaction();
+ }
+ public void process(String input){
+ String []inputArr = input.trim().split("\\s+");
+ String action = inputArr[0];
+ switch (action){
+ case "EXPENSE":
+ expenseProcessor.processTransaction(inputArr);
+ break;
+ case "SHOW":
+ balanceProcessor.processTransaction(inputArr);
+ break;
+ }
+ }
+}
diff --git a/src/main/java/com/splitwise/splitStrategy/SplitStartegy.java b/src/main/java/com/splitwise/splitStrategy/SplitStartegy.java
new file mode 100644
index 0000000..0c52253
--- /dev/null
+++ b/src/main/java/com/splitwise/splitStrategy/SplitStartegy.java
@@ -0,0 +1,8 @@
+package com.splitwise.splitStrategy;
+
+import com.splitwise.model.ExpenseTransactionInfo;
+
+public interface SplitStartegy {
+
+ public void executeSplit(ExpenseTransactionInfo expTxn);
+}
diff --git a/src/main/java/com/splitwise/splitStrategy/impl/SplitByEqual.java b/src/main/java/com/splitwise/splitStrategy/impl/SplitByEqual.java
new file mode 100644
index 0000000..9182cfa
--- /dev/null
+++ b/src/main/java/com/splitwise/splitStrategy/impl/SplitByEqual.java
@@ -0,0 +1,34 @@
+package com.splitwise.splitStrategy.impl;
+
+import com.splitwise.driver.SplitwiseDriver;
+import com.splitwise.model.ExpenseTransactionInfo;
+import com.splitwise.model.User;
+import com.splitwise.splitStrategy.SplitStartegy;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+public class SplitByEqual implements SplitStartegy {
+
+ @Override
+ public void executeSplit(ExpenseTransactionInfo expTxn) {
+ User user = expTxn.getPaidByUser();
+ for(int i=0;i users = SplitwiseDriver.getUserRegistry().getUserRegistry();
+ users = users.stream().filter(user-> !user.getExpenseKeepingBook().isEmpty()).collect(Collectors.toSet());
+ if(users.isEmpty()){
+ System.out.println("No balances");
+ return;
+ }
+
+ for(User user : users){
+ Map expenseMapping = user.getExpenseKeepingBook();
+ expenseMapping.forEach((u,amount)->{
+ if(amount < 0){
+ System.out.println("User "+user.getName()+"owes User "+u.getName()+"amount :"+(-1*amount));
+ }
+ });
+ }
+
+ }else if(inputArr.length == 2){
+ User u = SplitwiseDriver.getUserRegistry().searchUserFromRegistry(inputArr[1]).get();
+ if(u.getExpenseKeepingBook().isEmpty()){
+ System.out.println("No balances");
+ return;
+ }
+
+ Map expenseMapping = u.getExpenseKeepingBook();
+ expenseMapping.forEach((user,amount)->{
+ if(amount < 0){
+ System.out.println("User "+u.getName()+"owes User "+user.getName()+"amount :"+(-1*amount));
+ }else {
+ System.out.println("User "+user.getName()+"owes User "+u.getName()+"amount :"+amount);
+ }
+ });
+ }
+
+ }
+
+ @Override
+ public boolean validateInput(String[] inputArr) {
+ if(inputArr.length > 2)
+ return false;
+ if(!inputArr[0].equalsIgnoreCase("show"))
+ return false;
+ if(inputArr.length == 2){
+ String userName = inputArr[1];
+ Optional user = SplitwiseDriver.getUserRegistry().searchUserFromRegistry(userName);
+ if(!user.isPresent())
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/com/splitwise/transactionFactory/ExpenseTransaction.java b/src/main/java/com/splitwise/transactionFactory/ExpenseTransaction.java
new file mode 100644
index 0000000..4f6dcf4
--- /dev/null
+++ b/src/main/java/com/splitwise/transactionFactory/ExpenseTransaction.java
@@ -0,0 +1,104 @@
+package com.splitwise.transactionFactory;
+
+import com.splitwise.driver.SplitwiseDriver;
+import com.splitwise.model.ExpenseTransactionInfo;
+import com.splitwise.model.User;
+import com.splitwise.splitStrategy.SplitStartegy;
+import com.splitwise.splitStrategy.impl.SplitByEqual;
+import com.splitwise.splitStrategy.impl.SplitByExact;
+import com.splitwise.splitStrategy.impl.SplitByPercent;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+public class ExpenseTransaction implements Transaction{
+
+
+ SplitStartegy byEqual;
+ SplitStartegy byExact;
+ SplitStartegy byPercent;
+ public ExpenseTransaction(){
+ byEqual = new SplitByEqual();
+ byPercent = new SplitByPercent();
+ byExact = new SplitByExact();
+ }
+ @Override
+ public void processTransaction(String[] inputArr) {
+ boolean isValid = validateInput(inputArr);
+ if(!isValid){
+ return;
+ }
+
+ ExpenseTransactionInfo expTxn = getExpenseTransactionInfo(inputArr);
+ String splitType = inputArr[4+expTxn.getNoOfPeopleInTxn()];
+ switch(splitType.toUpperCase()){
+ case "EXACT":
+ byExact.executeSplit(expTxn);
+ break;
+ case "PERCENT":
+ byPercent.executeSplit(expTxn);
+ break;
+ case "EQUAL":
+ byEqual.executeSplit(expTxn);
+ break;
+
+ }
+
+ }
+ private ExpenseTransactionInfo getExpenseTransactionInfo(String[] inputArr){
+ double amount = Integer.parseInt(inputArr[2]);
+ int noOfPeopleinTxn = Integer.parseInt(inputArr[3]);
+ List usersInTxn = new ArrayList();
+ for(int i = 4; i < noOfPeopleinTxn+4;i++){
+ String userName = inputArr[i];
+ Optional u = SplitwiseDriver.getUserRegistry().searchUserFromRegistry(userName);
+ // TODO should be part of validation
+ if(u.isPresent()){
+ usersInTxn.add(u.get());
+ }else{
+ System.err.println("User in Transaction not present in user Registory: "+ Arrays.toString(inputArr));
+ //return;
+ }
+ }
+ String splitType = inputArr[4+noOfPeopleinTxn];
+
+ List args = new ArrayList<>();
+ for(int i = 5+noOfPeopleinTxn;i u = SplitwiseDriver.getUserRegistry().searchUserFromRegistry(inputArr[1]);
+ User paidByUser = u.get();
+ ExpenseTransactionInfo expTxn = new ExpenseTransactionInfo(amount,noOfPeopleinTxn,usersInTxn,paidByUser,args);
+ return expTxn;
+ }
+
+ @Override
+ public boolean validateInput(String[] inputArr) {
+ int size = inputArr.length;
+ try {
+ int amount = Integer.parseInt(inputArr[2]);
+ int noOfPeopleinTxn = Integer.parseInt(inputArr[3]);
+ int index = 3 +noOfPeopleinTxn+1;
+ String splitType = inputArr[index];
+ if(splitType.equalsIgnoreCase("EXACT") || splitType.equalsIgnoreCase("PERCENT")){
+ if(size-1- index != noOfPeopleinTxn){
+ System.err.println("Not valid Transaction: "+ Arrays.toString(inputArr));
+ return false;
+ }
+ else
+ return true;
+ }else if(splitType.equalsIgnoreCase("EQUAL") && index == size-1){
+ return true;
+ }else{
+ System.err.println("Not valid amount in Transaction: "+ Arrays.toString(inputArr));
+ return false;
+ }
+ }catch (NumberFormatException e){
+ System.err.println("Not valid integer input in Transaction: "+ Arrays.toString(inputArr));
+ return false;
+ }
+ }
+}
diff --git a/src/main/java/com/splitwise/transactionFactory/Transaction.java b/src/main/java/com/splitwise/transactionFactory/Transaction.java
new file mode 100644
index 0000000..c50b7ef
--- /dev/null
+++ b/src/main/java/com/splitwise/transactionFactory/Transaction.java
@@ -0,0 +1,7 @@
+package com.splitwise.transactionFactory;
+
+public interface Transaction {
+
+ public void processTransaction(String [] inputArr);
+ public boolean validateInput(String[] inputArr);
+}