Lab 6: The office inventory -- sample solution

////////////////////////////////////////////////////////////////////////
// C++ Programming CS177, Spring 1997                                 //
// Lab 6. The Office Inventory -- sample answer                       //
// Roger Hartley                                                      //
////////////////////////////////////////////////////////////////////////

#include <string>
#include <vector>
#include <iostream.h>
#include <iomanip.h>

// the class that describes an item
class SupplyItem {
private:
  string description;
  int holding;
  float unitCost;
public:
  SupplyItem() {}
  SupplyItem(const string& d, const float uc) :
    description(d), unitCost(uc), holding(0) {} // set holding to zero
  float worth() { return holding * unitCost; }
  void change(int ch);
  string getDescription() { return description; }
  int getHolding() { return holding; }
  SupplyItem& operator=(SupplyItem rhs) {
    // this overloaded operator was necessary to get rid of some
    // compiler warning messages -- it could be omitted
    description = rhs.description;
    holding = rhs.holding;
    unitCost = rhs.unitCost;
    return *this;
  }
};

// the stock on hand is stored in a vector or items
class Stock {
private:
  vector<SupplyItem> supplies;
  int noItems;
public:
  Stock();
  void maintain(string&, int);
  void report();
};

// the application class
class Inventory {
private:
  Stock stock;
public:
  void run();
  void input(string&, int&);
};

void SupplyItem::change(int ch) {
  // only allow a chamge of stock holding if the result is positive
  if (holding + ch < 0)
    cout << "We don't have that many!" << endl;
  else
    holding += ch;
}
  

Stock::Stock() : supplies(10) {
  // the stock constructor sets up the "empty" inventory
  // the unit costs are passed to the SupplyItem constructor
  // as constants
  supplies[0] = SupplyItem(string("pencils"), 0.3);
  supplies[1] = SupplyItem(string("legal-pads"), 1.2);
  supplies[2] = SupplyItem(string("paper-clips"), 0.02);
  supplies[3] = SupplyItem(string("folders"), 0.03);
  supplies[4] = SupplyItem(string("pens"), 1.35);
  noItems = 5;
}

void Inventory::input(string& desc, int& amt) {
  // use reference parameters to allow values to be passed out of the
  // function
  cout << "Type an item name and a change in stock holding: ";
  cin >> desc >> amt;
}

void Stock::maintain(string& desc, int amt) {
  // stock maintenance needs a search thrpigh the vector to
  // see if the supply item description is present

  int i;
  for (i = 0; i < noItems; i++) 
    if (supplies[i].getDescription() == desc) {
      // the description is in the vector, so allow the change
      supplies[i].change(amt);
      cout << "OK" << endl;
      break;  // no need to search further
    }

  // if the items was not found, then signal an error
  if (i >= noItems)
    cout << "Sorry, we do not carry that item" << endl;
}

void Stock::report() {
  // display an inventory report
  cout << endl << "Stock holdings:" << endl << endl;

  float total = 0.0;
  for (int i = 0; i < noItems; i++) {
    total += supplies[i].worth();
    cout << setw(15) << setiosflags(ios::left) 
	 << supplies[i].getDescription().c_str()
	 << setw(6) << setiosflags(ios::right)
	 << supplies[i].getHolding() << endl;
  }

  // printing floating point numbers for money amounts needs 
  // the following arcana
  cout << setiosflags(ios::showpoint)  // make sure the decimal point is shown
       << setiosflags(ios::fixed)  // don't use scientific notation
       << setprecision(2);  // round up to show two decimal places if necessary
  cout << endl << "Total worth is $" << total << endl;
}

void Inventory::run() {
  // the top-level loop reads an input line and processes it immediately
  while (!cin.eof()) {
    string desc;
    int amt;
    input(desc, amt);
    stock.maintain(desc, amt);
  }
  // all the input is exhausted, so print the report
  stock.report();
}

int main() {
  // just make an inventory and run it
  Inventory inventory;
  inventory.run();
}