package jesse.keeblarcraft.BankMgr; 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 // // 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 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. private Integer kbicInsuredAmount; private Boolean kbicInsured; // bankMoney is the total amount of money the bank possesses itself. The bank itself is personally responsible // for backing the amount of money it claims it has and this is the balance that is withdrawn from for credits. // A bank can have a sum of money that is less than the total amount of money of all its account holders private Integer bankMoney; // Key = ACCOUNT NUMBER // Value = ACCOUNT private HashMap accountsList; private HashMap> accountsListFromName; // This is a list that just points to a list of account numbers by person. USEFUL private List lockedUsers; // A list of users who are locked out of the bank and are incapable of performing more actions within it public IndividualBank(String routingNumber) { accountsList = new HashMap(); accountsListFromName = new HashMap>(); // 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. // 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 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 containsAccount; } }