/**************************************************************
 *       clrI2T.c - Tables of Pairs of Integers
 **************************************************************/
/***********************************************
 (C) Copyright 1993; dit/upm
   Distributed under the conditions stated in the
   EPS General Public License (see file LICENSE)
 ***********************************************
 $Log: clrI2T.c,v $
 * Revision 1.3  1993/12/16  14:56:07  eps
 * I2Trm moves every element down
 *
 * Revision 1.2  1993/12/16  14:09:11  eps
 * I2Tdup returns NULL, if argument is NULL
 *
 * Revision 1.1  1993/11/08  16:39:55  eps
 * Initial revision
 *
 **********************************************/

#ifndef lint
static char rcsid[]= "$Id: clrI2T.c,v 1.3 1993/12/16 14:56:07 eps Exp $";
#endif

/***********************************************************************
	Gabriel Huecas
        dpt. Ingenieria Telematica
        E.T.S.I. Telecomunicacion
        Ciudad Universitaria
        E-28040  MADRID

        ghuecas@dit.upm.es

        functions for tables of pairs of integers
	(follows closely IAT)
 **********************************************************************/

/* LINTLIBRARY */

# define cast_IMP
# include "cast.hh"

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

PUBLIC I2T*
I2Tcreate (size, incr, class)
  int size, incr;
  short class;
{
  I2T* tbl;
  int s;

  tbl= (I2T*) malloc (sizeof (I2T));
  if (tbl == NULL)
    fatal ("I2Tcreate run out of memory");
  tbl->size= 0;
  if (incr < 0)
    s= size;
  else if (incr == 0)
    for (s= 4; s < size; s*= 2)
      ;
  else
    for (s= incr; s < size; s+= incr)
      ;
  tbl->max= s;
  tbl->incr= incr;
  tbl->class= class;
  tbl->data= (int*) malloc (2 * s * sizeof (int));
  if (tbl->data == NULL)
    fatal ("I2Tcreate run out of memory for data");
  return tbl;
}

PUBLIC I2T*
I2Tdup (tbl)
  I2T* tbl;
{
  I2T* new;
  int i;

  if (tbl == NULL)
    return NULL;
  new= I2Tcreate (tbl->size, tbl->incr, tbl->class);
  for (i= 0; i < (2 * tbl->size); i++)
      new->data[i]= tbl->data[i];
  new->size= tbl->size;
  return new;
}

PRIVATE void
expand (tbl)
  I2T* tbl;
{
  int s;
  
  if (tbl->incr < 0) {
    (void) fprintf (stderr, "I2T colour: cannot expand fixed table\n");
    exit (1);
  }
  else if (tbl->incr == 0)
    for (s= 4; s < tbl->max+1; s*= 2)
      ;
  else
    for (s= tbl->incr; s < tbl->max+1; s+= tbl->incr)
      ;
  tbl->data= (int*) realloc (tbl->data, 2 * s * sizeof (int));
  if (tbl->data == NULL)
    fatal ("colour I2T cannot get memory for expansion");
  tbl->max= s;
}

PUBLIC int
I2Tadd (x, y, tbl)
  int  x, y;
  I2T* tbl;
{
  int i;
  
  switch (tbl->class) {
  case 1:			/* no dup */
    for (i= 0; i < tbl->size; i++)
      if ((tbl->data[2*i] == x) && (tbl->data[2*i+1] == y))
	return i;
  case 0:			/* as is */
    if ((2*tbl->size)+1 > tbl->max)
      expand (tbl);
    tbl->data[2*tbl->size]= x;
    tbl->data[2*tbl->size+1]= y;
    return tbl->size++;
  default:
    (void) fprintf (stderr, "I2T colour: unkown class (%d)\n", tbl->class);
    exit (1);
  }
  return -2;			/* should never happen! */
}

PUBLIC void
I2Trm (i, tbl)
  int i;
  I2T* tbl;
{
  int m;

  if (i < 0 || i >= tbl->size)
    return;
  tbl->size--;
  for (m= i; m < tbl->size; m++) {
    tbl->data[2*m]= tbl->data[2*m+2];
    tbl->data[2*m+1]= tbl->data[2*m+3];
  }
}

PUBLIC int
I2Tfind (x, y, tbl)
  int  x, y;
  I2T* tbl;
{
  int i;

  for (i= 0; i < tbl->size; i++)
    if ((tbl->data[2*i] == x) && (tbl->data[2*i+1] == y))
      return i;
  return -1;
}

PUBLIC void
I2Tnodup (tbl)
  I2T* tbl;
{
  int i, j;

  for (i= 0; i < tbl->size; i= i+2)
    for (j= i+2; j < tbl->size; j= j+2)
      if ((tbl->data[i] == tbl->data[j]) &&
	  (tbl->data[i+1] == tbl->data[j+1]))
	I2Trm (j, tbl);
  tbl->class= 1;
}

PUBLIC CLR_TYPE
getI2T (fp)
     FILE* fp;
{
  int size, incr;
  short class;
  I2T* tbl;
  int i;
  char c;

  (void) fscanf (fp, "%d", &size);
  c= getc (fp);

  incr= -1;
  class= 0;			/* as is */
  tbl= I2Tcreate (size, incr, class);
  for (c= getc (fp); c != '}'; c= getc (fp)) {
    while (c == ',' || c == '\n' || c == ' ')
      c= getc (fp);
    (void) ungetc (c, fp);
    if (c != '}') {
      (void) fscanf (fp, "%d", &i);
      tbl->data[tbl->size++]= i;
    }
  }
  (void) ungetc (c, fp);
  tbl->size = tbl->size / 2;
  assert (tbl->size == size);
  return (CLR_TYPE) tbl;
}

PUBLIC void
putI2T (fp, val)
     FILE* fp;
     CLR_TYPE val;
{
  I2T* tbl;
  int i;

  tbl= (I2T*) val;
  (void) fprintf (fp, "%d\n", tbl->size);
  if (tbl->size == 0)
    return;
  for (i= 0; i < (2 * tbl->size); i++) {
    if ((i+1)%16 == 0)
      (void) fprintf (fp, "%d,\n", tbl->data[i]);
    else
      (void) fprintf (fp, "%d,", tbl->data[i]);
  }
}

PUBLIC void
fI2T (val)
     CLR_TYPE val;
{
  I2T* tbl;

  assert (val != NULL);

  tbl= (I2T*)val;
  (void) free ((char*)tbl->data);
  (void) free ((char*)tbl);
}

PUBLIC CLR_TYPE
cI2T (val)
    CLR_TYPE val;
{
  return (CLR_TYPE) I2Tdup ((I2T*) val);
}

