CPhoneBook
Home ] Up ]

 

//PhoneBook11.cpp
//                           saved on 04/30/2001
//                           saved 10 on 12/06/2000
// deleteByAddress
// CPhoneBook(int n)
// overload assignment (=) operator
// copy constructor
// insertAtHead              added 09 11/27/2000
// searchByName              added
// void swap(p,q)            added 
// void swap(e1,e2)          added 
// bool isSortedByName()     added 06 11/08/2000
//    void sortByName(void); added 05
//Overload << for output     added 04
//Constructor CPhoneBook(ch) added 03


////////////////////////////////////////////////////////////
// project #6 Date Assigned 11/8/2000, Date Due 11/17/2000
// describe ten shuffling methods   (20)
// implement one of the ten methods (20)
// write the testShuffle            (10)
// Five test runs                   (10)


////////////////////////////////////////////////////////////
//include files
////////////////////////////////////////////////////////////
#include <iostream.h>
#include <string.h>
#include <stdlib.h>


////////////////////////////////////////////////////////////
//constants
////////////////////////////////////////////////////////////
int const MAX_LEN = 10;
int const MAX_COUNT = 10;
int const TEST_COUNT = 5;


////////////////////////////////////////////////////////////
//global variables
////////////////////////////////////////////////////////////
int masterKey = 1;


////////////////////////////////////////////////////////////
//test values
////////////////////////////////////////////////////////////
const char *testNames[] = 
  {"Bob", "Tom", "Ann", "Ron", "Ben", "Ken", "Rob",
   "Sam", "Don", "Dan", "Tim"};

const int MAX_NAMES = sizeof(testNames)/sizeof(testNames[0]);

const char *testPhones[] = 
  {"111-1111", "222-2222", "333-3333", "444-4444"};

const int MAX_PHONES = sizeof(testPhones)/sizeof(testPhones[0]);

const char *testGroups[] = 
  {"Group1", "Group2", "Group3", "Group4"};

const int MAX_GROUPS = sizeof(testGroups)/sizeof(testGroups[0]);


////////////////////////////////////////////////////////////
//CPhoneEntry
////////////////////////////////////////////////////////////
struct CPhoneEntry
  {
  char name[MAX_LEN+1];  //11
  char phone[14+1];      //15
  char group[10+1];      //11
  int key;               // 4
  CPhoneEntry *next;     // 4
  };                     //45 


////////////////////////////////////////////////////////////
//CPhoneBook
////////////////////////////////////////////////////////////
// CPhoneBook myList;

class CPhoneBook
  {
  private:
    CPhoneEntry *first;
    CPhoneEntry *last;
    int count;
  public:
    CPhoneEntry * addressOfEntryAt(int pos) const;
  public:
    CPhoneBook(void);
      // CPhoneBook myList;
    bool insertAtEnd(char name[], char phone[], char group[], int key);
      // myList.insertAtEnd("Bob", "231-6672", "G1", 3);
    void display(void) const;
      // myList.display();
    void deleteAll(void);
      // myList.deleteAll();
    ~CPhoneBook(void);
      // {CPhoneBook myList; ...} //
    CPhoneBook(char ch);
      // CPhoneBook myList('r');
    void sortByName(void) const;
      // myList.sortByName();
    bool isSortedByName(void) const;
      // if ( myList.isSortedByName() ) ...
    void displayReverse(void) const;
      // yourList.displayReverse();
    void displayReverse2(void) const;
      // yourList.displayReverse2();
      // x.displayReverse2();
    friend ostream & operator << (ostream &os, const CPhoneBook &list);
      // cout << myList << endl;
    CPhoneEntry * searchByName(char name[]);
      // p = myList.searchByName("John");
    bool insertAtHead(char name[], char phone[], char group[], int key);
      // myList.insertAtHead("Bob", "231-6672", "G1", 3);
    CPhoneBook(const CPhoneBook &aBook);
      // CPhoneBook yourList(myList);
    CPhoneBook & operator = (const CPhoneBook &list);
      // myList = yourList;
    void displayWithAddresses(void) const;
      // myList.displayWithAddresses();
    CPhoneBook(int n);
      // CPhoneBook hisList(5);
    bool deleteByAddress(CPhoneEntry *p);
      //myList.deleteByAddress(p);
    bool deleteByName(char name[]);
      //myList.deleteByName("John");
    int deleteAllByName(char name[]);
      //myList.deleteAllByName("John");
    bool deleteByPosition(int pos);
      //myList.deleteByPosition(i);
    bool searchReplaceByName(char nameOld[], char nameNew[]) const;
      // myList.searchReplaceByName("John", "Tom");
    int searchReplaceAllByName(char nameOld[], char nameNew[]) const;
      // myList.searchReplaceAllByName("John", "Tom");
    int deleteDuplicates(void);
      // myList.deleteDuplicates();
    void combine (const CPhoneBook &list);
      //list1.combine(list2);
    bool operator == (const CPhoneBook &list) const;
      //if (list1== list2) ...p#6
    void shuffle(void) const; //extra credit
      //list1.shuffle();
  };


////////////////////////////////////////////////////////////
//void CPhoneBook::combine (const CPhoneBook &list)
////////////////////////////////////////////////////////////
//list1.combine(list2)
/*
------- ------ +-------
this    list   |action
------- ------ +-------
empty   empty  |nothing
nempty  empty  |nothing
empty   nempty |combine
nempty  nempty |combine

if the list is empty then 
    exit function
  else
    insert all the elements from list to this list

*/
void CPhoneBook::combine (const CPhoneBook &list)
  {
  if (0 == list.count) return;

  CPhoneEntry *p;
  
  p = list.first;

  while (p != NULL)
    {
    this->insertAtEnd(p->name, p->phone, p->group, p->key);
    p = p->next;
    }
  }


////////////////////////////////////////////////////////////
//d void testCombine(void)
////////////////////////////////////////////////////////////
void testCombine(void)
  {
  cout << "Testing combine(yourList);\n";
  cout << "--------------------------\n";
  char ch;
  do
    {
    CPhoneBook myList('r'), yourList('r');

    cout << "myList:\n" << myList;
    cout << "yourList:\n" << yourList;

    myList.combine(yourList);
    cout << "After myList.combine(yourList);\n";
      
    cout << "myList:\n" << myList;
    cout << "yourList:\n" << yourList;
    cin >> ch;
    }
    while (ch != '0');
  }


////////////////////////////////////////////////////////////
// void shuffle(void)
////////////////////////////////////////////////////////////
  // Extra credit
  //void shuffle(void); //member
  //reorganize randomly, hash, scatter
  //void testShuffle(void); //not a member function
  /*
  do the following forever
    CPhoneBook list('r');
    cout << "Original:\n" << list;
    list.shuffle();
    cout << "Shuffled:\n" << list;
    until '0' entered

  Plan1:
  pick two random nodes and swap values, do it 2*count times

  Plan2:
  do the following 2*count times
    Pick two random positions from [0,count-1]
    Convert positions to addresses
    Swap nodes at those addresses
    end do

  Plan3:
  p1 = first
  p2 = last
  s1: pick from [head, tail]
  if head swap the nodes at p1 and p2
  advance p1
  retreat p2
  if p1 or p2 = null then exit else go to s1

  

////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
//overload == operator to compare two phone lists
//testOperatorEqual
/*
project #6
Without sorting
CPhoneBook list1('r'), list2('r');
display list1 and list2
if (list1 == list2) then display "equal" else "not equal"
list1 = list2
display list1 and list2
if (list1 == list2) then display "equal" else "not equal"
do the above 10 times
*/



////////////////////////////////////////////////////////////
//operator ==
////////////////////////////////////////////////////////////
/* comparing the list pointed to by this and the list otherList
   compare counts  this->count  otherList.count
   if counts are not equal return false
   if counts are zero return true
   let p1 point to the first node of the list pointed to by this
   let p2 point to the first node of the otherList

   while p1 <> NULL
     compare all the fields pointed to by p1 and p2
     if any two fields are not equal then return false
     ...
     advance p1
     advance p2
     end while

   return true
*/



////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
/*
void testOperatorEqual(void)
  {
  cout << "Testing operator ==\n";
  cout << "-------------------\n";
  char ch;
  do
    {
    CPhoneBook list1('r'), list2('r');
    cout << "list1=\n" << list1;
    cout << "list2=\n" << list2;

    if (list1 == list2) 
      cout << "Lists are equal\n";
    else 
      cout << "Lists are NOT equal\n";

    list1 = list2;

    cout << "list1=\n" << list1;
    cout << "list2=\n" << list2;

    if (list1 == list2) 
      cout << "Lists are equal\n";
    else 
      cout << "Lists are not equal\n";

    cin >> ch;
    }
    while (ch != '0');
  }
*/

////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
/*
bool DeleteByAddress(CPhoneEntry *p)
Possibility         Action
-------------       ----------
Empty List          false
p is NULL           false
p is not in list    false
single item         delete, true
first item          delete, true
last item           delete, true
between two         delete, true

Empty List
----------
if first is null then
  return false
  end if


p is NULL
---------
if p is null then
  return false
  end if


p is not in list
----------------
found = false
q = first

while (q != null)
  if p = q then then found = true, break
  advance q
  wend

if found is false then 
  return false
  end if



single item
-----------
if first = last  then
  if p = first then 
      delete p
      first = last = null
      count = 0
      return true
    else
      return false
    end if

  
first item
----------
if p = first then
  advance first
  delete p
  count--
  return true
  end if


last item
---------
if p = last then
  make q point to node left of p
  make q point to null
  last = q
  delete p
  count--
  return true
  end if

between two
-----------
if p <> last p <> first then
  make q point to node left of p
  make q point to next of p
  delete p
  count--
  return true
  end if


*/
////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
bool CPhoneBook::deleteByAddress(CPhoneEntry *p)
  {
  //empty list
  if (NULL == first)
      return false;

  //p is NULL
  if (NULL == p)
      return false;

  //first item or only item
  if (p == first)
    {
    first = first->next;
    delete p;
    if (NULL == first)
      last = NULL;
    count--;
    return true;
    }

  //search for node at p
  CPhoneEntry *q;
  q = first;
  while (p != q->next)
    {
    q = q->next;
    if (NULL == q)  //node not in list
      return false;
    }
  
  //node in the list
  q->next = p->next;
  if (p == last) //last node
    last = q;
  count--;
  delete p;
  return true;
 
  }


////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
void testDeleteByAddress(void)
  {
  cout << "Testing deleteByAddress =\n";
  cout << "-------------------------\n";
  char ch;
  do
    {
    switch (rand()%7)
      {
      case 0: //empty list
        {
        cout << "case 0:\n";
        CPhoneBook myList;
        CPhoneEntry *p = new CPhoneEntry;
        myList.displayWithAddresses();
        cout << "Node to be deleted at " << p << endl;
        bool result = myList.deleteByAddress(p);
        if (result) 
            cout << "delete successful\n";
          else
            cout << "delete not successful\n";
        myList.displayWithAddresses();
        delete p;
        break;
        }
      case 1: //1 p is NULL
        {
        cout << "case 1:\n";
        CPhoneBook myList('r');
        CPhoneEntry *p = NULL;
        myList.displayWithAddresses();
        cout << "Node to be deleted at " << p << endl;
        bool result = myList.deleteByAddress(p);
        if (result) 
            cout << "delete successful\n";
          else
            cout << "delete not successful\n";
        myList.displayWithAddresses();
        break;
        }
      case 2: //2 p is not in list
        {
        cout << "case 2:\n";
        CPhoneBook myList('r');
        CPhoneEntry *p = new CPhoneEntry;
        myList.displayWithAddresses();
        cout << "Node to be deleted at " << p << endl;
        bool result = myList.deleteByAddress(p);
        if (result) 
            cout << "delete successful\n";
          else
            cout << "delete not successful\n";
        myList.displayWithAddresses();
        delete p;
        break;
        }
      case 3: //3 single item
        {
        cout << "case 3:\n";
        CPhoneBook myList(1);
        CPhoneEntry *p;
        p = myList.addressOfEntryAt(0);
        myList.displayWithAddresses();
        cout << "Node to be deleted at " << p << endl;
        bool result = myList.deleteByAddress(p);
        if (result) 
            cout << "delete successful\n";
          else
            cout << "delete not successful\n";
        myList.displayWithAddresses();
        break;
        }
      case 4: //4 first item
        {
        cout << "case 4:\n";
        CPhoneBook myList(2+rand()%5);
        CPhoneEntry *p;
        p = myList.addressOfEntryAt(0);
        myList.displayWithAddresses();
        cout << "Node to be deleted at " << p << endl;
        bool result = myList.deleteByAddress(p);
        if (result) 
            cout << "delete successful\n";
          else
            cout << "delete not successful\n";
        myList.displayWithAddresses();
        break;
        }
      case 5:  //5 last item 
        {
        cout << "case 5:\n";
        int n = 2+rand()%5;
        CPhoneBook myList(n);
        CPhoneEntry *p;
        p = myList.addressOfEntryAt(n-1);
        myList.displayWithAddresses();
        cout << "Node to be deleted at " << p << endl;
        bool result = myList.deleteByAddress(p);
        if (result) 
            cout << "delete successful\n";
          else
            cout << "delete not successful\n";
        myList.displayWithAddresses();
        break;
        }
      case 6: //6 between two nodes
        {
        cout << "case 6:\n";
        int n = 5;
        CPhoneBook myList(n);
        CPhoneEntry *p;
        p = myList.addressOfEntryAt(1 + rand()%3);
        myList.displayWithAddresses();
        cout << "Node to be deleted at " << p << endl;
        bool result = myList.deleteByAddress(p);
        if (result) 
            cout << "delete successful\n";
          else
            cout << "delete not successful\n";
        myList.displayWithAddresses();
        break;
        }
      default:;
      }
    
    
    cin >> ch;
    }
    while (ch != '0');
  }


////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
CPhoneBook & CPhoneBook::operator = (const CPhoneBook &list)
  {
  if (this->count > 0)
      this->deleteAll();

  CPhoneEntry *p;
  p = list.first;
  
  while (p != NULL)
    {
    this->insertAtEnd(p->name, p->phone, p->group, p->key);
    p = p->next;
    }
  
  return *this;
  }


////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
void testOperatorAssign(void)
  {
  cout << "Testing operator =\n";
  cout << "------------------\n";
  char ch;
  do
    {
    CPhoneBook myList('r'), yourList, hisList;
    cout << "myList\n" << myList;
    
    hisList = yourList = myList;
    cout << "yourList\n" << yourList;
    cout << "hisList\n"  << hisList;
    cin >> ch;
    }
    while (ch != '0');
  }


////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
CPhoneBook::CPhoneBook(const CPhoneBook &aBook)
  {
  cout << "copy constructor called\n";
  count = 0; 
  // or this->count = 0; 
  // or (*this).count = 0;
  first = NULL;

  CPhoneEntry *p;
  p = aBook.first;
  
  while (p != NULL)
    {
    insertAtEnd(p->name, p->phone, p->group, p->key);
    // or this->insertAtEnd(p->name, p->phone, p->group, p->key);
    p = p->next;
    }
  }


////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
void testConstructorCopy(void)
  {
  cout << "Testing CPhoneBook myList(yourList);\n";
  cout << "------------------------------\n";
  char ch;
  do
    {
    CPhoneBook myList('r');
    cout << myList;
    CPhoneBook yourList(myList);
    cout << yourList;
    cin >> ch;
    }
    while (ch != '0');
  }


////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
void testInsertAtHead(void)
  {
    {
    CPhoneBook myBook;
    myBook.display();
    myBook.insertAtHead("John", "231-7000", "friend", 1);
    myBook.display();
    myBook.insertAtHead("Tom",  "231-7001", "enemy", 1);
    myBook.display();
    }

  }


////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
bool CPhoneBook::insertAtHead(char name[], char phone[], char group[], int key)
  {
  CPhoneEntry *p;

  p = new CPhoneEntry;
  if (NULL == p)
      return false;

  strcpy(p->name, name);
  strcpy(p->phone, phone);
  strcpy(p->group, group);
  p->key = key;

  /*
  if (NULL == first)
      {
      first = p;
      last  = p;
      p->next = NULL;
      }
    else
      {
      p->next = first;
      first = p;
      }
  */

  p->next = first;
  first = p;

  if (NULL == last)
      last = p;

  count++;
  return true;
  }



////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// p=first
// if the found return p
// else advance p and go to prev statement
/*
   p = first
   while p <> NULL
     if at p the name we are looking for then
         return p
       else
         advance p
     end while

   return NULL
*/
////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
void testSearchByName(void)
  {
  CPhoneBook b1('r');
  char tName[MAX_LEN+1];
  cout << b1;
  for (int i=1; i<=TEST_COUNT; i++)
    {
    //strcpy(tName, testNames[rand()%MAX_NAMES]);
    cin >> tName;
    //cout << tName << " is at " << b1.searchByName(tName)->key <<endl;
    cout << tName << " is at " << b1.searchByName(tName) << endl;
    }
  }


////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
/* for a given name
   return the address of the first node holding the name
*/
CPhoneEntry * CPhoneBook::searchByName(char name[])
  {
  CPhoneEntry *p;

  p = first;
  while (p != NULL)
    {
    if ((strcmp(p->name, name)==0))
        return p;
      else
        p = p->next;
    }

  return NULL;
  }

////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
//CPhoneEntry * CPhoneBook::addressOfEntryAt(int pos)
//Returns the address of a node at position [0 to count-1]

//Possibilities   return
//-------------   ------
//Empty list      NULL
//Nonempty
//  pos < 0         NULL
//  pos >= count    NULL
//  pos=0           address of first node
//  pos [0,count-1] address of the node by advancing pos times

CPhoneEntry * CPhoneBook::addressOfEntryAt(int pos) const
  {
  if (count <= 0)
      return NULL;
  if (pos < 0)
      return NULL;
  if (pos >= count)
      return NULL;

  CPhoneEntry *p;
  p = first;

  for (int steps=1; steps<=pos; steps++)
    p = p->next;

  return p;
  }


////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
//void CPhoneBook::displayReverse(void)
void CPhoneBook::displayReverse2(void) const
  {
  for (int pos=count-1; pos>=0; pos--)
    {
    CPhoneEntry *p;  //better if put outside the loop
    p = addressOfEntryAt(pos);

    cout << p->name << ", ";
    cout << p->phone << ", ";
    cout << p->group << ", ";
    cout << p->key << endl;
    }

  cout << endl;
  }



////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
void testDisplayReverse2(void)
  {
  for (int i=1; i<=TEST_COUNT; i++)
    {
    cout << "Test #" << i << ": ";
    CPhoneBook b1('r');
    cout << "Original\n";
    b1.display();
    cout << "Reverse\n";
    b1.displayReverse2();
    }
  }


////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
//void CPhoneBook::displayReverse(void)
/* start from the first, display the last node
   start from the first, display next to the last
   ...
   until first displayed

  for pos=count to 1 step -1 do the following
    point to first
    advance pointer pos-1 times
    display the pointed node

*/
void CPhoneBook::displayReverse(void) const
  {
  CPhoneEntry *p;

  for (int pos=count; pos>0; pos--)
    {
    p = first;

    for (int steps=1; steps<=pos-1; steps++)
      p = p->next;

    cout << p->name << ", ";
    cout << p->phone << ", ";
    cout << p->group << ", ";
    cout << p->key << endl;
    }

  cout << endl;
  }


////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
void testDisplayReverse(void)
  {
  for (int i=1; i<=TEST_COUNT; i++)
    {
    cout << "Test #" << i << ": ";
    CPhoneBook b1('r');
    cout << "Original\n";
    b1.display();
    cout << "Reverse\n";
    b1.displayReverse();
    }
  }


////////////////////////////////////////////////////////////
//swap the records d
//do not swap next fields
////////////////////////////////////////////////////////////
void swap(CPhoneEntry &e1, CPhoneEntry &e2)
  {
  char tName[MAX_LEN+1];
  char tPhone[14+1];
  char tGroup[10+1];
  int  tKey;
  //plug the e1 and e2 at the right places
  strcpy(tName, e1.name);
  strcpy(e1.name, e2.name);
  strcpy(e2.name, tName);

  strcpy(tPhone, e1.phone);
  strcpy(e1.phone, e2.phone);
  strcpy(e2.phone, tPhone);

  strcpy(tGroup, e1.group);
  strcpy(e1.group, e2.group);
  strcpy(e2.group, tGroup);

  tKey = e1.key;
  e1.key = e2.key;
  e2.key = tKey;
  }


////////////////////////////////////////////////////////////
//swap the records through the pointers d
//do not swap the next fields
////////////////////////////////////////////////////////////
void swap(CPhoneEntry *p, CPhoneEntry *q)
  {
  char tName[MAX_LEN+1];
  char tPhone[14+1];
  char tGroup[10+1];
  int  tKey;

  //swap name fields
  strcpy(tName, p->name);
  strcpy(p->name, q->name);
  strcpy(q->name, tName);

  //swap phone fields
  strcpy(tPhone, p->phone);
  strcpy(p->phone, q->phone);
  strcpy(q->phone, tPhone);

  //swap group fields
  strcpy(tGroup, p->group);
  strcpy(p->group, q->group);
  strcpy(q->group, tGroup);

  //swap key fields
  tKey = p->key;
  p->key = q->key;
  q->key = tKey;

  //do not swap next fields

  }


////////////////////////////////////////////////////////////
//bool CPhoneBook::isSortedByName(void) d
////////////////////////////////////////////////////////////
//Go from left to right
//  if a pair is found to be out of order
//     then return false 
//return true
bool CPhoneBook::isSortedByName(void) const
  {
  CPhoneEntry *p, *q;

  if (first == last)
      return true;

  p = first;
  q = p->next;
  while (q != NULL)
    {
    if ((strcmp(p->name, q->name)>0))
        return false;
    p = q; // or p = p->next
    q = q->next;
    }

  return true;
  }


////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
void testIsSortedByName(void)
  {
  //for (int i=0; i<TEST_COUNT; i++)
  //  {
    CPhoneBook b1('r');
    cout << "Original: " << b1;
    if (b1.isSortedByName())
        cout << "The list is SORTED\n";
      else
        cout << "The list is NOT SORTED\n";

    b1.sortByName();
    cout << "Sorted:   "<< b1;
    if (b1.isSortedByName())
        cout << "The list is SORTED\n";
      else
        cout << "The list is NOT SORTED\n";
  //  }
  }


////////////////////////////////////////////////////////////
//void CPhoneBook::sortByName(void) d
////////////////////////////////////////////////////////////
//Algorithm
/*
  do the following
    check pairs from left to right and put them in order
    until no swap made

  if first = last then exit function

  do the following
    set sorted = true
    p = first
    q = p->next

    while q <> null
      if name at p > name at q then
          swap records at p and q except the pointers
          sorted = false
          end if
      p = q (or p = p->next)
      q = q->next
      end while

    while not sorted
*/
void CPhoneBook::sortByName(void) const
  {
  if (first == last) return;

  bool sorted;
  CPhoneEntry *p, *q;

  do 
    {
    sorted = true;
    p = first;
    q = p->next;

    while (q != NULL)
      {
      if ((strcmp(p->name, q->name)>0))
          {
          //swap records at p and q except the pointers
          //swap(p, q); //using pointers
          swap(*p, *q); //using records
          //swap(r1, r2); 
          sorted = false;
          }
      p = q; // or p = p->next
      q = q->next;
      }

    }
    while (!sorted);
  }


////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
void testSortByName(void)
  {
  //for (int i=0; i<TEST_COUNT; i++)
  //  {
    CPhoneBook b1('r'), b2;
    cout << "Original: " << b1;
    b1.sortByName();
    cout << "Sorted:   "<< b1;
    b2 = b1;
    cout << b2;
  //  }
  }


////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
ostream & operator << (ostream &dan, const CPhoneBook &list)
  {
  CPhoneEntry *p;

  dan << "Phonebook[" << list.count << "]\n";

  p = list.first;

  while (p != NULL)
    {
    dan << p->name << ", ";
    dan << p->phone << ", ";
    dan << p->group << ", ";
    dan << p->key << endl;
    p = p->next;
    };

  return dan;
  }



////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
void testOperatorOutput(void)
  {
  //for (int i=0; i<TEST_COUNT; i++)
  //  {
    CPhoneBook b1('i'), b2('r'), b3(3);
    cout << b1 << b2 << b3;
  //  }
  }


////////////////////////////////////////////////////////////
//Constructor for CPhoneBook d
////////////////////////////////////////////////////////////
//'r' random elements           done
//'u' distinct random elements  ??
//'s' sorted list               ??
//'i' enter from the keyboard   done
CPhoneBook::CPhoneBook(char ch)
  {
  cout << "constructor(ch) called\n";
  count = 0;
  first = NULL;
  last = NULL;

  if ('r' == ch)
      {
      char rName[MAX_LEN+1];
      char rPhone[14+1];
      char rGroup[10+1];
      int  rKey;

      int n = rand()%(MAX_COUNT+1);

      for(; n>0; n--)
        {
        strcpy(rName, testNames[rand()%MAX_NAMES]);
        strcpy(rPhone, testPhones[rand()%MAX_PHONES]);
        strcpy(rGroup, testGroups[rand()%MAX_GROUPS]);
        rKey = masterKey++;
        insertAtEnd(rName, rPhone, rGroup, rKey);
        }
      }
  else if ('i' == ch)
      {
      char rName[MAX_LEN+1];
      char rPhone[14+1];
      char rGroup[10+1];
      int  rKey;
      
      int n;

      cout << "Enter a value for n: ";
      cin >> n;

      for(; n>0; n--)
        {
        cout << "name: "; cin >> rName;

        cout << "phone: "; cin >> rPhone;
        cout << "group: "; cin >> rGroup;

        rKey = masterKey++;

        insertAtEnd(rName, rPhone, rGroup, rKey);
        }
      }
  }


////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
void testCPhoneBookConstructorCh(void)
  {
  for (int i=0; i<2*TEST_COUNT; i++)
    {
    CPhoneBook b1('r');
    b1.display();
    }

  CPhoneBook b1('i');
  b1.display();
  }


////////////////////////////////////////////////////////////
//Constructor for CPhoneBook d
////////////////////////////////////////////////////////////
// CPhoneBook myList(8);

CPhoneBook::CPhoneBook(int n)
  {
  cout << "constructor(n) called\n";
  count = 0;
  first = NULL;
  last = NULL;

  char rName[MAX_LEN+1];
  char rPhone[14+1];
  char rGroup[10+1];
  int  rKey;

  for( ; n>0; n--)
    {
    strcpy(rName, testNames[rand()%MAX_NAMES]);
    strcpy(rPhone, testPhones[rand()%MAX_PHONES]);
    strcpy(rGroup, testGroups[rand()%MAX_GROUPS]);
    rKey = masterKey++;
    insertAtEnd(rName, rPhone, rGroup, rKey);
    }
  }


////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
void testCPhoneBookConstructor(void)
  {
  for (int i=0; i<2*TEST_COUNT; i++)
    {
    CPhoneBook b1(i);
    b1.display();
    }
  }


////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
CPhoneBook::~CPhoneBook(void)
  {
  cout << "destructor called\n";
  //deleteAll();
  this->deleteAll();
  }


////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
void testDestructor(void)
  {
  cout << "testDestructor()\n";
  cout << "================\n";

    {
    CPhoneBook myBook;
    myBook.display();
    }
    
    {
    CPhoneBook myBook;
    myBook.display();
    }

  }


////////////////////////////////////////////////////////////
//void CPhoneBook::deleteAll(void) d
////////////////////////////////////////////////////////////
//deletes all the nodes from the linked list
void CPhoneBook::deleteAll(void) 
  {
  while (first != NULL)
    {
    last = first->next;
    delete first;
    first = last;
    }

  count = 0;
  }


////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
void testDeleteAll(void)
  {
  cout << "testDeleteAll()\n";
  cout << "===============\n";
  CPhoneBook myBook;
  myBook.display();
  myBook.deleteAll();
  myBook.display();
  myBook.insertAtEnd("John", "231-7000", "friend", 1);
  myBook.display();
  myBook.insertAtEnd("Tom",  "231-7001", "enemy", 1);
  myBook.display();
  myBook.deleteAll();
  myBook.display();
  }


////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
void CPhoneBook::display(void) const
  {
  CPhoneEntry *p;

  cout << "Phonebook[" << count << "]\n";

  p = first;
  while (p != NULL)
    {
    cout << p->name << ", ";
    cout << p->phone << ", ";
    cout << p->group << ", ";
    cout << p->key << endl;
    
    p = p->next;
    };
  }


////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
void CPhoneBook::displayWithAddresses(void) const
  {
  CPhoneEntry *p;

  cout << "Phonebook[" << count << "]\n";

  p = first;
  while (p != NULL)
    {
    cout << p->name << ", ";
    cout << p->phone << ", ";
    cout << p->group << ", ";
    cout << p->key << ", ";
    cout << "at " << p << endl;

    p = p->next;
    };
  }


////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
void testDisplayWithAddresses(void)
  {
    {
    CPhoneBook myBook;
    myBook.displayWithAddresses();
    myBook.insertAtEnd("John", "231-7000", "friend", 1);
    myBook.displayWithAddresses();
    myBook.insertAtEnd("Tom",  "231-7001", "enemy", 1);
    myBook.displayWithAddresses();
    }
  }

////////////////////////////////////////////////////////////
// insertAtEnd d
////////////////////////////////////////////////////////////
bool CPhoneBook::insertAtEnd(char name[], char phone[], char group[], int key)
  {
  CPhoneEntry *p;

  p = new CPhoneEntry;
  if (NULL == p)
      return false;

  strcpy(p->name, name); //copy name to name field of new node
  //strcpy((*p).name, name);
  strcpy(p->phone, phone);
  strcpy(p->group, group);
  p->key = key;
  //(*p).key = key;
  p->next = NULL;

  if (NULL == first)
      {
      first = p;
      last  = p;
      }
    else
      {
      last->next = p; //make last node point to new node
      //(*last).next = p;
      last = p;
      }

  count++;
  return true;
  }


////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
void testInsertAtEnd(void)
  {
    {
    CPhoneBook myBook;
    myBook.display();
    myBook.insertAtEnd("John", "231-7000", "friend", 1);
    myBook.display();
    myBook.insertAtEnd("Tom",  "231-7001", "enemy", 1);
    myBook.display();
    }

    {
    CPhoneBook myBook;
    myBook.display();
    }
  }


////////////////////////////////////////////////////////////
//CPhoneBook constructor
////////////////////////////////////////////////////////////
CPhoneBook::CPhoneBook(void)
  {
  cout << "constructor called\n";
  count = 0;
  first = NULL;
  last  = NULL;
  }

////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
void main(void)
  {
  //testInsertAtEnd();
  //testDisplayWithAddresses();
  //testDeleteAll();
  //testDestructor();
  //testCPhoneBookConstructor();
  //testCPhoneBookConstructorCh();
  //testOperatorOutput();
  //testSortByName();
  //testIsSortedByName();
  //testDisplayReverse();
  //testDisplayReverse2();
  //testSearchByName();
  //testInsertAtHead();
  //testConstructorCopy();
  //testOperatorAssign();
  //testDeleteByAddress();
  testCombine();
  }