/*
   File:        colshape.c
   Author:      Andrew W. Moore
   Created:     Sat Aug 14 12:50:55 EDT 1999
   Description: SPR/Auton Shape of a datset structure

   Copyright 1999, Schenley Park Research
*/

#include "colshape.h"

/* Private headers */
static void sort_scolshape_values(scolshape *scs);
static int scolshape_insert_value_name(scolshape *scs,char *value_name);
static void scolshape_remove_all_value_names(scolshape *scs);
static void scolshape_valnames_prepend(scolshape *scs,char *prefix);
static void scolshape_delete_value(scolshape *scs,int value);
static void maybe_free_rcolshape(rcolshape **rc_ptr);
static void maybe_free_scolshape(scolshape **sc_ptr);
static int colshape_major_coltype(colshape *cs);
static int colshape_minor_coltype(colshape *cs);
static char *coltype_to_name(int coltype);






void free_scolshape(scolshape *x)
{
  free_string(x->name);
  free_string_array(x->value_names);
  free_hash_table(x->value_names_ht);
  AM_FREE(x,scolshape);
}

bool scolshape_equal(scolshape *x1,scolshape *x2)
{
  bool equal = eq_string(x1->name,x2->name);
  string_array *sa1, *sa2;
  
  if (equal)
  {
    sa1 = mk_copy_string_array(x1->value_names);
    sa2 = mk_copy_string_array(x2->value_names);
    
	sort_string_array(sa1);
    sort_string_array(sa2);

	equal = string_array_equal(sa1,sa2);
    free_string_array(sa1);
    free_string_array(sa2);
  }
  return equal;
}

void free_rcolshape(rcolshape *x)
{
  free_string(x->name);
  AM_FREE(x,rcolshape);
}

static void sort_scolshape_values(scolshape *scs)
{
  int i;
  string_array *sa = mk_copy_string_array(scs->value_names);
  sort_string_array(sa);

  for (i=0;i<string_array_size(sa);i++)
    if (!update_hash_entry(scs->value_names_ht,string_array_ref(sa,i),&i))
      my_error("sort_scolshape_attributes: corrupted hash table");
  free_string_array(scs->value_names);
  scs->value_names = sa;
}


bool rcolshape_equal(rcolshape *x1,rcolshape *x2)
{
  return eq_string(x1->name,x2->name);
}

void free_colshape(colshape *x)
{
  if ( x->scs != NULL ) free_scolshape(x->scs);
  if ( x->rcs != NULL ) free_rcolshape(x->rcs);
  AM_FREE(x,colshape);
}

/* Returns TRUE if and only if the two colshapes are identical
   is all respects */
bool colshape_equal(colshape *c1,colshape *c2)
{
  bool result = TRUE;
  if ( result && c1->scs != NULL )
    result = c2->scs != NULL && scolshape_equal(c1->scs,c2->scs);
  if ( result && c1->rcs != NULL )
    result = c2->rcs != NULL && rcolshape_equal(c1->rcs,c2->rcs);
  return result;
}

scolshape *mk_copy_scolshape(scolshape *x)
{
  scolshape *newx = AM_MALLOC(scolshape);
  newx -> name = mk_copy_string(x->name);
  newx -> value_names = mk_copy_string_array(x->value_names);
  newx -> value_names_ht = mk_copy_hash_table(x->value_names_ht);
  return(newx);
}

rcolshape *mk_copy_rcolshape(rcolshape *x)
{
  rcolshape *newx = AM_MALLOC(rcolshape);
  newx -> name = mk_copy_string(x->name);
  return(newx);
}

colshape *mk_copy_colshape(colshape *x)
{
  colshape *newx = AM_MALLOC(colshape);
  newx -> major_coltype = x -> major_coltype;
  newx -> minor_coltype = x -> minor_coltype;
  newx -> scs = (x->scs==NULL) ? NULL : mk_copy_scolshape(x->scs);
  newx -> rcs = (x->rcs==NULL) ? NULL : mk_copy_rcolshape(x->rcs);
  return(newx);
}

void fprintf_scolshape(FILE *s,char *m1,scolshape *x,char *m2)
{
  char buff[200];
  sprintf(buff,"%s -> name",m1);
  fprintf_string(s,buff,x->name,m2);
  sprintf(buff,"%s -> value_names",m1);
  fprintf_string_array(s,buff,x->value_names,m2);
}

void fprintf_rcolshape(FILE *s,char *m1,rcolshape *x,char *m2)
{
  char buff[200];
  sprintf(buff,"%s -> name",m1);
  fprintf_string(s,buff,x->name,m2);
}

void fprintf_colshape(FILE *s,char *m1,colshape *x,char *m2)
{
  char buff[200];
  sprintf(buff,"%s -> major_coltype",m1);
  fprintf_int(s,buff,x->major_coltype,m2);
  sprintf(buff,"%s -> minor_coltype",m1);
  fprintf_int(s,buff,x->minor_coltype,m2);
  sprintf(buff,"%s -> scs",m1);
  if ( x->scs != NULL ) fprintf_scolshape(s,buff,x->scs,m2);
  sprintf(buff,"%s -> rcs",m1);
  if ( x->rcs != NULL ) fprintf_rcolshape(s,buff,x->rcs,m2);
}

scolshape *mk_scolshape(char *name)
{
  scolshape *scs = AM_MALLOC(scolshape);
  scs -> name = mk_copy_string(name);
  scs -> value_names = mk_string_array(0);
  scs -> value_names_ht = mk_empty_hash_table(vint_copy,vint_free,
					      int_num_bytes);
  return(scs);
}

/* Returns -1 if no such value name exists */
int scolshape_name_to_value(scolshape *scs,char *s)
{
  int *result_ptr = (int *)lookup_hash_entry(scs->value_names_ht,s);
  int result = ( result_ptr == NULL ) ? -1 : *result_ptr;
  return result;
}

/* If the name is not already present in the list of symbols, it is added.
   This does NOT attempt to ensure that the order of the values 
   corresponds to lexicographic order of their names. */
void scolshape_add_value_name(scolshape *scs,char *name)
{
#define ILLEGAL_SCOLSHAPE_VALUES "\""
  if(find_index_in_string(name, ILLEGAL_SCOLSHAPE_VALUES) != -1)
    {
    char* errmsg = mk_printf("Illegal character in symbolic field %s (one of [" ILLEGAL_SCOLSHAPE_VALUES "])\n", name);
    my_error(errmsg);
    free_string(errmsg); /* Like we ever make it here.. heh */
    }
  if (!lookup_hash_entry(scs->value_names_ht,name))
    {
    int place = string_array_size(scs->value_names);
    add_to_string_array(scs->value_names,name);
    add_hash_entry(scs->value_names_ht,name,(void *)(&place));
    }
}

/* Adds value_name into the list of names of the scolshape,
   inserting at the appropriate position to ensure that the
   values remain in lexicographic order. Returns the small int
   integer value of the new value name. You may assume that if some
   other value_name had small int value v before then afterwards
   it has...

     ...value v if v < result
     ...value v+1 if v >= result

   where result is the result of this function (i.e. the new symbol_value
   of the new value_name)
*/
static int scolshape_insert_value_name(scolshape *scs,char *value_name)
{
  scolshape_add_value_name(scs,value_name);
  sort_scolshape_values(scs);
  return scolshape_name_to_value(scs,value_name);
}

/* Afterwards there are no symbolic names */
static void scolshape_remove_all_value_names(scolshape *scs)
{
  free_string_array(scs->value_names);
  free_hash_table(scs->value_names_ht);
  scs -> value_names = mk_string_array(0);
  scs -> value_names_ht = mk_empty_hash_table(vint_copy,vint_free,
					      int_num_bytes);
}

int scolshape_value_from_string(scolshape *scs,char *s,char **r_errmess)
{
  int result = scolshape_name_to_value(scs,s);
  if ( result < 0 )
  {
    char buff[1000];
    sprintf(buff,"%s is not one of the legal values for attribute %s",
            s,scs->name);
    *r_errmess = mk_copy_string(buff);
  }
  return(result);
}

/* The value is renamed. If there was another value with the
   same name we end up with two values with the same name.
   This does NOT attempt to ensure that the order of the values 
   corresponds to lexicographic order of their names. */
void scolshape_rename_value(scolshape *scs,int value,char *newname)
{
  if ( value < 0 || value >= string_array_size(scs->value_names) )
    my_error("scolshape_rename_value: illegal value");

  delete_hash_entry(scs->value_names_ht,
                    string_array_ref(scs->value_names,value));
  string_array_set(scs->value_names,value,newname);
  add_hash_entry(scs->value_names_ht,newname,(void *)(&value));
}

/* Very efficiently changes all the value names of the 
   given (symbolic) attribute. If the i'th value name was
   previously "xxx" it now becomes "<prefix>xxx". PRE:
   attnum is symbolic and not real */
static void scolshape_valnames_prepend(scolshape *scs,char *prefix)
{
  int v;
  int arity = string_array_size(scs->value_names);
  for ( v = 0 ; v < arity ; v++ )
  {
    char *oldname = string_array_ref(scs->value_names,v);
    char *newname = mk_printf("%s%s",prefix,oldname);
    scolshape_rename_value(scs,v,newname);
    free_string(newname);
  }
}

/* The value is deleted. */
static void scolshape_delete_value(scolshape *scs,int value)
{
  if ( value < 0 || value >= string_array_size(scs->value_names) )
    my_error("scolshape_delete_value: illegal value");

  delete_hash_entry(scs->value_names_ht,
                    string_array_ref(scs->value_names,value));
  string_array_remove(scs->value_names,value);
  
  sort_scolshape_values(scs);
     /* Needed in order to renumber within the hash-table (could
        be more efficient) */
}

rcolshape *mk_rcolshape(char *name)
{
  rcolshape *rcs = AM_MALLOC(rcolshape);
  rcs->name = mk_copy_string(name);
  return(rcs);
}

double rcolshape_value_from_string(rcolshape *rcs,char *s,char **r_errmess)
{
  double result = -7777.77;

  if ( !is_a_number(s) )
  {
    char buff[1000];
    sprintf(buff,"%s is not a legal numeric value for attribute %s",
            s,rcs->name);
    *r_errmess = mk_copy_string(buff);
  }
  else
    result = atof(s);
  return(result);
}

void rcolshape_rename(rcolshape *rcs,char *newname)
{
  free_string(rcs->name);
  rcs->name = mk_copy_string(newname);
}

void scolshape_rename(scolshape *scs,char *newname)
{
  free_string(scs->name);
  scs->name = mk_copy_string(newname);
}

/* It will cause a my_error if you attempt to set major_coltype
   to be UNDEFINED_COL or to the same value as minor_coltype */
colshape *mk_colshape(char *name,int major_coltype,int minor_coltype)
{
  colshape *cs = AM_MALLOC(colshape);

  if ( major_coltype == UNDEFINED_COL || major_coltype == minor_coltype )
    my_error("mk_colshape");
  cs -> major_coltype = major_coltype;
  cs -> minor_coltype = minor_coltype;
  cs -> scs = NULL;
  cs -> rcs = NULL;

  if ( major_coltype == REAL_COL || minor_coltype == REAL_COL )
    cs -> rcs = mk_rcolshape(name);

  if ( major_coltype == SYMBOL_COL || minor_coltype == SYMBOL_COL )
    cs -> scs = mk_scolshape(name);

  return(cs);
}

/* Returns TRUE if and only if cs has SYMBOL_COL as its major or
   minor mode. */
bool colshape_symbol_ref_ok(colshape *cs)
{
  return cs->scs != NULL;
}

/* Returns TRUE if and only if cs has REAL_COL as its major or
   minor mode. */
bool colshape_real_ref_ok(colshape *cs)
{
  return cs->rcs != NULL;
}

/* Returns TRUE if both real and symbol coltypes exist among the
   major and minor coltypes */
bool colshape_both_refs_ok(colshape *cs)
{
  return colshape_real_ref_ok(cs) && colshape_symbol_ref_ok(cs);
}

/* Returns TRUE if and only if cs has coltype as its major or
   minor mode. */
bool colshape_ref_ok(colshape *cs,int coltype)
{
  return (coltype == REAL_COL && colshape_real_ref_ok(cs)) ||
	 (coltype == SYMBOL_COL && colshape_symbol_ref_ok(cs));
}

/* Returns the name of the attribute denoted by colshape */
char *colshape_name(colshape *cs)
{
  return (colshape_real_ref_ok(cs)) ?
         cs->rcs->name : cs->scs->name;
}

void rcolshape_set_attname(rcolshape *rcs,char *new_attname)
{
  free_string(rcs->name);
  rcs->name = mk_copy_string(new_attname);
}

void scolshape_set_attname(scolshape *scs,char *new_attname)
{
  free_string(scs->name);
  scs->name = mk_copy_string(new_attname);
}

void colshape_set_attname(colshape *cs,char *new_attname)
{
  if ( colshape_real_ref_ok(cs) ) rcolshape_set_attname(cs->rcs,new_attname);
  if ( colshape_symbol_ref_ok(cs) ) scolshape_set_attname(cs->scs,new_attname);
}

static void maybe_free_rcolshape(rcolshape **rc_ptr)
{
  if ( *rc_ptr != NULL )
  {
    free_rcolshape(*rc_ptr);
    *rc_ptr = NULL;
  }
}

static void maybe_free_scolshape(scolshape **sc_ptr)
{
  if ( *sc_ptr != NULL )
  {
    free_scolshape(*sc_ptr);
    *sc_ptr = NULL;
  }
}


/* It will cause a my_error if you attempt to set major_coltype
   to be UNDEFINED_COL or to the same value as minor_coltype */
void set_colshape_type(colshape *cs,int major_coltype,int minor_coltype)
{
  if ( major_coltype == UNDEFINED_COL || major_coltype == minor_coltype )
    my_error("set_colshape_type");
  else
  {
    char *name = mk_copy_string(colshape_name(cs));

    if ( major_coltype == REAL_COL || minor_coltype == REAL_COL )
    {
      if ( cs -> rcs == NULL )
	cs -> rcs = mk_rcolshape(name);
    }
    else 
      maybe_free_rcolshape(&cs->rcs);

    if ( major_coltype == SYMBOL_COL || minor_coltype == SYMBOL_COL )
    {
      if ( cs -> scs == NULL )
	cs -> scs = mk_scolshape(name);
    }
    else 
      maybe_free_scolshape(&cs->scs);

    cs -> major_coltype = major_coltype;
    cs -> minor_coltype = minor_coltype;

    free_string(name);
  }
}

/* Changes the attribute name associated with this colshape */
void colshape_rename(colshape *cs,char *newname)
{
  if ( colshape_real_ref_ok(cs)   ) rcolshape_rename(cs->rcs,newname);
  if ( colshape_symbol_ref_ok(cs) ) scolshape_rename(cs->scs,newname);
}

/* Returns TRUE iff the MAJOR coltype of cs is symbolic. */
bool colshape_is_symbolic(colshape *cs)
{
  return cs->major_coltype == SYMBOL_COL;
}

void slow_check_colshape_ref_ok(colshape *cs,int coltype)
{
  if ( !colshape_ref_ok(cs,coltype) )
    my_error("The programmer attempted to access a column-shape\n"
	     "(colshape) an incompatible operation.");
}


/* This function may only be called on a colshape for which
   symbol_ref_ok(cs) */
/* Returns the symbolic name (string) associated with the small integer
   value */
char *colshape_value_to_name(colshape *cs,int value)
{
  check_colshape_ref_ok(cs,SYMBOL_COL);
  return string_array_ref(cs->scs->value_names,value);
}

/* This function may only be called on a colshape for which
   symbol_ref_ok(cs). Returns the number of symbolic values (which
   is thus 1 greater than the maximum value in the attribute) */
int colshape_arity(colshape *cs)
{
  check_colshape_ref_ok(cs,SYMBOL_COL);
  return string_array_size(cs->scs->value_names);
}

/* This function may only be called on a colshape for which
   symbol_ref_ok(cs). MAKES and returns a string array whose ith 
   element is the name of the ith value. */
string_array *mk_colshape_value_names(colshape *cs)
{
  int i;
  string_array *sa = mk_string_array(colshape_arity(cs));
  for ( i = 0 ; i < colshape_arity(cs) ; i++ )
    string_array_set(sa,i,colshape_value_to_name(cs,i));
  return sa;
}

/* REturns a white-space-separated \0-terminated string containing
   the value names of the colshape.
   PRE: colshape_symbol_ref_ok(cs) */ 
char *mk_colshape_value_names_string(colshape *cs)
{
  string_array *sa = mk_colshape_value_names(cs);
  char *s = mk_string_from_string_array(sa);
  free_string_array(sa);
  return s;
}

static int colshape_major_coltype(colshape *cs)
{
  return cs->major_coltype;
}

static int colshape_minor_coltype(colshape *cs)
{
  return cs->minor_coltype;
}

static char *coltype_to_name(int coltype)
{
  char *name = NULL;
  switch ( coltype )
  {
    case REAL_COL: name = "real"; break;
    case SYMBOL_COL: name = "symbolic"; break;
    case UNDEFINED_COL: name = "undefined"; break;
    default: my_error("Unknown coltype"); break;
  }
  return name;
}

/* Saves to s in a way that can later be loaded with load_colshape */
void save_colshape(FILE *s,colshape *cs)
{
  int major_coltype = colshape_major_coltype(cs);
  int minor_coltype = colshape_minor_coltype(cs);
  char *major_string = coltype_to_name(major_coltype);
  char *minor_string = coltype_to_name(minor_coltype);
  fprintf(s,"%s %s ",major_string,(minor_coltype==UNDEFINED_COL)?"":minor_string);

  fprintf(s,"%s ",colshape_name(cs));

  if ( colshape_symbol_ref_ok(cs) )
  {
    char *str = mk_colshape_value_names_string(cs);
    fprintf(s,"values: %s",str);
    free_string(str);
  }
  fprintf(s,"\n");
}

/* Reads from stream using the above format */
colshape *mk_colshape_from_stream(FILE *s,int *line,char **r_errmess)
{
  string_array *sa = mk_next_interesting_line(s,line);
  colshape *cs = NULL;
  int sa_size = string_array_size(sa);
  int major_coltype = UNDEFINED_COL;
  int minor_coltype = UNDEFINED_COL;

  *r_errmess = NULL;

  if ( *r_errmess == NULL && sa_size < 2 )
    *r_errmess = mk_printf("I need at least 2 tokens in a column description");
  else
  {
    char *s0 = string_array_ref(sa,0);
    char *s1 = string_array_ref(sa,1);
    char *real_string = coltype_to_name(REAL_COL);
    char *symbolic_string = coltype_to_name(SYMBOL_COL);
    bool major_real = eq_string(s0,real_string);
    bool major_symbolic = eq_string(s0,symbolic_string);
    if ( !major_real && !major_symbolic )
      *r_errmess = mk_printf("First item should be %s or %s: not %s",
                             real_string,symbolic_string,s0);

    if ( *r_errmess == NULL )
    {
      major_coltype = (major_real) ? REAL_COL : SYMBOL_COL;
      minor_coltype = (eq_string(s1,real_string)) ? REAL_COL : 
                      (eq_string(s1,symbolic_string)) ? SYMBOL_COL : UNDEFINED_COL;

      if ( minor_coltype != UNDEFINED_COL && minor_coltype == major_coltype )
        *r_errmess = mk_printf("major and minor coltypes must not be the same");
    }
  }
   
  if ( *r_errmess == NULL )
  {
    int idx = (minor_coltype == UNDEFINED_COL) ? 1 : 2;
    if ( sa_size < idx+1 )
      *r_errmess = mk_printf("I'm missing the name and values");
    
    if ( *r_errmess == NULL )
    {
      char *name = string_array_ref(sa,idx);
      cs = mk_colshape(name,major_coltype,minor_coltype);

      if ( colshape_symbol_ref_ok(cs) )
      {
        if ( sa_size < idx+2 )
          *r_errmess = mk_printf("I'm missing values: <values>");
        else
        {
          int i;
          for ( i = idx+2 ; i < sa_size ; i++ )
            scolshape_add_value_name(cs->scs,string_array_ref(sa,i));
        }
      }
    }
  }

  if ( *r_errmess != NULL && cs != NULL )
  {
    free_colshape(cs);
    cs = NULL;
  }

  if ( *r_errmess != NULL )
  {
    char *fullmess = mk_printf("Column Description should be one of:\n"
                               "  real <name>\n"
                               "  symbolic <name> values: <value_names>\n"
                               "  real symbolic <name> values: <value_names>\n"
                               "  symbolic real <name> values: <value_names>\n"
                               "But I encountered the following problem:\n%s\n",*r_errmess);
    free_string(*r_errmess);
    *r_errmess = fullmess;
  }

  if ( sa != NULL ) free_string_array(sa);

  return(cs);
}

/* If the name is not already present in the list of symbols, it is added.
   This does NOT attempt to ensure that the order of the values 
   corresponds to lexicographic order of their names. */
/* PRE: colshape_symbol_ref_ok(cs) */
void colshape_add_value_name(colshape *cs,char *name)
{
  check_colshape_ref_ok(cs,SYMBOL_COL);
  scolshape_add_value_name(cs->scs,name);
}

/* Very efficiently changes all the value names of the 
   given (symbolic) attribute. If the i'th value name was
   previously "xxx" it now becomes "<prefix>xxx". PRE:
   attnum is symbolic and not real */
void colshape_valnames_prepend(colshape *cs,char *prefix)
{
  check_colshape_ref_ok(cs,SYMBOL_COL);
  scolshape_valnames_prepend(cs->scs,prefix);
}

/* For each name in turn, if the name is not already present in the list of
   symbols, it is added.
   This does NOT attempt to ensure that the order of the values 
   corresponds to lexicographic order of their names. */
/* PRE: colshape_symbol_ref_ok(cs) */
void colshape_add_value_names(colshape *cs,string_array *value_names)
{
  int i;
  for ( i = 0 ; i < string_array_size(value_names) ; i++ )
    colshape_add_value_name(cs,string_array_ref(value_names,i));
}

/* Afterwards there are no symbolic names */
void colshape_remove_all_value_names(colshape *cs)
{
  check_colshape_ref_ok(cs,SYMBOL_COL);
  scolshape_remove_all_value_names(cs->scs);
}

/* Irrespective of previous symbolic values, they are replaced
   with value_names.
   This does NOT attempt to ensure that the order of the values 
   corresponds to lexicographic order of their names. */
/* PRE: colshape_symbol_ref_ok(cs) */
void colshape_set_value_names(colshape *cs,string_array *value_names)
{
  colshape_remove_all_value_names(cs);
  colshape_add_value_names(cs,value_names);
}

/* Returns -1 if no such value name exists */
/* PRE: colshape_symbol_ref_ok(cs) */
int colshape_name_to_value(colshape *cs,char *s)
{
  check_colshape_ref_ok(cs,SYMBOL_COL);
  return scolshape_name_to_value(cs->scs,s);
}

/* The value is renamed. If there was another value with the
   same name we end up with two values with the same name.
   This does NOT attempt to ensure that the order of the values 
   corresponds to lexicographic order of their names. */
/* PRE: colshape_symbol_ref_ok(cs) */
void colshape_rename_value(colshape *cs,int value,char *newname)
{
  check_colshape_ref_ok(cs,SYMBOL_COL);
  scolshape_rename_value(cs->scs,value,newname);
}

/* The value is deleted. */
/* PRE: colshape_symbol_ref_ok(cs) */
void colshape_delete_value(colshape *cs,int value)
{
  check_colshape_ref_ok(cs,SYMBOL_COL);
  scolshape_delete_value(cs->scs,value);
}

/* If string can be parsed as a symbolic value, returns the small-int-value
   asociated with that string. Sets *r_errmess to be NULL.

   If it can't returns -1, and sets *r_errmess to a AM_MALLOCKED
   null-terminated error message that must eventually be free with
   free_string(...) */
int colshape_symbol_value_from_string(colshape *cs,char *name,
				      char **r_errmess)
{
  check_colshape_ref_ok(cs,SYMBOL_COL);
  return scolshape_value_from_string(cs->scs,name,r_errmess);
}

/* If string can be parsed as a realic value, returns the small-int-value
   asociated with that string. Sets *r_errmess to be NULL.

   If it can't returns -1, and sets *r_errmess to a AM_MALLOCKED
   null-terminated error message that must eventually be free with
   free_string(...) */
double colshape_real_value_from_string(colshape *cs,char *name,
                                       char **r_errmess)
{
  check_colshape_ref_ok(cs,REAL_COL);
  return rcolshape_value_from_string(cs->rcs,name,r_errmess);
}

void colshape_sort_values(colshape *cs)
{
  check_colshape_ref_ok(cs,SYMBOL_COL);
  sort_scolshape_values(cs->scs);
}

/* Adds value_name into the list of names of the given attnum,
   inserting at the appropriate position to ensure that the
   values remain in lexicographic order. Returns the small int
   integer value of the new value name. You may assume that if some
   other value_name had small int value v before then afterwards
   it has...

     ...value v if v < result
     ...value v+1 if v >= result

   where result is the result of this function (i.e. the new symbol_value
   of the new value_name)
*/
int colshape_insert_value_name(colshape *cs,char *value_name)
{
  check_colshape_ref_ok(cs,SYMBOL_COL);
  return scolshape_insert_value_name(cs->scs,value_name);
}
