/**************************************************************************
 * Course Project Header File: PointSet.h                                 *
 *                                                                        *
 * Description: This class defines a set containing 2-D points.           *
 *                                                                        *
 *              Internally this class is implemented using a resizable    *
 *              array that contains 2-D points.                           *
 *                                                                        *
 **************************************************************************/
#ifndef _POINT_SET_H
#define _POINT_SET_H

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "Point.h"
#include "PointPairSet.h"

#define SORT_X 0
#define SORT_Y 1

class PointSet
{
private:
  /**
   * Internally adjustable array holding 2-D points.
   */
  Point*  points_;

  /**
   * Size of this array.
   */
  unsigned int array_size_;

  /**
   * Number of points in this set.
   *
   * When set_size_ == array_size_, insertion of a new point will 
   * result in allocation of more space.
   */
  unsigned int set_size_;

public:
  /**
   * Default constructor.
   *     To contruct an empty set.
   *
   * parameter default_size: initial array size of this set.
   */
  PointSet                (unsigned int default_size = 256);

  /**
   * Copy constructor.
   *     To construct a set that has the same content of a given set.
   *
   * parameter set: a 2-D point set.
   */
  PointSet                (const PointSet& set);

  /**
   * Assignment operator.
   *     To make an existing set to have the same content of a given set.
   *     Old content will be lost.
   *
   * parameter set: a 2-D point set.
   */
  PointSet& operator =    (const PointSet& set);

  /**
   * Destructor.
   *     To release all resources associated with this set.
   */
  ~PointSet               (void);
  
  /**
   * Number of points in the set.
   *
   * return: number of points 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 point.
   */
  int          isEmpty         (void) const;

  /**
   * Check whether a point is in the set.
   *
   * parameter point: a 2-D point.
   *
   * return: 1 if the point is in this set.
   *         0 if the point is not in this set.
   */
  int          has             (const Point& point) const;

  /**
   * Add a point to this set.
   * 
   * parameter point: a 2-D point.
   *
   * return: -1 if this set has the point.
   *          0 if the point has been added.
   */
  int          add             (const Point& point);

  /**
   * Remove a point from this set.
   *
   * parameter point: a 2-D point.
   *
   * return: -1 if the point is not in this set.
   *          0 the point has been removed from this set.
   */
  int          remove          (const Point& point);

  
  /**
   * Merge this set with another set.
   *
   * parameter set: a 2-D point set.
   *
   * return: a new set that is a union of this set and set 'set'.
   */
  PointSet merge          (const PointSet& set);

  /**
   * Find intersection of this set and another set.
   *
   * parameter set: a 2-D point set.
   *
   * return: a new set that is an intersection of this set and set 'set'.   
   */
  PointSet intersect      (const PointSet& set);

  /**
   * Find two closest points in the set by the brute force method.
   *
   * return: a point pair set containing all point pairs that are closest
   *         in distance in the set.
   */
  PointPairSet closestPointBF (void);

  /**
   * find two closest points in the set by the divide and conquer method.
   *
   * return: a point pair set containing all point pairs that are closest 
   *         in distance in the set.
   */
  PointPairSet closestPointDC (void);  

  /**
   * Create a set randomly.
   *
   * parameter xmax: maximum value of x coordinate for all points in the set. 
   * parameter ymax: maximum value of y coordinate for all points in the set.  
   * parameter num : number of randomly generated points.
   *
   * return: a newly generated set.
   */
  static PointSet create (int xmax, int ymax, int num);

  /**
   * Create a set from a file that contains two columns of integers.
   *
   * parameter fname: the name of a file which contains two columns of 
   *                  integers.
   *
   * return: a newly generated set.
   */
  static PointSet create (char* fname);

  /**
   * Comparison operator.
   *     Compare whether this set equals to a given set.
   *
   * return: 1 if this set equals to a given set.
   *         0 if this set is different from a given set.
   */
  int operator == (const PointSet& 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 equals to a given set.
   */
  int operator != (const PointSet& set);

  /**
   * Overloaded output stream operator.
   *     This operator enables the following statements:
   *     PointSet pset;
   *     cout << pset;
   */
  friend ostream& operator << (ostream& os, const PointSet& pset);

protected:
  /**
   * Sort all points inside the set along either x or y direction.
   *     Sorting must be done by the quick sort algorithm.
   *     Default sorting direction is along x direrction.
   */
  void          qsort          (int type = SORT_X);


  /**
   * Resize the internal array when there are no space to insert
   * a new point (array_size_ == set_size_).
   */
  void          resize         (void);

  /**
   * Index operator
   *    Return the point in position 'index' inside this set
   */
   Point& operator [] (int index) const;

  /**
   * Add a point without checking if it is already in the set.
   *
   * This function can only be used when you are sure adding the point
   * will not cause duplication.
   *
   * This function can be used to improve performance since checking
   * a point inside the set takes a lot time.
   */
  void          force          (const Point& point);

  /**
   * This is the recursive algorithm used inside qsort.
   *
   */
  static void   quickSort      (PointSet& points, int type,
				int left, int right);

  /**
   * this is the recursive algorithm used inside closestPointDC
   * for finding the closest points.
   */
  static void   closestPoints  (const PointSet& sortx, 
				const PointSet& sorty,
				int left, int right,
				PointPairSet& nset);
};
#endif
