/**************************************************************************
 * Course Project Header File: PointPairSet.h                       *
 *                                                                        *
 * Description: This class defines a set of point pairs.                  *
 *                                                                        *
 *              Internally this set is implemented using a linked list.   *
 *                                                                        *
 **************************************************************************/
#ifndef _POINT_PAIR_SET_H
#define _POINT_PAIR_SET_H

#include <stdio.h>
#include <stdlib.h>

#include "PointPair.h"

/**
 * Forward declaration.
 */
class PointPairSet;

/**
 * The next class PointPairNode will be used by PointPairSet only.
 *
 * Constructor and Destructor are all private so that no other classes
 * can use this class.
 */
class PointPairNode
{
public:
  /**
   * Get reference of internal PointPair of this PointPairNode object.
   */
  PointPair& getPointPair (void) {return pair_;}

  /**
   * Get pointer to the next PointPairNode.
   */
  PointPairNode* getNext (void) const {return next_;}
   
private:
  /**
   * PointPair value inside this PointPairNode object.
   */
  PointPair      pair_;

  /**
   * A pointer pointing to the next PointPairNode object.
   */
  PointPairNode* next_;

  /**
   * Constructor.
   *     To construct a PointPairNode with next pointing to next.
   */
  PointPairNode (const PointPair& pair, PointPairNode* next = 0)
    :pair_ (pair), next_ (next)
    {
      // empty
    }

  /**
   * Destructor.
   *     To release all resources associated with this node.
   */
  ~PointPairNode (void) 
    {
      // empty
    }

  /**
   * Friend class: allow PointPairSet to access this class.
   */
  friend class PointPairSet;
};

class PointPairSet
{
private:

  /**
   * Beginning of the linked list.
   */
  PointPairNode* head_;

public:
  /**
   * Default constructor.
   *    To construct an empty set.
   */
  PointPairSet (void);

  /**
   * Copy constructor.
   *    To construct a new set that has the same content as a given set.
   *
   * parameter set: a point pair set.
   */
  PointPairSet (const PointPairSet& set);

  /**
   * Assignment operator.
   *    To make an existing set to have the same content as a given set.
   * 
   * parameter set: a point pair set.
   * return: this assigned point pair set
   */
  PointPairSet& operator = (const PointPairSet& set);

  /**
   * Merge operator.
   *    To merge another set into this set.
   *
   * parameter set: a different point pair set.
   * return: this modified set.
   */
  PointPairSet& operator += (const PointPairSet& set);

  /**
   * Destructor.
   *    To release all resources associated with this set.
   */
  ~PointPairSet (void);

  /**
   * Number of point pairs in the set.
   *
   * return: number of pairs in the set.
   *         >= 0
   */
  unsigned int numElements     (void) const;

  /**
   * Check whether this set is empty.
   *
   * return: 1 if this set is empty.
   *         0 if this set contains at least one pair.
   */
  int          isEmpty         (void) const;

  /**
   * Check whether a pair is in the set.
   *
   * parameter pair: a point pair.
   * return: 1 if this pair is in this set.
   *         0 if this pair is not in this set.
   */
  int          has             (const PointPair& pair) const;

  /**
   * Add a point pair to this set.
   * 
   * parameter pair: a point pair.
   * return: -1 if this set already has this pair.
   *          0 if this pair has been added.
   */
  int          add             (const PointPair& pair);

  /**
   * Add a point pair to the set without checking whether this pair
   * is in the set. Use this function only if you know there will be
   * no duplication after insertion of this new pair.
   *
   * parameter pair: a point pair.
   */
  void force (const PointPair& pair);


  /**
   * Remove a pair from this set.
   *
   * parameter pair: a point pair.
   * return: -1 if this pair is not in this set.
   *          0 if this pair has been removed from this set.
   */
  int          remove          (const PointPair& pair);

  /**
   * Remove all pairs from this set.
   *    Maybe called by the destructor.
   */
  void         clean           (void);

  /**
   * Comparison operator.
   *     Compare whether this set equals to a given set.
   *
   * return: 1 if this set is the same as a given set.
   *         0 if this set is different from a given set.
   */
  int operator == (const PointPairSet& set);

  /**
   * Comparison operator.
   *     Compare whether this set is different from a given set.
   *
   * return: 1 if this set is different from a given set.
   *         0 if this set is the same as a given set.
   */
  int operator != (const PointPairSet& set);

  /**
   * Overloaded output stream operator.
   *     This operator enables the following statements:
   *     PointPairSet pset;
   *     cout << p;
   */
  friend ostream& operator << (ostream& os, const PointPairSet& pset)
    {
      int haselements = 0;
      PointPairNode* p;

      os << endl;
      os << "This PointPairSet Contains: " << endl;

      for (p = pset.head_; p; p = p->getNext()) {
	haselements = 1;
	os << p->getPointPair() << endl;
      }
      if (!haselements)
	os << "Zero PointPair" << endl;
      os << endl;

      return os;
    }
  
  /**
   * Index operator
   *    Return the point pair in position index (start counting from 0)
   *    inside this set
   */
  PointPair& operator [] (int index) const;
  

};
#endif
