/*
       File:             apict.c
       Author:           Mary Soon Lee
       Created:          16 Jan 96
       Modified:         30 Jan 96

       Description:      Code supporting apicts, the structures used 
                         to store pictures.  Elements of these pictures
                         may be circles, lines, strings, rectangles,
                         and discs (solid circles).

           Andrew added "apict_set" data structure. Contains multiple
           apicts.
*/

#include <stdio.h>
#include <math.h>
#include "ambs.h"
#include "apict.h"

/* ==================================================================== */
/* Basic functions to allocate/free/print apicts and their components.  */
/* ==================================================================== */

/* Allocates and returns an empty apict of default size and indentation
   (width = height = 512; indent = 0). */
apict *mk_apict()
{
  apict *result = AM_MALLOC(apict);
  result->indent = 0;
  result->width = 512;
  result->height = 512;
  result->lines = NULL;
  result->circles = NULL;
  result->strings = NULL;
  result->rects = NULL;
  result->discs = NULL;
  return(result);
}

void am_free_ap_line(ap_line *l)
{
  AM_FREE(l, ap_line);
}

void am_free_ap_lines(ap_lines *l)
{
  if (l != NULL)
  {
    am_free_ap_lines(l->rest_lines);
    am_free_ap_line(l->l1);
    AM_FREE(l, ap_lines);
  }
} 

void am_free_ap_circle(ap_circle *c)
{
  AM_FREE(c, ap_circle);
}

void am_free_ap_circles(ap_circles *c)
{
  if (c != NULL)
  {
    am_free_ap_circles(c->rest_circles);
    am_free_ap_circle(c->c1);
    AM_FREE(c, ap_circles);
  }
} 

void am_free_ap_string(ap_string *s)
{
  AM_FREE(s, ap_string);
}

void am_free_ap_strings(ap_strings *s)
{
  if (s != NULL)
  {
    am_free_ap_strings(s->rest_strings);
    am_free_ap_string(s->s1);
    AM_FREE(s, ap_strings);
  }
} 
 
void am_free_ap_rect(ap_rect *r)
{
  AM_FREE(r, ap_rect);
}

void am_free_ap_rects(ap_rects *r)
{
  if (r != NULL)
  {
    am_free_ap_rects(r->rest_rects);
    am_free_ap_rect(r->r1);
    AM_FREE(r, ap_rects);
  }
} 
 
void am_free_ap_disc(ap_disc *d)
{
  AM_FREE(d, ap_disc);
}

void am_free_ap_discs(ap_discs *d)
{
  if (d != NULL)
  {
    am_free_ap_discs(d->rest_discs);
    am_free_ap_disc(d->d1);
    AM_FREE(d, ap_discs);
  }
} 

/* AWM- N.B. I'm changing the preferred name of this to free_apict, which
   is an Auton Project convention. am_free_apict retained for compatibility
*/ 
void free_apict(apict *g)
{
  am_free_ap_lines(g->lines);
  am_free_ap_circles(g->circles);
  am_free_ap_strings(g->strings);
  am_free_ap_rects(g->rects);
  am_free_ap_discs(g->discs);
  AM_FREE(g, apict);
}

void am_free_apict(apict *g)
{
  free_apict(g);
}

void print_ap_line(ap_line *l)
{
  printf("Line: (%g, %g) -> (%g, %g)\n", l->x1, l->y1, l->x2, l->y2);
}

void print_ap_circle(ap_circle *c)
{
  printf("Circle: center (%g, %g), radius %g\n", c->x, c->y, c->r);
}

void print_ap_string(ap_string *s)
{
  printf("String: start (%g, %g), text \"%s\"\n", s->x, s->y, s->str);
}

void print_ap_rect(ap_rect *r)
{
  printf("Rect: (%g, %g) -> (%g, %g)\n",
         r->x, r->y, r->x + r->w, r->y + r->h);
}

void print_ap_disc(ap_disc *d)
{
  printf("Disc: center (%g, %g), radius %g\n", d->x, d->y, d->r);
}

void print_apict(apict *g)
{
  ap_lines *l = g->lines;
  ap_circles *c = g->circles;
  ap_strings *s = g->strings;
  ap_rects *r = g->rects;
  ap_discs *d = g->discs;

  while (l != NULL)
  {
    print_ap_line(l->l1);
    l = l->rest_lines;
  }
  while (c != NULL)
  {
    print_ap_circle(c->c1);
    c = c->rest_circles;
  }
  while (s != NULL)
  {
    print_ap_string(s->s1);
    s = s->rest_strings;
  }
  while (r != NULL)
  {
    print_ap_rect(r->r1);
    r = r->rest_rects;
  }
  while (d != NULL)
  {
    print_ap_disc(d->d1);
    d = d->rest_discs;
  }
}

ap_line *mk_ap_line(double x1, double y1, double x2, double y2, int col)
{
  ap_line *result = AM_MALLOC(ap_line);
  result->x1 = x1;
  result->x2 = x2;
  result->y1 = y1;
  result->y2 = y2;
  result->color = col;
  return(result);
}

ap_circle *mk_ap_circle(double x, double y, double r, int col)
{
  ap_circle *result = AM_MALLOC(ap_circle);
  result->x = x;
  result->y = y;
  result->r = r;
  result->color = col;
  return(result);
}

ap_string *mk_ap_string(double x, double y, char *s, int col)
{
  ap_string *result = AM_MALLOC(ap_string);
  result->x = x;
  result->y = y;
  if (((int) strlen(s)) > MAX_APICT_STR_LEN)
    my_error("mk_ap_string: Too long a string");
  sprintf(result->str, "%s", s);
  result->color = col;
  return(result);
}

ap_rect *mk_ap_rect(double x, double y, double w, double h, int col)
{
  ap_rect *result = AM_MALLOC(ap_rect);
  result->x = x;
  result->y = y;
  result->w = w;
  result->h = h;
  result->color = col;
  return(result);
}

ap_disc *mk_ap_disc(double x, double y, double r, int col)
{
  ap_disc *result = AM_MALLOC(ap_disc);
  result->x = x;
  result->y = y;
  result->r = r;
  result->color = col;
  return(result);
}

/* ==================================================================== */
/* Basic functions to add lines/circles/strings/rects/discs to an apict */
/* ==================================================================== */

void ap_add_line(apict *g, double x1, double y1, double x2, double y2,
                 int col)
{
  ap_lines *new_lines = AM_MALLOC(ap_lines);
  ap_line *nl = mk_ap_line(x1, y1, x2, y2, col);

  new_lines->l1 = nl;
  if (g->lines == NULL)
    new_lines->rest_lines = NULL;
  else
    new_lines->rest_lines = g->lines;
  g->lines = new_lines;
}

void ap_add_circle(apict *g, double x, double y, double r, int col)
{
  ap_circles *new_circles = AM_MALLOC(ap_circles);
  ap_circle *nc = mk_ap_circle(x, y, r, col);

  new_circles->c1 = nc;
  if (g->circles == NULL)
    new_circles->rest_circles = NULL;
  else
    new_circles->rest_circles = g->circles;
  g->circles = new_circles;
}

void ap_add_string(apict *g, double x, double y, char *s, int col)
{
  ap_strings *new_strings = AM_MALLOC(ap_strings);
  ap_string *ns = mk_ap_string(x, y, s, col);

  new_strings->s1 = ns;
  if (g->strings == NULL)
    new_strings->rest_strings = NULL;
  else
    new_strings->rest_strings = g->strings;
  g->strings = new_strings;
}

/* Take care to add the disc to the *end* of the list, so that
   discs added last will be drawn up last. */  
void ap_add_disc(apict *a, double x, double y, double r, int col)
{
  ap_discs *old_discs = a->discs;
  ap_discs *new_discs = AM_MALLOC(ap_discs);

  new_discs->d1 = mk_ap_disc(x, y, r, col);
  new_discs->rest_discs = NULL;
  if (old_discs == NULL)
    a->discs = new_discs;
  else
  {
	while (old_discs->rest_discs != NULL)
	{
	  old_discs = old_discs->rest_discs;
	}
    old_discs->rest_discs = new_discs;
  }
}

/* Take care to add the rectangle to the *end* of the list, so that
   rectangles added last will be drawn up last. */  
void ap_add_rect(apict *g, double x, double y, double w, double h, int col)
{
  ap_rects *old_rects = g->rects;
  ap_rects *new_rects = AM_MALLOC(ap_rects);

  new_rects->r1 = mk_ap_rect(x, y, w, h, col);
  new_rects->rest_rects = NULL;
  if (old_rects == NULL)
    g->rects = new_rects;
  else
  {
	while (old_rects->rest_rects != NULL)
	{
	  old_rects = old_rects->rest_rects;
	}
    old_rects->rest_rects = new_rects;
  }
}

/* ==================================================================== */
/* Basic functions to copy lines/circles/strings/rects/discs/apicts and */
/* to clear an apict.                                                   */
/* ==================================================================== */

/* Clears the apict, freeing its subcomponents */
void ap_clear(apict *a)
{
  am_free_ap_lines(a->lines);
  am_free_ap_circles(a->circles);
  am_free_ap_strings(a->strings);
  am_free_ap_rects(a->rects);
  am_free_ap_discs(a->discs);
  a->lines = NULL;
  a->circles = NULL;
  a->strings = NULL;
  a->rects = NULL;
  a->discs = NULL;
}

/* Copies the lines in a_from into a_to.  Assumes that a_to's lines
   field is NULL initially (i.e. nothing needs to be freed). */
void ap_copy_lines(apict *a_from, apict *a_to)
{
  ap_lines *ls = a_from->lines;
  ap_line *l;

  while (ls != NULL)
  {
    l = ls->l1;
    ap_add_line(a_to, l->x1, l->y1, l->x2, l->y2, l->color);
    ls = ls->rest_lines;
  }
}

/* Copies the circles in a_from into a_to.  Assumes that a_to's circles
   field is NULL initially (i.e. nothing needs to be freed). */
void ap_copy_circles(apict *a_from, apict *a_to)
{
  ap_circles *cs = a_from->circles;
  ap_circle *c;

  while (cs != NULL)
  {
    c = cs->c1;
    ap_add_circle(a_to, c->x, c->y, c->r, c->color);
    cs = cs->rest_circles;
  }
}

/* Copies the strings in a_from into a_to.  Assumes that a_to's strings
   field is NULL initially (i.e. nothing needs to be freed). */
void ap_copy_strings(apict *a_from, apict *a_to)
{
  ap_strings *ss = a_from->strings;
  ap_string *s;

  while (ss != NULL)
  {
    s = ss->s1;
    ap_add_string(a_to, s->x, s->y, s->str, s->color);
    ss = ss->rest_strings;
  }
}

/* Copies the rects in a_from into a_to.  Assumes that a_to's rects
   field is NULL initially (i.e. nothing needs to be freed). 

   4 Dec 95: amended so that the rectangles are in the same order in
   the copied list.  This is an ugly revision, needed so that when
   one box is drawn after another it will really overlay the other
   box.
*/
void ap_copy_rects(apict *a_from, apict *a_to)
{
  ap_rects *rs = a_from->rects;
  ap_rect *r;
  apict *tem = mk_apict();

  while (rs != NULL)
  {
    r = rs->r1;
    ap_add_rect(tem, r->x, r->y, r->w, r->h, r->color);
    rs = rs->rest_rects;
  }
  /* tem->rects now holds a reversed list of the rectangles... */
  rs = tem->rects;
  while (rs != NULL)
  {
    r = rs->r1;
    ap_add_rect(a_to, r->x, r->y, r->w, r->h, r->color);
    rs = rs->rest_rects;
  }
  am_free_apict(tem);
}

/* Copies the discs in a_from into a_to.  Assumes that a_to's discs
   field is NULL initially (i.e. nothing needs to be freed). 

   4 Dec 95: amended so that the discs are in the same order in
   the copied list.  This is an ugly revision, needed so that when
   one disc is drawn after another it will really overlay the other
   disc.
*/
void ap_copy_discs(apict *a_from, apict *a_to)
{
  ap_discs *ds = a_from->discs;
  ap_disc *d;
  apict *tem = mk_apict();

  while (ds != NULL)
  {
	d = ds->d1;
    ap_add_disc(tem, d->x, d->y, d->r, d->color);
    ds = ds->rest_discs;
  }
  /* tem->discs now holds a reversed list of the discs... */
  ds = tem->discs;
  while (ds != NULL)
  {
	d = ds->d1;
    ap_add_disc(a_to, d->x, d->y, d->r, d->color);
    ds = ds->rest_discs;
  }
  am_free_apict(tem);
}

/* Copies the contents of a_from to a_to, first clearing a_to. */
void ap_copy_from_to(apict *a_from, apict *a_to)
{
  ap_clear(a_to);
  ap_copy_lines(a_from, a_to);
  ap_copy_circles(a_from, a_to);
  ap_copy_strings(a_from, a_to);
  ap_copy_rects(a_from, a_to);
  ap_copy_discs(a_from, a_to);
  a_to->indent = a_from->indent;
  a_to->width = a_from->width;
  a_to->height = a_from->height;	  
}

apict *mk_copy_apict(apict *ap)
{
  apict *result = mk_apict();
  ap_copy_from_to(ap,result);
  return(result);
}

/* ==================================================================== */
/* If apict_on has been called more recently than apict_off, then any   */
/* calls to ag_line, ag_circle, etc., should save the picture elements  */
/* to the global variable Current_Apict.  This is achieved by a series  */
/* of functions called apict_line, apict_circle, etc., that mimic       */
/* screen_line, screen_circle, etc.  (See amgr.c/amgr.h.)               */
/*                                                                      */
/* When apict_off is called, the Current_Apict structure is returned,   */
/* and Current_Apict is reset to an empty apict.                        */
/* ==================================================================== */

apict *Current_Apict = NULL;

/* Sets Current_Apict to hold a new, empty apict structure.  Subsequent
   calls to apict_line, apict_circle, etc., will add elements to this
   apict.  When apict_off is next called, it will return this apict,
   and reset Current_Apict to NULL.   This allows the user to incrementally
   build up a structure representing a picture.

   It is an error to call apict_on when Current_Apict is not NULL; hence
   it is an error to call apict_on twice without calling apict_off in
   between.
*/
void apict_on()
{
  if (Current_Apict != NULL)
    my_error("apict_on called when the Current_Apict was non-NULL");
  Current_Apict = mk_apict();
}

/* This returns the structure in Current_Apict, and resets the global 
   variable to NULL.  */
apict *apict_off()
{
  apict *res = Current_Apict;

  Current_Apict = NULL;
  return(res);
}

/* ==================================================================== */
/* Principal functions.  These are the functions that the programmer    */
/* should use to manipulate apicts.                                     */
/* ==================================================================== */

/* Clears the current apict */
void apict_clear()
{
  ap_clear(Current_Apict);
}

/* Adds a line from (x1, y1) to (x2, y2) to the current apict */
void apict_line(double x1, double y1, double x2, double y2)
{
  extern int Pen_Color;
  ap_add_line(Current_Apict, x1, y1, x2, y2, Pen_Color);
}

/* Adds a circle, center (x, y), radius r, to the current apict */
void apict_circle(double x, double y, double r)
{
  extern int Pen_Color;
  ap_add_circle(Current_Apict, x, y, r, Pen_Color);
}

/* Adds a string, s, that starts at coordinates (x, y), to the current
   apict */
void apict_print(char *s, double x, double y)
{
  extern int Pen_Color;
  ap_add_string(Current_Apict, x, y, s, Pen_Color);
}

/* Adds a filled rectangle to the current apict.  The bottom left of the
   rectangle is at (x, y); its width and height are w and h.  Assumption:
   w and h are positive. */
void apict_box(double x, double y, double w, double h)
{
  extern int Pen_Color;
  ap_add_rect(Current_Apict, x, y, w, h, Pen_Color);
}

/* Adds a disc, center (x, y), radius r, to the current apict */
void apict_disc(double x, double y, double r)
{
  extern int Pen_Color;
  ap_add_disc(Current_Apict, x, y, r, Pen_Color);
}

/* Draws a dot at (x, y). */
void apict_dot(double x, double y) 
{
  apict_disc(x, y, 3.0);
}

/* Returns the apict currently being built up.  */
apict *cur_apict()
{
  return(Current_Apict);
}

/* Returns TRUE iff an apict is currently being built up
   (i.e. apict_on has been called more recently than apict_off).  */
bool apict_on_p()
{
  bool res = FALSE;

  if (Current_Apict != NULL)
    res = TRUE;
  return(res);
}

/* ==================================================================== */
/* Miscellaneous functions                                              */
/* ==================================================================== */

/* Sets a to hold colored concentric circles.  */
void set_apict_circles(apict *a)
{
  int i;
  int simple_spectrum_color(double fract);
  
  ap_clear(a);
  for (i = 0; i < 100; i++)
    ap_add_circle(a, 256.0, 256.0, 256.0 * ((1 + i) / 101.0), 
                  simple_spectrum_color(((double) i)/101.0));
}

/* Sets a to hold a grid of colored boxes.  */
void set_apict_boxes(apict *a)
{
  int i, j;
  int simple_spectrum_color(double fract);
  
  ap_clear(a);
  for (j = 0; j < 5; j++)
	for (i = 0; i < 3; i++)
	  ap_add_rect(a, 20 + j * 70.0, 380 - i * 150.0, 60.0, 140.0, 
                  i * 5 + j);
}

#if (PLATFORM_CODE==WINDOWS_NT_PLATFORM_CODE) 
/* ==================================================================== */
/* Document-related functions =-- thus far only implemented in the PC   */
/* world.                                                               */
/* ==================================================================== */

int line_spacing = 1;
int text_height = 30;
int space_between_secs = 30;
int apict_height = 512;

/* Note that this doesn't set the y_start and y_end fields. */
doc_section *mk_doc_section_from_apict(apict *ap)
{
  doc_section *ds = AM_MALLOC(doc_section);

  ds->apictp = TRUE;
  ds->expop = FALSE;
  ds->ex = NULL;
  ds->ap = ap;
  return(ds);
}

/* Note that this doesn't set the y_start and y_end fields. */
doc_section *mk_doc_section_from_expo(expo *exp)
{
  doc_section *ds = AM_MALLOC(doc_section);

  ds->expop = TRUE;
  ds->apictp = FALSE;
  ds->ex = exp;
  ds->ap = NULL;
  return(ds);
}

document *mk_empty_document()
{
  document *doc = AM_MALLOC(document);

  doc->ds = NULL;
  doc->length = space_between_secs;
  return(doc);
}

void am_free_doc_section(doc_section *ds)
{
  if (ds->apictp)
	am_free_apict(ds->ap);
  if (ds->expop)
	free_expo(ds->ex);
  AM_FREE(ds, doc_section);
}

void am_free_doc_sections(doc_sections *ds)
{
  if (ds != NULL)
  {
    am_free_doc_sections(ds->rest_ds);
    am_free_doc_section(ds->ds1);
    AM_FREE(ds, doc_sections);
  }
} 

/* Clears a document, freeing its subcomponents */
void doc_clear(document *d)
{
  am_free_doc_sections(d->ds);
  d->ds = NULL;
  d->length = space_between_secs;
}

/* Note that we ensure the document sections are kept in order, with the new 
   apict being added to the end. */
void add_apict_to_doc(document *doc, apict *ap)
{
  doc_sections *old_ds = doc->ds;
  doc_sections *new_secs = AM_MALLOC(doc_sections);
  int old_doc_len = doc->length;
  int new_doc_len = old_doc_len + space_between_secs + ap->height;
  
  new_secs->ds1 = mk_doc_section_from_apict(ap);
  new_secs->rest_ds = NULL;
  (new_secs->ds1)->y_start = old_doc_len;
  (new_secs->ds1)->y_end = new_doc_len;
  (new_secs->ds1)->indent = ap->indent;
  doc->length = new_doc_len;
  if (old_ds == NULL)
    /* The document is currently empty. */
    doc->ds = new_secs;
  else
  {
    while (old_ds->rest_ds != NULL)
    {
      old_ds = old_ds->rest_ds;
    }
    old_ds->rest_ds = new_secs;
  }
}

/* Note that we ensure the document sections are kept in order, with the new 
   expo being added to the end. */
void add_expo_to_doc(document *doc, expo *ex, int num_chars_per_line)
{
  doc_sections *old_ds = doc->ds;
  doc_sections *new_secs = AM_MALLOC(doc_sections);
  string_array *sa = mk_string_array_from_expo(ex, num_chars_per_line);
  int old_doc_len = doc->length;
  int new_doc_len = old_doc_len + space_between_secs + 
	                  string_array_size(sa) * (text_height + line_spacing + 1);

  free_string_array(sa);
  new_secs->ds1 = mk_doc_section_from_expo(ex);
  new_secs->rest_ds = NULL;
  (new_secs->ds1)->y_start = old_doc_len;
  (new_secs->ds1)->y_end = new_doc_len;
  (new_secs->ds1)->indent = ex->indent;
  doc->length = new_doc_len;
  if (old_ds == NULL)
    /* The document is currently empty. */
    doc->ds = new_secs;
  else
  {
    while (old_ds->rest_ds != NULL)
    {
      old_ds = old_ds->rest_ds;
    }
    old_ds->rest_ds = new_secs;
  }
}

/* Render_apict does nothing in the PC world....  */
void render_apict(apict *g)
{
}

#endif /* #if (PLATFORM_CODE==WINDOWS_NT_PLATFORM_CODE) */

/* =================================================================== */

#if (PLATFORM_CODE==CMU_PLATFORM_CODE)

/* Code to display an apict in the Unix world.  This will only have
   an effect if ag_on has been called earlier.  */
void render_apict(apict *g)
{
  ap_lines *l = g->lines;
  ap_line *l1;
  ap_circles *c = g->circles;
  ap_circle *c1;
  ap_strings *s = g->strings;
  ap_string *s1;
  ap_rects *r = g->rects;
  ap_rect *r1;
  ap_discs *d = g->discs;
  ap_disc *d1;
  int old_color = ag_pen_color();

  while (l != NULL)
  {
    l1 = l->l1;
    if (l1->color != ag_pen_color())
      ag_set_pen_color(l1->color);
    ag_line(l1->x1, l1->y1, l1->x2, l1->y2);
    l = l->rest_lines;
  }
  while (c != NULL)
  {
    c1 = c->c1;
    if (c1->color != ag_pen_color())
      ag_set_pen_color(c1->color);
    ag_circle(c1->x, c1->y, c1->r);
    c = c->rest_circles;
  }
  while (s != NULL)
  {
    s1 = s->s1;
    if (s1->color != ag_pen_color())
      ag_set_pen_color(s1->color);
    ag_print(s1->x, s1->y, s1->str);
    s = s->rest_strings;
  }
  while (r != NULL)
  {
    r1 = r->r1;
    if (r1->color != ag_pen_color())
      ag_set_pen_color(r1->color);
    ag_box(r1->x, r1->y, r1->x + r1->w, r1->y + r1->h);
    r = r->rest_rects;
  }
  while (d != NULL)
  {
    d1 = d->d1;
    if (d1->color != ag_pen_color())
      ag_set_pen_color(d1->color);
    ag_disc(d1->x, d1->y, d1->r);
    d = d->rest_discs;
  }
  ag_set_pen_color(old_color);
}

#endif /* #if (PLATFORM_CODE==CMU_PLATFORM_CODE) */

/***** apict_array time! ****/

#define INITIAL_APICT_SET_SIZE 10

apict_set *mk_empty_apict_set()
{
  apict_set *aps = AM_MALLOC(apict_set);
  aps -> size = 0;
  aps -> array_size = INITIAL_APICT_SET_SIZE;
  aps -> array = AM_MALLOC_ARRAY(apict_ptr,aps->array_size);
  return(aps);
}

void add_to_apict_set(apict_set *aps,apict *this_apict)
/*
     Assume apict_set is previously of size n. After this it is of size
   n+1, and the n+1'th element is a COPY of this_apict.
*/
{
  if ( aps -> size == aps -> array_size )
  {
    int new_size = 2 + 2 * aps->array_size;
    apict **new_array = AM_MALLOC_ARRAY(apict_ptr,new_size);
    int i;
    for ( i = 0 ; i < aps -> array_size ; i++ )
      new_array[i] = aps->array[i];
    AM_FREE_ARRAY(aps->array,apict_ptr,aps->array_size);
    aps -> array = new_array;
    aps -> array_size = new_size;
  }
  aps->array[aps->size] = mk_copy_apict(this_apict);
  aps->size += 1;
}

int apict_set_size(apict_set *aps)
{
  return(aps->size);
}

apict *apict_set_ref(apict_set *aps,int index)
/*
     Returns a pointer (not a copy) to the index'th element stored in
   the apict_set. Error if index < 0 or index >= size
*/
{
  apict *result;
  if ( index < 0 || index >= apict_set_size(aps) )
  {
    result = NULL;
    my_error("apict_set_ref");
  }
  else
    result = aps->array[index];
  return(result);
}
  
void fprintf_apict_set(FILE *s,char *m1,apict_set *aps,char *m2)
{
  if ( apict_set_size(aps) == 0 )
    fprintf(s,"%s = <apict_set with zero entries>%s",m1,m2);
  else
  {
    int i;
    for ( i = 0 ; i < apict_set_size(aps) ; i++ )
    {
      fprintf(s,"\n%s[%2d] follows (on stdout).....\n\n",m1,i);
      print_apict(apict_set_ref(aps,i));
    }
  }
}

void free_apict_set(apict_set *aps)
{
  int i;
  for ( i = 0 ; i < apict_set_size(aps) ; i++ )
    free_apict(aps->array[i]);
  AM_FREE_ARRAY(aps->array,apict_ptr,aps->array_size);
  AM_FREE(aps,apict_set);
}

apict_set *mk_copy_apict_set(apict_set *aps)
{
  apict_set *new_ar = mk_empty_apict_set();
  int i;

  for ( i = 0 ; i < apict_set_size(aps) ; i++ )
    add_to_apict_set(new_ar,apict_set_ref(aps,i));

  return(new_ar);
}


