Intro CS I/fall2019/address

From Maryville College CS Wiki
Jump to: navigation, search

Makefile

File: Makefile

TARGETS=address

all: $(TARGETS)
address: address_book.o contact.o contact_info.o iofun.o main.o
	g++ -o $@ $^
address_book.o: address_book.h address_book.cpp
contact.o: contact.h contact.cpp
contact_info.o: contact_info.h contact_info.cpp
iofun.o: iofun.h iofun.cpp
main.o: main.cpp

clean:
	rm -f a.out *.o $(TARGETS)

iofun.h

File: iofun.h

// IO functions
#include <string>

//prototypes
int prompt_int(std::string prompt);
int prompt_int_range(std::string prompt, int min, int max);
double prompt_double(std::string prompt);
double prompt_double_range(std::string prompt, double min, double max);


iofun.cpp

File: iofun.cpp

#include <iostream>
#include <string>
#include <limits>
#include "iofun.h"

using namespace std;

// Prompt for an integer.  Force the user to give us a number
// or end the file.
int prompt_int(string prompt)
{
    int n;  //number

    //loop until we get a valid input
    for(;;) {
        //try to get the number
        cout << prompt;
        cin >> n;

        //if we succeed, or the input ends, return
        if(cin or cin.eof()) {
            return n;
        }

        //something went wrong
        cout << "Invalid entry. Please Try Again" << endl;
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    } 
}


// Prompt the user for an integer within a given range
// only return valid output, or return on eof
int prompt_int_range(string prompt, int min, int max) 
{
    int n;  //number we read

    //loop until we get a valid input
    for(;;) {
        n = prompt_int(prompt);

        //return valid integers
        if(n >= min and n <= max) {
            return n;
        }

        //return on eof
        if(cin.eof()) {
            return n;
        }

        //print an error message
        cout << "Entry out of range.  Please try again." << endl;
    }
}



// Prompt for a dobule.  Force the user to give us a number
// or end the file.
double prompt_double(string prompt)
{
    double n;  //number

    //loop until we get a valid input
    for(;;) {
        //try to get the number
        cout << prompt;
        cin >> n;

        //if we succeed, or the input ends, return
        if(cin or cin.eof()) {
            return n;
        }

        //something went wrong
        cout << "Invalid entry. Please Try Again" << endl;
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    } 
}


// Prompt the user for an double within a given range
// only return valid output, or return on eof
double prompt_double_range(string prompt, double min, double max) 
{
    double n;  //number we read

    //loop until we get a valid input
    for(;;) {
        n = prompt_double(prompt);

        //return valid doubleegers
        if(n >= min and n <= max) {
            return n;
        }

        //return on eof
        if(cin.eof()) {
            return n;
        }

        //prdouble an error message
        cout << "Entry out of range.  Please try again." << endl;
    }
}


contact.h

File: contact.h

// Class definition for the contact class
#ifndef CONTACT_H
#define CONTACT_H

#include <vector>
#include <string>
#include "contact_info.h"

class Contact 
{
public:
    //Constructors
    Contact();
    Contact(std::string name);

    //add information to the contact
    void add(const Contact_Info& info);

    //get the name of the contact
    std::string get_name();

    //set the name of the contact
    void set_name(const std::string& name);

    //return the number of info items in the contact
    int get_size();

    //return the indexed contact info (indexed from 0)
    Contact_Info get_info(int index);

    //change contact info
    void update_info(int index, const Contact_Info& info);

    //remove the contact info
    void remove_info(int index);

private:
    //the contact information
    std::vector<Contact_Info>  info;

    //the name of the contact
    std::string name;
};

#endif


contact.cpp

File: contact.cpp

//The implementation of the Contact class
#include <vector>
#include "contact.h"
#include "contact_info.h"

//Constructors
Contact::Contact()
{
    //this space left intentionally blank
}


Contact::Contact(std::string name)
{
    this->name = name;
}


//add information to the contact
void Contact::add(const Contact_Info& info)
{
    this->info.push_back(info);
}


//get the name of the contact
std::string Contact::get_name()
{
    return name;
}


//set the name of the contact
void Contact::set_name(const std::string& name)
{
    this->name = name;
}


//return the number of info items in the contact
int Contact::get_size()
{
    return info.size();
}


//return the indexed contact info (indexed from 0)
Contact_Info Contact::get_info(int index)
{
    return info[index];
}

//change contact info
void Contact::update_info(int index, const Contact_Info& info)
{
    this->info[index] = info;
}


//remove the contact info
void Contact::remove_info(int index)
{
    info.erase(info.begin() + index);
}


address_book.h

File: address_book.h

// Class definition for the Address_Book class.
#ifndef ADDRESS_BOOK_H
#define ADDRESS_BOOK_H
#include <string>
#include <vector>
#include "contact.h"

class Address_Book
{
public:
    //constructor
    Address_Book();

    //add a contact
    void add(const Contact& contact);

    //get the number of contacts
    int get_size();

    //get the contact at the index
    Contact get_contact(int index);

    //update the contact
    void update_contact(int index, const Contact& contact);

    //remove a contact
    void remove_contact(int index);
private:
    //list of contacts
    std::vector<Contact> contact_list;
};
#endif


address_book.cpp

File: address_book.cpp

#include "address_book.h"


//constructor
Address_Book::Address_Book()
{

}


//add a contact
void Address_Book::add(const Contact& contact)
{
    contact_list.push_back(contact);
}


//get the number of contacts
int Address_Book::get_size()
{
    return contact_list.size();
}


//get the contact at the index
Contact Address_Book::get_contact(int index)
{
    return contact_list[index];
}


//update the contact
void Address_Book::update_contact(int index, const Contact& contact)
{
    contact_list[index] = contact;
}


//remove a contact
void Address_Book::remove_contact(int index)
{
    contact_list.erase(contact_list.begin()+index);
}


contact_info.h

File: contact_info.h

// Class definition for the Contact_Info class.
#ifndef CONTACT_INFO_H
#define CONTACT_INFO_H
#include <string>

class Contact_Info
{
public:
    //constructors
    Contact_Info();
    Contact_Info(const std::string &label, const std::string &phone, const std::string &address);

    //accessors
    std::string get_label();
    std::string get_phone();
    std::string get_address();


    //mutators
    void set_label(const std::string &label);
    void set_phone(const std::string &phone);
    void set_address(const std::string &address);


private:
    std::string label;
    std::string phone;
    std::string address;
};
#endif


contact_info.cpp

File: contact_info.cpp

#include "contact_info.h"


//constructors
Contact_Info::Contact_Info()
{

}


Contact_Info::Contact_Info(const std::string &label, const std::string &phone, const std::string &address)
{
    this->label = label;
    this->phone = phone;
    this->address = address;
}


//accessors
std::string Contact_Info::get_label()
{
    return label;
}


std::string Contact_Info::get_phone()
{
    return phone;
}


std::string Contact_Info::get_address()
{
    return address;
}


//mutators
void Contact_Info::set_label(const std::string &label)
{
    this->label = label;
}


void Contact_Info::set_phone(const std::string &phone)
{
    this->phone = phone;
}


void Contact_Info::set_address(const std::string &address)
{
    this->address = address;
}


main.cpp

File: main.cpp

// Main program for the address book program
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include "iofun.h"
#include "address_book.h"
#include "contact_info.h"
#include "contact.h"

using namespace std;

//prototypes
int menu();
void load(Address_Book &book);
void save(Address_Book &book);
void view_contact_list(Address_Book &book);
void add_contact(Address_Book &book);
void remove_contact(Address_Book &book);
void edit_contact(Contact &contact);
void edit_info(Contact_Info &info);
int contact_menu(Address_Book &book);

int main()
{
    enum Menu_Choice{VIEW=1, ADD, REMOVE, EXIT};
    Address_Book book;
    int choice;

    //retore from the file
    load(book);

    do {
        choice = menu();

        //do the menu selection
        if(choice == VIEW) {
            view_contact_list(book);
        } else if(choice == ADD) {
            add_contact(book);
        } else if(choice == REMOVE) {
            remove_contact(book);
        }
    } while(choice != EXIT);

    //save the address book
    save(book);
}


//display a menu and return the user's selection
int menu()
{
    ostringstream os;

    //construct the menu
    os << endl
       << "\t   MAIN MENU" << endl
       << "\t1.) View Contact List" << endl
       << "\t2.) Add Contact" << endl
       << "\t3.) Remove Contact" << endl
       << "\t4.) Exit" << endl
       << endl
       << "\tYour Choice? ";
    
    return prompt_int_range(os.str(), 1, 4);
}


//save to a file
void save(Address_Book &book)
{
    ofstream file;

    //open the file
    file.open("ADDRESS.DAT");
    if(not file) {
        cout << "Could not open file for writing" << endl;
        return;
    }

    //write the number of entries
    file << book.get_size() << endl;
    for(int i=0; i<book.get_size(); i++) {
        Contact contact = book.get_contact(i);

        //write the contact name
        file << contact.get_name() << endl;
        
        //write the number of contact info parts
        file << contact.get_size() << endl;
        for(int j=0; j<contact.get_size(); j++) {
            Contact_Info info = contact.get_info(j);
            file << info.get_label() << endl
                 << info.get_phone() << endl
                 << info.get_address() << endl;
        }
    }

    file.close();
}


//load address book from a file
void load(Address_Book &book)
{
    ifstream file;

    //open the file
    file.open("ADDRESS.DAT");
    if(not file) {
        return;
    }

    //read the number of entries
    int nc; 
    file >> nc;
    file.get(); //consume newline

    for(int i=0; i<nc; i++) {
        Contact contact;

        //get the name
        string name;
        getline(file, name);
        contact.set_name(name);

        //get the info entries
        int ni; //number of info entries
        file >> ni;
        file.get(); //consume newline

        for(int j=0; j<ni; j++) {
            string label, phone, address;
            getline(file, label);
            getline(file, phone);
            getline(file, address);

            //add via anonymous object
            contact.add(Contact_Info{label, phone, address});
        }

        //add the contact to the address book
        book.add(contact);
    }

    file.close();
}


//View the contact list
void view_contact_list(Address_Book &book)
{
    //get the contact
    int i = contact_menu(book);
    if(i < 0) {
        return;
    }
    Contact contact = book.get_contact(i);

    //edit the contact
    edit_contact(contact);
    book.update_contact(i, contact);
}


//Add a contact
void add_contact(Address_Book &book)
{
    string name;
    Contact contact;

    //get the name of the contact
    cout << "Name: ";
    if(cin.peek() == '\n') cin.get();
    getline(cin, name);

    //populate the contact
    contact.set_name(name);
    edit_contact(contact);

    //add the contact to the address book
    book.add(contact);
}


//Remove a contact
void remove_contact(Address_Book &book)
{
    int i = contact_menu(book);
    if(i < 0) {
        return;
    }
    book.remove_contact(i);
}


//Edit a contact
void edit_contact(Contact &contact)
{
    int choice;
    ostringstream os;

    //build the menu
    os << "1.) Add Information" << endl
       << "2.) Edit Information" << endl
       << "3.) Remove Information" << endl
       << "4.) Previous Menu" << endl
       << "Choice? ";
    string menu = os.str();
    
    do {
        //display the user information
        cout << contact.get_name() << endl;
        for(int i=0; i<contact.get_size(); i++) {
            Contact_Info info = contact.get_info(i);
            cout << left << setw(30) << info.get_label() 
                 << setw(20) << info.get_phone()
                 << info.get_address() << endl;
        }

        //get the choice
        choice = prompt_int_range(menu, 1, 4);

        //perform the choice
        if(choice == 1 ) {
            //edit the information
            Contact_Info info;
            edit_info(info);
            contact.add(info);
        } else if(choice == 2) {
            //skip empty info lists
            if(contact.get_size() == 0) {
                continue;
            }

            //get the entry to edit
            string prompt = "Which entry (1-" + to_string(contact.get_size()) + "): ";
            int index = prompt_int_range(prompt, 1, contact.get_size());

            //load up the info, edit, and replace
            Contact_Info info = contact.get_info(index-1);
            edit_info(info);
            contact.update_info(index-1, info);
        } else if(choice == 3) {
            //skip empty info lists
            if(contact.get_size() == 0) {
                continue;
            }

            //get the entry to edit
            string prompt = "Which entry (1-" + to_string(contact.get_size()) + "): ";
            int index = prompt_int_range(prompt, 1, contact.get_size());

            //reove the info
            contact.remove_info(index-1);
        }
    } while(choice != 4);
}

//Edit contact info
void edit_info(Contact_Info &info)
{
    string label;
    string phone;
    string address;

    //clear newlines (if needed)
    if(cin.peek() == '\n') cin.get();

    //get the information
    cout << "Label: ";
    getline(cin, label);
    info.set_label(label);

    cout << "Phone: ";
    getline(cin, phone);
    info.set_phone(phone);

    cout << "Address: ";
    getline(cin, address);
    info.set_address(address);
}


//select a contact
int contact_menu(Address_Book &book)
{
    ostringstream os;

    //check for empty contact list
    if(book.get_size() == 0) {
        cout << "No Contacts" << endl;
        return -1;
    }

    //display the contacts
    for(int i=0; i<book.get_size(); i++) {
        os << i+1 << ".) " << book.get_contact(i).get_name() << endl;
    }
    os << "Choice? ";

    return prompt_int_range(os.str(), 1, book.get_size())-1;
}