#include #include #include #include "linklist.h" typedef struct heldChequeListNodeStruct{ char daysRemainingOnHold; double value; struct heldChequeListNodeStruct *link; } heldChequeListNode; typedef struct accountNodeStruct{ char accountType; char accountNumber[ACCOUNT_NUMBER_LENGTH+1]; double accountAvailableBalance; heldChequeListNode *heldCheques; struct accountNodeStruct *link; } accountNode; typedef struct customerListNodeStruct{ char cardNumber[CARD_NUMBER_LENGTH + 1]; char pinNumber[PIN_NUMBER_LENGTH + 1]; char incorrectPINAttemptsToday; double withdrawnAmountToday; char cardIsDisabled; accountNode *accounts; struct customerListNodeStruct *link; } customerListNode ; // Private function declarations static accountNode* linklist_FindAccountWithinCustomer(customerListNode *customer, char *accountNumber); /*-------------------------------------------------------------- * linklist_CreateCustomerList() * * Description: Initializes the linked list. * * Module: linklist - Linked lists for bank database simulation. * * Return values: * 0 - Fail * 1 - Success *--------------------------------------------------------------*/ char linklist_CreateCustomerList(customerList *headPointer) { *headPointer=NULL; return SUCCESS; } /*-------------------------------------------------------------- * linklist_AddCustomer() * * Description: Add a new customer to the head of the database * linked list. * * Module: linklist - Linked lists for bank database simulation. * * Return value: * Address of the new customer's entry, NULL if operation failed. *--------------------------------------------------------------*/ customerList linklist_AddCustomer(customerList list, char *cardNumber, char *pinNumber) { customerListNode *newNode; newNode = (customerListNode *)malloc(sizeof(customerListNode)); if(newNode==NULL) { printf("Couldn't malloc while adding cusomer.\n"); return(NULL); } if(strlen(cardNumber) != CARD_NUMBER_LENGTH) { printf("linklist_CreateCustomerList: Invalid card number passed in.\n"); return(NULL); } strcpy(newNode->cardNumber, cardNumber); strcpy(newNode->pinNumber, pinNumber); newNode->incorrectPINAttemptsToday=0; newNode->withdrawnAmountToday=0; newNode->cardIsDisabled=FALSE; newNode->accounts=NULL; // No accounts added to this customer yet newNode->link = (customerListNode *)list; list = (customerList)newNode; return(list); } /*-------------------------------------------------------------- * linklist_AddAccount() * * Description: Add a new account to a customer's entry in the * linked list. * * Module: linklist - Linked lists for bank database simulation. * * Return value: * Address of the customer's entry, NULL if operation failed. *--------------------------------------------------------------*/ customerList linklist_AddAccount(customerList list, char *cardNumber, char accountType, char *accountNumber) { customerListNode *customer = NULL; accountNode *accountsHead; if(strlen(accountNumber) != ACCOUNT_NUMBER_LENGTH) { printf("linklist_add_account: Invalid account number passed in.\n"); return(NULL); } customer = (customerListNode*)linklist_FindCustomer(list, cardNumber); if (customer == NULL) { printf("linklist_add_account: Internal error, couldn't find customer.\n"); } else { // Else the customer linked list node was successfully found accountsHead = customer->accounts; customer->accounts = (accountNode*)malloc(sizeof(accountNode)); // Need to search for tail of account list here!!! if (customer->accounts == NULL) { printf("linklist_add_account: Couldn't malloc.\n"); return(NULL); } customer->accounts->accountType = accountType; strcpy(customer->accounts->accountNumber, accountNumber); customer->accounts->accountAvailableBalance = 0; customer->accounts->heldCheques = NULL; customer->accounts->link = accountsHead; } return((customerList)customer); } /*-------------------------------------------------------------- * linklist_FindCustomer() * * Description: Finds a customer in the database. Returns * pointer to the customer entry. * * Module: linklist - Linked lists for bank database simulation. * * Return value: * Address of the customer's entry, NULL if operation failed. *--------------------------------------------------------------*/ // Note that this is a static function (local to this C file) customerList linklist_FindCustomer(customerList list, char *cardNumber) { while (list != NULL) { if(!strcmp(cardNumber, ((customerListNode*)list)->cardNumber)) return(list); list = (customerList)((customerListNode*)list)->link; } return (NULL); } /*-------------------------------------------------------------- * linklist_FindAccountWithinCustomer() * * Description: Finds a customer account in the database. Returns * pointer to the account entry. * * Module: linklist - Linked lists for bank database simulation. * * Return value: * Address of the account's entry, NULL if operation failed. *--------------------------------------------------------------*/ accountNode* linklist_FindAccountWithinCustomer(customerListNode *customer, char *accountNumber) { accountNode *tempAccount = NULL; if ((customer == NULL) || (accountNumber == NULL)) { printf("linklist_FindAccountWithinCustomer: NULL passed in.\n"); return 0; } tempAccount = customer->accounts; while (tempAccount != NULL) { if (!strcmp(tempAccount->accountNumber, accountNumber)) { return tempAccount; } else { tempAccount = tempAccount->link; } } return NULL; } /*-------------------------------------------------------------- * linklist_FindNumberAccounts() * * Description: Finds a customer account in the database. Returns * pointer to the account entry. * * Module: linklist - Linked lists for bank database simulation. * * Return value: * Address of the account's entry, NULL if not found, -1 if * list head passed in is NULL. *--------------------------------------------------------------*/ int linklist_FindNumberAccounts(customerList customer) { accountNode *tempAccount = NULL; int accountsFound=0; if (customer == NULL) return(-1); tempAccount = ((customerListNode*)customer)->accounts; while (tempAccount != NULL) { accountsFound++; tempAccount = tempAccount->link; } return accountsFound; } /*-------------------------------------------------------------- * linklist_GetAccountInfo() * * Description: Extracts information about an account from the * database. The "accountIndexIntoList" parameter is a * zero-based index of the account of interest (for the * specific customer number passed in). An index is used * rather than an account number because the calling routines * may not know what the account type or number is before * making the call to this function. * * Module: linklist - Linked lists for bank database simulation. * * Return value: * 0 on completion, -1 if customer passed in is NULL. *--------------------------------------------------------------*/ // accountIndexIntoList is 0-based index into the account char linklist_GetAccountInfo(customerList customer, int accountIndexIntoList, char* accountType, char* accountNumber) { accountNode *tempAccount = NULL; if (customer == NULL) return(-1); tempAccount = ((customerListNode*)customer)->accounts; while (accountIndexIntoList) { tempAccount = tempAccount->link; accountIndexIntoList--; } switch(tempAccount->accountType) { case ACCOUNT_TYPE_CHEQUING: strcpy(accountType, "Chequing"); break; case ACCOUNT_TYPE_SAVINGS: strcpy(accountType, "Savings"); break; case ACCOUNT_TYPE_CREDIT_CARD: strcpy(accountType, "Credit card"); break; case ACCOUNT_TYPE_LINE_OF_CREDIT: strcpy(accountType, "Line of credit"); break; } strcpy(accountNumber, tempAccount->accountNumber); return 0; } /*-------------------------------------------------------------- * linklist_AddHeldCheque() * * Description: Adds a held cheque to the account's held * cheque queue. * * Module: linklist - Linked lists for bank database simulation. * * Return value: * True on success, false on failure *--------------------------------------------------------------*/ char linklist_AddHeldCheque(customerList list, char *cardNumber, char *accountNumber, double chequeValue) { customerListNode *customer; accountNode *account; heldChequeListNode *chequeListHead; customer = (customerListNode*)linklist_FindCustomer(list, cardNumber); if (customer == NULL) { printf("linklist_AddHeldCheque: Couldn't find customer.\n"); return FALSE; } account = linklist_FindAccountWithinCustomer((customerListNode *)customer, accountNumber); if (account == NULL) { printf("linklist_AddHeldCheque: Couldn't find account within customer.\n"); return FALSE; } chequeListHead = account->heldCheques; account->heldCheques = (heldChequeListNode*)malloc(sizeof(heldChequeListNode)); if (account->heldCheques == NULL) { printf("linklist_AddHeldCheque: Couldn't malloc for new cheque storage.\n"); return FALSE; } account->heldCheques->daysRemainingOnHold = CHEQUE_HOLD_TIME_IN_DAYS; account->heldCheques->value = chequeValue; account->heldCheques->link = chequeListHead; return TRUE; } /*-------------------------------------------------------------- * linklist_debug_printDatabase() * * Description: Prints the database contents to the screen * for debugging and verification purposes. * * Module: linklist - Linked lists for bank database simulation. * * Return value: None. *--------------------------------------------------------------*/ void linklist_debug_printDatabase(customerList incomingList) { customerListNode *list; accountNode *tempAccount; heldChequeListNode *tempCheque; list = (customerListNode *)incomingList; if (list==NULL) { printf("linklist_debug_printList: List empty.\n"); return; } printf("\nlinklist_debug_printList:\n"); while (list != NULL) { // Until hit end of customer linked list printf("\n\tCard=%s\n\tPIN=%s\n\tPINAttemptsToday=%i\n\tWithdrawnToday=$%lf\n", \ list->cardNumber, list->pinNumber, list->incorrectPINAttemptsToday, list->withdrawnAmountToday); if (list->cardIsDisabled == TRUE) printf("\tCard __DISABLED__\n"); else printf("\tCard enabled\n"); // Now jump through the linked list of associated accounts tempAccount = list->accounts; while (tempAccount != NULL) { switch(tempAccount->accountType) { case ACCOUNT_TYPE_CHEQUING: printf("\t-->\tChequing account: "); break; case ACCOUNT_TYPE_SAVINGS: printf("\t-->\tSavings account: "); break; case ACCOUNT_TYPE_CREDIT_CARD: printf("\t-->\tCredit card account: "); break; case ACCOUNT_TYPE_LINE_OF_CREDIT: printf("\t-->\tLine of credit account: "); break; } printf(" $%lf\n", tempAccount->accountAvailableBalance); printf("\t\t\tAccount number: %s\n", tempAccount->accountNumber); // Now list any cheques on hold for the current account tempCheque = tempAccount->heldCheques; while (tempCheque != NULL) { printf("\t\t\tCheque worth $%.2f on hold for %i more days.\n", tempCheque->value, tempCheque->daysRemainingOnHold); tempCheque = tempCheque->link; } tempAccount = tempAccount->link; } printf("\t-------------------------------------------\n"); list = (customerListNode *)list->link; } printf("\n"); } /*-------------------------------------------------------------- * linklist_GetPIN() * * Arguments: * customerList customer: Customer entry to extract PIN from * char* PIN: Pointer to string in which PIN will be stored * * Return values: * 0 - Successful * 1 - Invalid customer pointer *--------------------------------------------------------------*/ char linklist_GetPIN(customerList customer, char* PIN) { if(customer == NULL) return(1); strcpy(PIN, ((customerListNode*)customer)->pinNumber); return(0); } /*-------------------------------------------------------------- * db_IsAccountLocked() * * Arguments: * customerList customer: Customer entry to extract PIN from * * Return values: * 0 - Account active * 1 - Account LOCKED * 2 - Other error *--------------------------------------------------------------*/ char linklist_IsAccountLocked(customerList customer) { if(customer == NULL) return(2); if((((customerListNode*)customer)->cardIsDisabled) == 1) return(1); else return(0); } char linklist_IncrementCustomerFailedPinAttempts(customerList customer) { printf("IncrementFailedPIN Card Number: %s, customer=%p\n", ((customerListNode*)customer)->cardNumber, customer); (((customerListNode*)customer)->incorrectPINAttemptsToday)++; if ((((customerListNode*)customer)->incorrectPINAttemptsToday) >= LOCKOUT_FAILED_PIN_ATTEMPTS) ((customerListNode*)customer)->cardIsDisabled = 1; linklist_debug_printDatabase(customer); return(0); } /*-------------------------------------------------------------- * linklist_GetAvailableBalances() * * Return values: * 0 - Successful * 1 - Couldn't find customer * 2 - Couldn't find account number * 3 - Other error *--------------------------------------------------------------*/ char linklist_GetAvailableBalance(customerList customer, char* accountNumber, double* balance) { accountNode *account; if (customer == NULL) return(1); account = linklist_FindAccountWithinCustomer((customerListNode *)customer, accountNumber); if (account == NULL) { return(2); } *balance = account->accountAvailableBalance; return(0); } // End linklist_GetAvailableBalance() /*-------------------------------------------------------------- * linklist_GetTotalBalances() * * Return values: * 0 - Successful * 1 - Couldn't find customer * 2 - Couldn't find account number * 3 - Other error *--------------------------------------------------------------*/ char linklist_GetTotalBalance(customerList customer, char* accountNumber, double* balance) { accountNode *account; heldChequeListNode *cheque; *balance = 0; if (customer == NULL) return(1); account = linklist_FindAccountWithinCustomer((customerListNode *)customer, accountNumber); if (account == NULL) { return(2); } *balance = account->accountAvailableBalance; cheque = account->heldCheques; while(cheque != NULL) { *balance += cheque->value; cheque = cheque->link; } return(0); } // End linklist_GetTotalBalance() /*-------------------------------------------------------------- * linklist_AddCash() * * Arguments: * * Return values: * 0 - Successful * 1 - Couldn't find account number * 2 - Other error *--------------------------------------------------------------*/ char linklist_AddCash(customerList customer, char *accountNumber, double cashValue) { accountNode *account = NULL; account = linklist_FindAccountWithinCustomer((customerListNode*)customer, accountNumber); if (account == NULL) return(1); // Actually update the account balance (account->accountAvailableBalance) += cashValue; return(0); } // End linklist_AddCash() /*-------------------------------------------------------------- * linklist_AddToCashWithdrawn() * * Arguments: * * Return values: * 0 - Successful * 1 - Couldn't find customer * 2 - Other error *--------------------------------------------------------------*/ char linklist_AddToCashWithdrawn(customerList customer, double addedValue) { if(customer == NULL) return(1); // Actually update the withdrawn balance (((customerListNode*)customer)->withdrawnAmountToday) += addedValue; return(0); } // End linklist_AddToCashWithdrawn() /*-------------------------------------------------------------- * linklist_GetCashWithdrawn() * * Arguments: * * Return values: * 0 - Successful * 1 - Couldn't find customer * 2 - Other error *--------------------------------------------------------------*/ char linklist_GetCashWithdrawn(customerList customer, double *withdrawnValue) { if(customer == NULL) return(1); // Actually update the withdrawn balance *withdrawnValue = (((customerListNode*)customer)->withdrawnAmountToday); return(0); } // End linklist_GetCashWithdrawn() /*-------------------------------------------------------------- * linklist_NewDayRollup() * * Description: Updates the database values for the beginning of * a new day. * * Module: linklist - Linked lists for bank database simulation. * * Return values: * 0 - Successful * 1 - Other error *--------------------------------------------------------------*/ char linklist_NewDayRollup(customerList customer) { accountNode *tempAccount = NULL; heldChequeListNode *tempCheque, *prevCheque=NULL, *chequeToFree=NULL; // Move through the customers of the linked list while (customer != NULL) { // Move through the accounts of the customer tempAccount = ((customerListNode*)customer)->accounts; while (tempAccount != NULL) { // Move through any cheques associated with the account tempCheque = tempAccount->heldCheques; while (tempCheque != NULL) { tempCheque->daysRemainingOnHold--; // If the cheque has now been cleared if (tempCheque->daysRemainingOnHold <= 0) { tempAccount->accountAvailableBalance += tempCheque->value; // Remove from list if (prevCheque == NULL) tempAccount->heldCheques = tempCheque->link; // If this was the first cheque in the account's held cheque list else prevCheque->link = tempCheque->link; chequeToFree = tempCheque; tempCheque = tempCheque->link; free(chequeToFree); // Release memory from the cleared cheque } else { prevCheque = tempCheque; tempCheque = tempCheque->link; } } // End while(tempCheque != NULL) tempAccount = tempAccount->link; } // Reset the daily counters in the customer record ((customerListNode*)customer)->incorrectPINAttemptsToday = 0; ((customerListNode*)customer)->withdrawnAmountToday = 0; // Move to next customer in the database customer = (customerList)((customerListNode*)customer)->link; } return(0); } // End db_NewDayRollup()