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

   Copyright 1999, Schenley Park Research
*/


#ifndef COLSHAPE_H
#define COLSHAPE_H
#include "amut.h"
#include "pivec.h"
#include "hash.h"

/* Private... */
#define UNDEFINED_COL 0
#define REAL_COL      1
#define SYMBOL_COL    2

#define UNKNOWN_STRING "?"

/* Represents all the necessary information about values of a symbolic 
   attribute.  Note the last two elements are intertwined.  The first
   is an array of symbol names, which is useful for looking up the actual
   character strings from an index, specifying which value the attribute
   holds.  The second is a hash table storing these indices, which is
   keyed by the character string itself.  Note that this means we store
   each character string twice.  If this becomes a problem, we can make
   it more efficient. */
typedef struct scolshape
{
  char *name;  /* The name of the symbolic attribute */
  string_array *value_names; /* One entry for each possible value of
                                 the attribute. */
  hash_table *value_names_ht; /* Hash table for each possible value of
                                  an attribute.  The table stores an index,
                                  which is the position of the name in the
                                  symbols_names array. */
} scolshape;

/* Represents all necessary info about a real attribute */
typedef struct rcol_shape
{
  char *name; /* The name of the real attribute */
} rcolshape;

/* A colshape defines whether an attribute is real or symbolic.

   This is defined to be the major coltype of the colshape. However it
   is legal for colshapes to optionally have a minor coltype. If there
   is no minor type we define that minor_coltype is UNDEFINED_COL. But
   if there *is* a minor coltype it must be SYMBOL if major is REAL and
   it must be REAL if major is SYMBOL.

   What are minor coltypes for? Some columns, such as those that have
   been converted from real to symbolic, like to keep their real
   values around, just in case they ever need to be unsymbolized, or for the
   purposes of visualization, or for the purpose of future REAL-adtrees. */
typedef struct colshape 
{
  int major_coltype;  /* Either REAL_COL or SYMBOL_COL */
  int minor_coltype;  /* UNDEFINED, REAL or SYMBOL, must not be the same 
                         as major coltype */
  scolshape *scs;  /* non-NULL only if SYMBOL_COL */
  rcolshape *rcs;  /* non-NULL only if REAL_COL */
} colshape;

#ifdef AMFAST
#define check_colshape_ref_ok(cs,coltype)
#else
void slow_check_colshape_ref_ok(colshape *cs,int coltype);
#define check_colshape_ref_ok(cs,coltype) slow_check_colshape_ref_ok(cs,coltype)
#endif

void free_colshape(colshape *x);
void free_scolshape(scolshape *x);
bool scolshape_equal(scolshape *x1,scolshape *x2);
void free_rcolshape(rcolshape *x);
bool rcolshape_equal(rcolshape *x1,rcolshape *x2);
scolshape *mk_copy_scolshape(scolshape *x);
rcolshape *mk_copy_rcolshape(rcolshape *x);
void fprintf_scolshape(FILE *s,char *m1,scolshape *x,char *m2);
void fprintf_rcolshape(FILE *s,char *m1,rcolshape *x,char *m2);
scolshape *mk_scolshape(char *name);
int scolshape_name_to_value(scolshape *scs,char *s);
void scolshape_add_value_name(scolshape *scs,char *name);
int scolshape_value_from_string(scolshape *scs,char *s,char **r_errmess);
void scolshape_rename_value(scolshape *scs,int value,char *newname);
rcolshape *mk_rcolshape(char *name);
double rcolshape_value_from_string(rcolshape *rcs,char *s,char **r_errmess);
void rcolshape_rename(rcolshape *rcs,char *newname);
void scolshape_rename(scolshape *scs,char *newname);
char *mk_colshape_value_names_string(colshape *cs);

/* Returns TRUE if and only if the two colshapes are identical
   is all respects */
bool colshape_equal(colshape *c1,colshape *c2);

colshape *mk_copy_colshape(colshape *x);

void fprintf_colshape(FILE *s,char *m1,colshape *x,char *m2);

/* 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);

/* Returns TRUE if and only if cs has SYMBOL_COL as its major or
   minor mode. */
bool colshape_symbol_ref_ok(colshape *cs);

/* Returns TRUE if and only if cs has REAL_COL as its major or
   minor mode. */
bool colshape_real_ref_ok(colshape *cs);

/* Returns TRUE if both real and symbol coltypes exist among the
   major and minor coltypes */
bool colshape_both_refs_ok(colshape *cs);

/* Returns TRUE if and only if cs has coltype as its major or
   minor mode. */
bool colshape_ref_ok(colshape *cs,int coltype);

/* Returns the name of the attribute denoted by colshape */
char *colshape_name(colshape *cs);

void colshape_set_attname(colshape *cs,char *new_attname);

/* 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);

/* Changes the attribute name associated with this colshape */
void colshape_rename(colshape *cs,char *newname);

/* Returns TRUE iff the MAJOR coltype of cs is symbolic. */
bool colshape_is_symbolic(colshape *cs);

/* 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);

/* 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);

/* 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);

/* Saves to s in a way that can later be loaded with load_colshape */
void save_colshape(FILE *s,colshape *cs);

/* Reads from stream using the above format */
colshape *mk_colshape_from_stream(FILE *s,int *line,char **r_errmess);

/* 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);

/* 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);

/* 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);

/* Afterwards there are no symbolic names */
void colshape_remove_all_value_names(colshape *cs);

/* 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);

/* Returns -1 if no such value name exists */
/* PRE: colshape_symbol_ref_ok(cs) */
int colshape_name_to_value(colshape *cs,char *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);

/* The value is deleted. */
/* PRE: colshape_symbol_ref_ok(cs) */
void colshape_delete_value(colshape *cs,int 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);

/* 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);

void colshape_sort_values(colshape *cs);

/* 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);

#endif /* #ifndef COLSHAPE_H */
