From 87afc5c8ab545d76a4aeaf5adfc083c75b23a335 Mon Sep 17 00:00:00 2001 From: Jkibbels Date: Wed, 6 Nov 2024 20:01:41 -0500 Subject: [PATCH] [BANKING] Fleshing out more banking information. Logic to populate fast-access bank account list added UNTESTED --- .../BankMgr/AccountNumberGenerator.java | 20 ++- .../BankMgr/IndividualAccount.java | 20 ++- .../keeblarcraft/BankMgr/IndividualBank.java | 133 +++++++++++++++--- 3 files changed, 149 insertions(+), 24 deletions(-) diff --git a/src/main/java/jesse/keeblarcraft/BankMgr/AccountNumberGenerator.java b/src/main/java/jesse/keeblarcraft/BankMgr/AccountNumberGenerator.java index a59883f..02f9894 100644 --- a/src/main/java/jesse/keeblarcraft/BankMgr/AccountNumberGenerator.java +++ b/src/main/java/jesse/keeblarcraft/BankMgr/AccountNumberGenerator.java @@ -27,7 +27,7 @@ import java.util.Random; public class AccountNumberGenerator { // Callers of this function are required to verify the given number is unique. - public static String NewAccountNumber(String symbol, Integer routingNumber, Integer accountType, String username) { + public static String GenerateNewAccountNumber(String symbol, Integer routingNumber, Integer accountType, String username) { String generatedAccountNumber = symbol + "-" + routingNumber + "-" + accountType + "-"; // Block to translate part of username into number format @@ -48,4 +48,22 @@ public class AccountNumberGenerator { return generatedAccountNumber; } + + // the below functions must be given a key generated from the above function or they will combust into + // not less than one million pieces! :) + public static String GetFinancialSymbolFromId(String accountId) { + return accountId.substring(0, 4); + } + + public static Integer GetRoutingNumberFromId(String accountId) { + return Integer.parseInt(accountId.substring(5, 9)); + } + + public static Integer GetAccountNumberFromId(String accountId) { + return Integer.parseInt(accountId.substring(10, accountId.length())); + } + + public static Integer GetAccountTypeFromId(String accountId) { + return (int) accountId.charAt(10); + } } diff --git a/src/main/java/jesse/keeblarcraft/BankMgr/IndividualAccount.java b/src/main/java/jesse/keeblarcraft/BankMgr/IndividualAccount.java index 1585d12..b56cbbe 100644 --- a/src/main/java/jesse/keeblarcraft/BankMgr/IndividualAccount.java +++ b/src/main/java/jesse/keeblarcraft/BankMgr/IndividualAccount.java @@ -6,9 +6,9 @@ import java.util.List; // TODO: Add ability to store NBT data of items in the future so we can store not just money but items too // like a safety deposit box public class IndividualAccount { - private String accountNumber; + private Integer accountNumber; private String accountNumberAlias; - private String routingNumber; // Will always be the bank it's in + private Integer routingNumber; // Will always be the bank it's in private List accountHolders; private Integer accountBalance; private Boolean allowNegativeBalance; @@ -18,7 +18,7 @@ public class IndividualAccount { public IndividualAccount() {} - public IndividualAccount(String accountNumber, String routingNumber, List holders, + public IndividualAccount(Integer accountNumber, Integer routingNumber, List holders, Boolean allowNegativeBalance, Integer initialBalance, String alias) { this.accountNumber = accountNumber; this.routingNumber = routingNumber; @@ -28,6 +28,12 @@ public class IndividualAccount { this.accountNumberAlias = alias; } + public void AddAccountHolder(String newHolder) { + if (!accountHolders.contains(newHolder)) { + accountHolders.add(newHolder); + } + } + public void AliasAccount(String newAlias) { this.accountNumberAlias = newAlias; } @@ -36,6 +42,10 @@ public class IndividualAccount { return accountLocked; } + public void LockAccount() { + accountLocked = true; + } + public Boolean Deposit(Integer amount) { Boolean success = false; if (!accountLocked) @@ -96,11 +106,11 @@ public class IndividualAccount { return accountBalance; } - public String GetAccountNumber() { + public Integer GetAccountNumber() { return accountNumber; } - public String GetRoutingNumber() { + public Integer GetRoutingNumber() { return routingNumber; } diff --git a/src/main/java/jesse/keeblarcraft/BankMgr/IndividualBank.java b/src/main/java/jesse/keeblarcraft/BankMgr/IndividualBank.java index 3369381..2aea2f1 100644 --- a/src/main/java/jesse/keeblarcraft/BankMgr/IndividualBank.java +++ b/src/main/java/jesse/keeblarcraft/BankMgr/IndividualBank.java @@ -1,10 +1,11 @@ package jesse.keeblarcraft.BankMgr; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import static java.util.Map.entry; import jesse.keeblarcraft.ConfigMgr.ConfigManager; // Contains the information of an individual bank @@ -12,9 +13,17 @@ import jesse.keeblarcraft.ConfigMgr.ConfigManager; // The bank will keep track of all accounts within its facilities. In addition to accounts, the bank // maintains its own identifier which is unique and other misc things. public class IndividualBank { + private Map ACCOUNT_TYPES = Map.ofEntries( + entry("checking", 0), + entry("savings", 1) + ); + + ConfigManager config = new ConfigManager(); - private String routingNumber; // this is the banks unique identifier - private String numberOfAccounts; // Total number of accounts the bank has. This includes only active accounts + private Integer routingNumber; // this is the banks unique identifier + private Integer numberOfAccounts; // Total number of accounts the bank has. This includes only active accounts inside accountsList. + private String bankFourLetterIdentifier; + private Integer maxBankAccounts = 100_000_000; // Making this simple for myself any one type of account has 8 random numbers genereated so 10^8 possible accounts // Think FDIC but from the servers account (keeblarcraft insurance corporation) // KBIC will ensure an amount of money based on its trustworthiness to a bank and the number of holders it has. @@ -38,30 +47,118 @@ public class IndividualBank { // READ IN BANK CONFIG + + + + + // A modified config reader is needed here for when each IndividualAccount is read in - the name is taken from that and is attached to the - // 'accountsListFromName' structure. This makes it no worse than O(n) to fill these two structures in - } - - public Boolean CreateAccount(String holderName, String accountType) { - if (accountType.toLowerCase() != "checking" || accountType.toLowerCase() != "savings") { - return false; - } // TODO: Replace String with enum type in future and remove this early return - - Boolean success = false; - - // Verify this isn't a blacklisted user - if (!lockedUsers.contains(holderName)) { + // 'accountsListFromName' structure. This makes it no worse than O(n) to fill these two structures in. + // NOTE: This is an *EXPENSIVE* operation! Future us might need to update this. Also note a method is needed for everytime a player opens a new account + // or gets put on one to update the map every time + for (Entry account : accountsList.entrySet()) { + // We must loop over the string of holders for each account as well to make the flattened accountsListFromName map + List accountHolders = account.getValue().GetAccountHolders(); + // Match each user to the secondary map & add to list-value if not existing + for (Integer holderIndex = 0; holderIndex < accountHolders.size(); holderIndex++) { + if (accountsListFromName.containsKey(accountHolders.get(holderIndex))) { + // Case 1: User exists, update map entry + accountsListFromName.get(accountHolders.get(holderIndex)).add(account.getKey()); // Add a new account id to this person in the new flat map + } else { + // Case 2: User does not already exist; add a new map entry + accountsListFromName.put(accountHolders.get(holderIndex), List.of(account.getKey())); // Store name as key, and new List with the value of ACCOUNT # + } + } } + numberOfAccounts = accountsList.size(); + } + + // Updates the regular bank account list & the fast-access bank account list + // NO values are allowed to be null. Manually update lists separately if that's the behaviour you want! + public void UpdateBankAccounts(String newHolderName, Integer accountIdentifier, IndividualAccount newAccountOnly) { + // Update the fast-access map first + if (accountsListFromName.containsKey(newHolderName)) { + // Check if user is already in map + accountsListFromName.get(newHolderName).add(accountIdentifier); + } else { + // Add new entry to map + accountsListFromName.put(newHolderName, List.of(accountIdentifier)); + } + + // Update regular account list + if (accountsList.containsKey(accountIdentifier)) { + // This path assumes we are adding a holder as opposed to adding an account (else, how else would this work?) + accountsList.get(accountIdentifier).AddAccountHolder(newHolderName); + } else { + // Non-existent account means a new one! + accountsList.put(accountIdentifier, newAccountOnly); + numberOfAccounts++; + } + } + + public Boolean CreateAccount(String holderName, String accountTypeStr) { + Boolean success = false; + if (accountsList.size() <= maxBankAccounts && ACCOUNT_TYPES.containsKey(accountTypeStr.toLowerCase())) { + // Verify this isn't a blacklisted user + if (!lockedUsers.contains(holderName)) { + Integer maxAttempts = 1000; // Reasonably a unique bank account should pop up within 1000 generations. If not, the user may try again. + String accountId = AccountNumberGenerator.GenerateNewAccountNumber(bankFourLetterIdentifier, routingNumber, ACCOUNT_TYPES.get(accountTypeStr), holderName); + + // TODO: Fix in future with a method that will guarentee a one-time necessary number generator. Statistically speaking; this will be okay for the + // entire life time of the server. BUT, you never know! + while (maxAttempts != 0 && !accountsList.containsKey(AccountNumberGenerator.GetAccountNumberFromId(accountId))) { + accountId = AccountNumberGenerator.GenerateNewAccountNumber(bankFourLetterIdentifier, routingNumber, ACCOUNT_TYPES.get(accountTypeStr), holderName); + maxAttempts--; + } + + // Final check to add the account + Integer actualAccountNumber = AccountNumberGenerator.GetAccountNumberFromId(accountId); + if (!accountsList.containsKey(actualAccountNumber)) { + IndividualAccount newAccount = new IndividualAccount(actualAccountNumber, this.routingNumber, List.of(holderName), false, 0, ""); + UpdateBankAccounts(holderName, actualAccountNumber, newAccount); + success = true; + } + } + } return success; } - public Boolean HasAccount(String accountIdentifier) { + public void AliasAccount(String accountId, String newAlias) { + Integer accountNumber = AccountNumberGenerator.GetAccountNumberFromId(accountId); + if (accountsList.containsKey(accountNumber)) { + accountsList.get(accountNumber).AliasAccount(newAlias); + } + } + + public Boolean LockAccountHolder(String holderName) { + Boolean success = false; + + Integer accountIter = 0; + for (Entry> holderAccounts : accountsListFromName.entrySet()) { + accountsList.get(holderAccounts.getValue().get(accountIter++)).LockAccount(); + } + return success; + } + + public Boolean CloseAccount(String accountId) { + Boolean success = false; + + Integer accountNumber = AccountNumberGenerator.GetAccountNumberFromId(accountId); + + if (accountsList.get(accountNumber).GetAccountBalance() == 0) { + accountsList.remove(accountNumber); + success = true; + } + return success; + } + + public Boolean HasAccount(Integer accountIdentifier) { Boolean containsAccount = false; if (accountsList.containsKey(accountIdentifier)) { containsAccount = true; } - return true; + return containsAccount; } -} +} \ No newline at end of file