#include "stdstuff.h" #include "CustomerDB.h" void CustomerDB::subCopyDB(CNode* &subHead, CNode* otherSubHead) { // used by copyDB CNode *n; // temporary node pointer to join up the list // if other list is empty, we're done -- just return if(otherSubHead==NULL) { subHead=NULL; return; } // copy the rest of the list subCopyDB(n,otherSubHead->next); // and add the first value to the front of that list subHead = new CNode(otherSubHead->ci, n); walkInProgress = false; // we changed the database } void CustomerDB::subDeleteDB(CNode* &subHead) { // used by deleteDB if(subHead==NULL) return; // nothing to do // delete the rest of the list subDeleteDB(subHead->next); delete subHead; // and then delete the head subHead = NULL; // just to tidy things up } bool CustomerDB::subIDInUse(int ID, CNode* subHead) const { // used by add and changeID if(subHead==NULL) return false; // if list is empty id is not in use if((subHead->ci).getID()==ID) return true; // ID is in the first node // otherwise ID is in use iff it's in use in the rest of the list return subIDInUse(ID,subHead->next); } bool CustomerDB::subRemove(int id, CNode* subPrev, CNode* subCurr) { // used by remove if(subCurr==NULL) return false; // customer is not in database if((subCurr->ci).getID()==id) { // found it, so remove it if(subPrev==NULL) // deleting the first element head=subCurr->next; else // deleting another element subPrev->next=subCurr->next; // delete the node delete subCurr; walkInProgress = false; // database changed return true; } // otherwise remove id from the rest of the list return subRemove(id,subCurr,subCurr->next); } void CustomerDB::subPrint(CNode *subHead) const { // used by print if(subHead==NULL) return; // nothing to print if DB is empty // print the first element (subHead->ci).print(); // print the rest of the list subPrint(subHead->next); } bool CustomerDB::subChangeID(int id, int nID, CNode* subHead) { // used by changeID if(subHead==NULL) return false; // id not found in database if((subHead->ci).getID()==id) { // found it, change the ID (subHead->ci).setID(nID); // change the ID walkInProgress=false; // database changed return true; } // otherwise change the id in the rest of list return subChangeID(id,nID,subHead->next); } // private method to delete database; used by destructor and assignment void CustomerDB::deleteDB() { subDeleteDB(head); // call recursive submethod } // private method to copy database; used by copy constructor and assignment void CustomerDB::copyDB(const CustomerDB &otherCustDB) { numCusts = otherCustDB.numCusts; // set number of customers // copy over contents of linked list recursively subCopyDB(head,otherCustDB.head); } // the constructor creates an empty database CustomerDB::CustomerDB() { numCusts=0; // no customers yet head = NULL; // no customers to pointer is NULL walkInProgress = false; // no walk in progress } // copy constructor CustomerDB::CustomerDB(const CustomerDB &otherCustDB) { copyDB(otherCustDB); // copy the database } // destructor CustomerDB::~CustomerDB() { cout << "destructor invoked\n"; pause(); // so we can see this message at the end of the program deleteDB(); // deletes the dynamically allocated array } // assignment CustomerDB& CustomerDB::operator=(const CustomerDB &otherCustDB) { deleteDB(); // deletes the old dynamically allocated array copyDB(otherCustDB); // copy the database return *this; } // returns the number of customers in the database int CustomerDB::getNumCusts() const { return numCusts; } // add a new customer to the database; returns true if successful, false otherwise // (database full or customer already exists) bool CustomerDB::add(const Customer &newCust) { if(subIDInUse(newCust.getID(),head)) return false; // customer already in database // insert new customer at beginning (as that's easiest) head = new CNode(newCust,head); numCusts++; // we've added a Customer walkInProgress = false; // we've changed the database return true; // success } // remove a customer from the database; returns true if successful, false otherwise (customer // does not exist) bool CustomerDB::remove(int id) { return subRemove(id,NULL,head); // use recursive submethod } // prints the full customer database (or a note if the database is empty); // Customers are printed one per line, with 2 decimals for the total. void CustomerDB::print() const { if(numCusts==0) { // empty database cout << "Customer database is empty.\n"; return; } subPrint(head); // recursive method to print the database } // change the customer number of an existing customer; returns true if successful, // false otherwise (customer does not exist, or new customer number in use) bool CustomerDB::changeID(int id, int nid) { if(subIDInUse(nid,head)) return false; // new id is in use return subChangeID(id,nid,head); // recursive submethod } // change the customer total of an existing customer; returns true if successful, // false otherwise (customer does not exist) bool CustomerDB::changeTotal(int id, double ntotal) { for(CNode *c=head; c!=NULL; c=c->next) { if((c->ci).getID()==id) { // found the one we want to change so update total, use getID (c->ci).setTotal(ntotal); // **must** use setTotal method walkInProgress = false; // we've changed the database return true; // Customer information updated } } return false; // Customer does not exist in database } // move the purchase date by the number of days given; returns true if successful, // false otherwise (customer does not exist) bool CustomerDB::moveDate(int id, int days) { Date temp; for(CNode *c=head; c!=NULL; c=c->next) { if((c->ci).getID()==id) { // found the one we want to change so update total, use getID temp = (c->ci).getDate(); // **must** use getDate and setDate methods temp.move(days); // adjust old date (c->ci).setDate(temp); // and set the date to the newly calculated date walkInProgress = false; // we've changed the database return true; // Customer information updated } } return false; // Customer does not exist in database } // append the given String2002 to the customer name; returns true if successful, // false otherwise (customer does not exist) bool CustomerDB::appendName(int id, const String2002 &add) { for(CNode *c=head; c!=NULL; c=c->next) { if((c->ci).getID()==id) { // found the one we want to change so update total, use getID (c->ci).setName((c->ci).getName()+add); // **must** use getName and setName methods walkInProgress = false; // we've changed the database return true; // Customer information updated } } return false; // Customer does not exist in database } // returns the lowest customer ID of all customers // (returns -1 if there are no customers in the database) int CustomerDB::getLowestID() const { CNode *lowestIDptr; if(numCusts==0) return -1; // return -1 if database empty // assume first customer has the lowest id and check the rest lowestIDptr = head; for(CNode *c=head->next; c!=NULL; c=c->next) { if(c->cici) lowestIDptr = c; } return (lowestIDptr->ci).getID(); // return the lowest ID } // returns the highest total of all customers // (returns -1 if there are no customers in the database) double CustomerDB::getBestTotal() const { double maxtotal; if(numCusts==0) return -1; // return -1 if database empty // assume first total is largest and then check the rest maxtotal = (head->ci).getTotal(); // **must** use getTotal for(CNode *c=head->next; c!=NULL; c=c->next) { if((c->ci).getTotal()>maxtotal) // use getTotal maxtotal=(c->ci).getTotal(); // **must** use getTotal } return maxtotal; } // prints (to cout) the earliest purchase date of all customers // (prints 31 12 2099 if there are no customers in the database) void CustomerDB::outputFirstDate() const { Date max(31,12,2099); cout << "The first purchase date is: "; for(CNode *c=head->next; c!=NULL; c=c->next) { if((c->ci).getDate().compareTo(max)<0) // **must** use getDate max = (c->ci).getDate(); // **must** use getDate } max.write(cout); cout << endl; } // returns the customer name that's first in case insensitive alphabetical order // (returns "" if there are no customers in the database) String2002 CustomerDB::getFirstName() const { String2002 lowerFirstName, firstName, lowerName, name; if (numCusts==0) return ""; // return empty string if no customers // start with index 0 as the first name (convert to lower case) name = (head->ci).getName(); // **must** use getName lowerFirstName = name; firstName = name; for(int i=0;i<(int)lowerFirstName.length();i++) lowerFirstName[i] = tolower(lowerFirstName[i]); // go through the rest, checking to see if each (converted to lower // case) is the first one so far for(CNode *c=head->next; c!=NULL; c=c->next) { name = (c->ci).getName(); // **must** use getName lowerName = name; for(int j=0;j<(int)lowerName.length();j++) lowerName[j] = tolower(lowerName[j]); if(lowerNameci; // return first customer return true; } bool CustomerDB::continueWalk (Customer ¤tCustomer) { if (!walkInProgress) // change made during walk so abort quit("CustomerDB::continueWalk - invalid call\n"); walkPosition = walkPosition->next; if (walkPosition==NULL) { walkInProgress = false; // we've come to the end of the road return false; } currentCustomer = walkPosition->ci; // return next customer return true; }