/* Copyright (c) 2009
 * Vincenzo Liberatore, Case Western Reserve University
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * - Neither the name of Case Western Reserve University nor the names of
 *   its contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 */

/* Example 3: a bag of pointers to points in the plane */

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


typedef struct {
  double x;
  double y;
} plane_point_t;

typedef struct {
  plane_point_t **bag;
  size_t n;    /* Maximum size of the bag */
  size_t cnt;  /* Number of elements in the bag */
} point_bag_t;


point_bag_t *point_bag_init(size_t n) {
  point_bag_t *bag;

  /* Allocate the bag */
  bag = (point_bag_t *) malloc(sizeof(point_bag_t));
  if (bag == NULL) {
    fprintf(stderr, "Cannot allocate bag\n");
    exit(EXIT_FAILURE);
  }

  /* Allocate the bag array */
  bag->bag = (plane_point_t **) calloc(n, sizeof(point_bag_t *));
  if (bag->bag == NULL) {
    fprintf(stderr, "Cannot allocate bag array\n");
    exit(EXIT_FAILURE);
  }

  /* Initialize bag values */
  bag->n = n;
  bag->cnt = 0;

  return bag;
}


int point_bag_insert(point_bag_t *bag, plane_point_t *value) {
  assert(bag != NULL);

  /* Check that there is enough room in the bag */
  if (bag->cnt >= bag->n)
    return 0;

  bag->bag[bag->cnt++] = value;
  return 1;
}


int point_equal(plane_point_t *a, plane_point_t *b) {
  return a->x == b->x && a->y == b->y;
}

int point_bag_search(point_bag_t *bag, plane_point_t *value) {
  size_t i;                  /* Cursor */
  size_t cnt;                /* Alias for bag->cnt */
  plane_point_t **bag_array; /* Alias for bag->bag */

  assert(bag != NULL);

  /* Assign local aliases */
  cnt       = bag->cnt;
  bag_array = bag->bag;

  /* Search the array */
  for (i = 0; i < cnt && !point_equal(bag_array[i],value); i++);

  /* If i<cnt, the loop terminated earlier --> the element was found.
     Otherwise, it ran to the end --> it was not found */
  return i < cnt;
}


void point_bag_delete(point_bag_t *bag) {
  assert(bag != NULL);

  free(bag->bag);
  free(bag);
}


int main() {
  plane_point_t point[4];
  point_bag_t *bag;

  bag = point_bag_init(10);

  point[0].x = 4.;
  point[0].y = 5.;
  printf("Insert (4,5): %u (1=ok, 0=failure)\n", 
         point_bag_insert(bag, point));

  point[1].x = 8.;
  point[1].y = 9.;
  printf("Insert (8,9): %u (1=ok, 0=failure)\n", 
         point_bag_insert(bag, point+1));

  printf("Insert (4,5): %u (1=ok, 0=failure)\n", 
         point_bag_insert(bag, point));

  point[2].x = 7.;
  point[2].y = 6.;
  printf("Is (7,6) in the bag? %u\n", point_bag_search(bag, point+2));

  printf("Insert (7,6): %u (1=ok, 0=failure)\n", 
         point_bag_insert(bag, point+2));

  printf("Is (7,6) in the bag? %u\n", point_bag_search(bag, point+2));

  point_bag_delete(bag);

  return 0;
}
