#include <iostream>
#include <stdexcept>
#include "keyed_bag4.h"

using namespace std;

int main() {
  keyed_bag4<int, double> k0;
  
  // Test dynamic allocation
  
  for (int i = 0; i < 1000; ++i)
    k0.insert(i, 1000*i);
  
  cout << endl;
  cout << "After 1000 insertions:" << endl;
  cout << "The bag k0 has " << k0.size() << " [1000] elements." << endl;
  cout << "The value of key 50,000 is " << k0.get(50000) << " [50]" << endl;
  cout << "k0.has_key(50000) returns " << k0.has_key(50000) << " [1]" << endl << endl;
  
  // Test the copy constructor
  
  keyed_bag4<int, double> k1(k0);
  
  cout << "After keyed_bag3 k1(k0):" << endl;
  cout << "The bag k1 has " << k1.size() << " [1000] elements." << endl << endl;
  
  // Test erase() and has_key()
  
  for (int i = 0; i < 1000; ++i)
    k0.erase(1000*i);
  
  cout << "After 1000 erases: " << endl;
  cout << "The bag k0 has " << k0.size() << " [0] elements." << endl;
  cout << "The bag k1 has " << k1.size() << " [1000] elements." << endl;
  cout << "k0.has_key(50000) returns " << k0.has_key(50000) << " [0]" << endl << endl;
  
  // Test the assignment operator
  
  k1 = k0;
  
  cout << "After k1 = k0:" << endl;
  cout << "The bag k1 has " << k1.size() << " [0] elements." << endl << endl;
  
  // Test the insert() of duplicate keys
  
  k1.insert(1, 1000);
  k1.insert(2, 1000);
  k1.insert(3, 1000);
  
  cout << "After inserting into K1 (1, 1000); (2, 1000); (3, 1000):" << endl;
  cout << "   The value of key 1000 is " << k1.get(1000) << " [3]" << endl << endl;

  // Test count()
  
  k1.insert(1, 1000);
  k1.insert(1, 2000);
  k1.insert(1, 3000);
  
  cout << "After inserting (1, 1000); (1, 2000); (1, 3000):" << endl;
  cout << "   The count of value 1 is " << k1.count(1) << " [3]" << endl << endl;
  
  // Test the iterator
  
  keyed_bag4<int, double> k2;
  
  for (int i = 10; i < 30; ++i)
    k2.insert(i, 100*i);
  
  const_iterator<int, double> i, e = k2.end();
  
  for (i = k2.begin(); i != e; i++)
    cout << "Key: " << (*i).second << " Value: " << (*i).first << endl;
  cout << endl;
  
  // Test get() and exception handling
  
  double v;
  try {
    v = k2.get(31416);
    cout << "The get for key 31316 was successful, v = " << v << endl; }
  catch (invalid_argument ia) {
    cout << "Key 31316 not found!" << endl
         << "ia.what() returns: " << ia.what() << endl << endl; }
  catch (...) {
    cout << "Unknown exception caught." << endl; }
  
  return EXIT_SUCCESS;
}