
#include <iostream>
#include <string>
#include <utility>
#include <cassert>

#include "hash_set.h"

class hash_string_obj {
public:
  unsigned int operator() ( std::string const& key ) const
  {
    //  This implementation comes from 
    //  http://www.partow.net/programming/hashfunctions/
    unsigned int b    = 378551;
    unsigned int a    = 63689;
    unsigned int hash = 0;

    for(unsigned int i = 0; i < str.length(); i++)
      {
        hash = hash * a + str[i];
        a    = a * b;
      }

    return hash;
  }   
};

typedef hash_set<std::string, hash_string_obj> hash_set_type;

int
main()
{
  hash_set_type set1;
  std::pair< hash_set_type::iterator, bool > insert_result;

  std::string to_insert = std::string("hello");
  insert_result = set1.insert( to_insert );
  assert( insert_result.second );

  insert_result = set1.insert( std::string("good-bye") );
  assert( insert_result.second );

  insert_result = set1.insert( std::string("friend") );
  assert( insert_result.second );

  insert_result = set1.insert( std::string("abc") );
  assert( insert_result.second );

  insert_result = set1.insert( std::string("puppy") );
  assert( insert_result.second );

  insert_result = set1.insert( std::string("zebra") );
  assert( insert_result.second );

  insert_result = set1.insert( std::string("daddy") );
  assert( insert_result.second );

  insert_result = set1.insert( std::string("puppy") );
  assert( !insert_result.second && * insert_result.first == std::string("puppy") );

  std::cout << "The set size should be 8.  Its actual value is " << set1.size() 
	    << "\nHere is the table: \n";
  set1.print( std::cout );


  p = set1.find( "foo" );
  if ( p == set1.end() )
    std::cout << "\"foo\" is not in the set\n";
  else
    std::cout << "\"foo\" is in the set\n"
	      << "The iterator points to " << *p << std::endl;

  p = set1.find("puppy");
  if ( p == set1.end() )
    std::cout << "\"puppy\" is not in the set\n";
  else
    std::cout << "\"puppy\" is in the set\n"
	      << "The iterator points to " << *p << std::endl;

  p = set1.find("daddy");
  if ( p == set1.end() )
    std::cout << "\"daddy\" is not in the set\n";
  else
    std::cout << "\"daddy\" is in the set\n"
	      << "The iterator points to " << *p << std::endl;

  /*   Uncomment for Checkpoint 2

  hash_set_type::iterator p = set1.begin();
  
  std::cout << "\nHere is the result of iterating: \n";
  for ( p = set1.begin(); p != set1.end(); ++p )
    std::cout << *p << '\n';

  */

  /*  Uncomment for Checkpoint 3

  hash_set_type set2( set1 );
  std::cout << "set1.size() = " << set1.size() << ", set2.size() = " << set2.size() << std::endl;

  //  Now add more stuff to set2.  This should trigger a resize given the default settings.
  insert_result = set2.insert( std::string("ardvark") );
  assert( insert_result.second );
  insert_result = set2.insert( std::string("baseball") );
  assert( insert_result.second );
  insert_result = set2.insert( std::string("football") );
  assert( insert_result.second );
  insert_result = set2.insert( std::string("gymnastics") );
  assert( insert_result.second );
  insert_result = set2.insert( std::string("dance") );
  assert( insert_result.second );
  insert_result = set2.insert( std::string("swimming") );
  assert( insert_result.second );
  insert_result = set2.insert( std::string("track") );
  assert( insert_result.second );

  std::cout << "\nAfter six inserts:\n"
	    << "set1.size() = " << set1.size() << ", set2.size() = " << set2.size() << "\n"
	    << "\nThe contents of set2:" << std::endl;
  set2.print(std::cout);
  std::cout << "The results of iterating:\n";
  for ( p = set2.begin(); p != set2.end(); ++p )
    std::cout << *p << '\n';

  //  Now test erase
  int num = set2.erase( std::string("hello") );
  std::cout << "Tried erase \"hello\" and got num (should be 1) = " << num << std::endl;
  num = set2.erase( std::string("abc") );
  std::cout << "Tried erase \"abc\" and got num (should be 1) = " << num << std::endl;
  num = set2.erase( std::string("hello") );
  std::cout << "Tried erase \"hello\" and got num (should be 0) = " << num << std::endl;
  num = set2.erase( std::string("football") );
  std::cout << "Tried erase \"football\" and got num (should be 1) = " << num << std::endl;
  num = set2.erase( std::string("friend") );
  std::cout << "Tried erase \"friend\" and got num (should be 1) = " << num
	    << "\nHere are the final contents of set2:" << std::endl;
  set2.print(std::cout);

  */

  return 0;
}

