/*
* @author : Charlie Lee
* @date : 2020-09-03
* @email : find1086@gmail.com
*
* @info : simple bank account manage program.
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
public class GenericBankingSystem {
private static final BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
private static final Map<String, List<BankAccount>> accountsMap = new HashMap<>();
private static final List<BankUser> userList = new ArrayList<>();
private static Long accountId = 0L;
private static final GenericBankingSystem bankSystem = GenericBankingSystem.getInstance();
private GenericBankingSystem() {}
public static GenericBankingSystem getInstance() {
if(bankSystem == null) return new GenericBankingSystem();
return bankSystem;
}
public static void main(String[] args) throws IOException {
System.out.println("Welcome to Bank System.");
bankSystem.run();
}
public void run() throws IOException {
boolean flag = true;
while(flag) {
bankSystem.addAccount();
System.out.print("successfully added. do you want to add more? (y/n) : ");
String addmore = br.readLine().toLowerCase();
if(!addmore.equals("y")) flag = false;
}
bankSystem.manageAccount();
}
private void addAccount() throws IOException {
boolean flag = true;
String accountNumber = "";
while(flag) {
System.out.println("type account number please.");
accountNumber = validateFormat(br.readLine());
if(accountNumber != null) flag = checkDuplicatedAccountNumber(accountNumber);
else System.out.println("it seems not valid account number format.");
}
System.out.print("type username for adding this account : ");
String username = br.readLine();
BankUser user;
if(!accountsMap.containsKey(username)) {
user = new BankUser(username);
} else {
user = userList.stream()
.filter(name -> (name.getUsername()).equals(username))
.findFirst()
.orElse(null);
}
if(user != null) {
user.addAccount(new BankAccount(++accountId, accountNumber));
userList.add(user);
accountsMap.put(username, user.getAccountList());
} else {
throw new Error("Unexpected Error! contact to the Administrator.");
}
}
private String validateFormat(String text) {
String koreanFormat = "^[0-9]{3,6}+[-]?[0-9]{2,6}+[-]?[0-9]{1,7}+([-]?[0-9]{1,7})?$";
if(text.matches(koreanFormat)) return text;
return null;
}
private boolean checkDuplicatedAccountNumber(String accountNumber) {
boolean exist = bankSystem.findDuplicatedAccountNumer(accountNumber);
if(exist) System.out.println("this number is already exist. try other please.");
return exist;
}
private boolean findDuplicatedAccountNumer(String number) {
if(userList.size() <= 0) return false;
return userList.stream().anyMatch(user -> accountsMap.get(user.getUsername())
.stream()
.anyMatch(v -> (v.getAccountNumber()).equals(number)));
}
private void manageAccount() throws IOException {
boolean flag = true;
while (flag) {
String name = chooseUserAccount();
List<BankAccount> accountsOfanUser = accountsMap.get(name);
bankSystem.printUserAccount(accountsOfanUser);
// specify which account state change.
BankAccount account = bankSystem.chooseOneAccount(accountsOfanUser);
bankSystem.controlAccount(account);
flag = bankSystem.continueToManage();
}
}
private boolean continueToManage() throws IOException {
System.out.println("would you like to return to select user? (y/n)");
String value = br.readLine().toLowerCase();
if (value.equals("n")) {
System.out.println("would you like to go back selecting account menu ? (y/n) : ");
value = br.readLine().toLowerCase();
if(value.equals("n")) {
System.out.println("would you like to go back first step? (y/n) : n will shut down program) : ");
value = br.readLine().toLowerCase();
if(value.equals("n")) {
System.out.println("okay. program will be shut down.");
br.close();
} else {
System.out.println("Welcome back to account registration.");
bankSystem.run();
}
} else {
bankSystem.manageAccount();
}
return false;
}
return true;
}
private BankAccount chooseOneAccount(List<BankAccount> accountsOfanUser) throws IOException {
System.out.println("which account's balance do you want to change?");
System.out.print("please choose number in [], not account number : ");
int accountId = parseToInt(br.readLine()) - 1;
return accountsOfanUser.get(accountId);
}
private void printUserAccount(List<BankAccount> accountsOfanUser) {
System.out.println("The user has those accounts: ");
for (int i = 1; i <= accountsOfanUser.size(); i++) {
System.out.println("[" + i + "] " + accountsOfanUser.get(i - 1));
}
}
private String chooseUserAccount() throws IOException {
String name;
do {
System.out.println("::: user account list :::");
Set<String> key = accountsMap.keySet();
for (String o : key) {
System.out.print(o + " ");
}
System.out.println("\nwhich users account do you want manage? : ");
name = br.readLine();
} while (!bankSystem.validateRegisteredUser(name));
return name;
}
private boolean validateRegisteredUser(String name) {
if (!accountsMap.containsKey(name)) {
System.out.println("this user seems not registered yet.");
return false;
}
return true;
}
private void controlAccount(BankAccount account) throws IOException {
boolean changeMoneyProcess = true;
int chooseNum;
while (changeMoneyProcess) {
System.out.println("what would you want to do? choose number please.");
System.out.println("[1] deposit [2] withdraw [3] show money balance");
chooseNum = parseToInt(br.readLine());
switch (chooseNum) {
case 1: {
System.out.println("how much money do you want to deposit ?");
account.depositMoney(parseToDouble(br.readLine()));
break;
}
case 2: {
System.out.println("how much money do you want to withdraw ?");
account.withdrawMoney(parseToDouble(br.readLine()));
break;
}
case 3:
break;
default:
System.out.println("not service this number yet.");
}
System.out.printf("money balance : %5.2f\n", account.getMoney());
changeMoneyProcess = wantToContinueChangeMoney();
}
}
private boolean wantToContinueChangeMoney() throws IOException {
System.out.println("would you want to continue changing money balance ? (y/n)");
return !(br.readLine()).equals("n");
}
private static Integer parseToInt(String text) throws IOException {
boolean isAbleToParseInt = false;
int parsedInt = 0;
while (!isAbleToParseInt) {
try {
parsedInt = Integer.parseInt(text);
isAbleToParseInt = true;
} catch (NumberFormatException nfe) {
System.out.println("it seems not number! please check again.");
text = br.readLine();
}
}
return parsedInt;
}
private static Double parseToDouble(String text) throws IOException {
boolean isAbleToParseDouble = false;
double parsedDouble = 0;
while (!isAbleToParseDouble) {
try {
parsedDouble = Double.parseDouble(text);
isAbleToParseDouble = true;
} catch (NumberFormatException nfe) {
System.out.println("it seems not number! please check again.");
text = br.readLine();
}
}
return parsedDouble;
}
}
class BankUser {
private final String username;
private final List<BankAccount> accountList = new ArrayList<>();
public BankUser(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
public void addAccount(BankAccount account) {
accountList.add(account);
}
public List<BankAccount> getAccountList() {
return accountList;
}
@Override
public String toString() {
return "BankUser{" +
"username='" + username + '\'' +
", accountList=" + accountList +
'}';
}
}
class BankAccount {
private final long accountId;
private final String accountNumber;
private final LocalDateTime regDate;
private double money;
public BankAccount(long accountId, String accountNumber) {
this.accountId = accountId;
this.accountNumber = accountNumber;
this.regDate = LocalDateTime.now();
}
public String getAccountNumber() {
return accountNumber;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BankAccount)) return false;
BankAccount that = (BankAccount) o;
return accountId == that.accountId &&
Double.compare(that.money, money) == 0 &&
Objects.equals(accountNumber, that.accountNumber);
}
@Override
public int hashCode() {
return Objects.hash(accountId, accountNumber, money);
}
@Override
public String toString() {
return "accountNumber: " + accountNumber +
"\n\tmoney: " + money +
"\n\tregDate: " + regDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + "\n";
}
public double getMoney() {
return money;
}
public void depositMoney(double money) {
this.money += money;
}
public void withdrawMoney(double money) {
double temp = this.money -= money;
if (temp < 0) {
throw new Error("you can't withdraw that money.");
}
this.money = temp;
}
}
// http://colorscripter.com/s/rcw1z3L
// http://colorscripter.com/s/rcw1z3L
// http://colorscripter.com/s/rcw1z3L