/*
   File:        query.h
   Author:      Andrew W. Moore
   Created:     Wed Dec 30 05:28:24 EST 1998
   Description: Header for Query for symbolic dsets

   Copyright 1998, Schenley Park Research, Inc
*/


#ifndef QUERY_H
#define QUERY_H
#include "dsut.h"

typedef struct query
{
  ivec *attnums;
  ivec *values;
} query;

query *mk_empty_query(void);
void free_query(query *q);

#ifdef AMFAST
#define query_size(q) ivec_size(q->attnums)
#define query_attnum_ref(q,idx) ivec_ref((q)->attnums,idx)
#define query_value_ref(q,idx) ivec_ref((q)->values,idx)
#else
#define query_size(q) slow_query_size(q)
#define query_attnum_ref(q,idx) slow_query_attnum_ref(q,idx)
#define query_value_ref(q,idx) slow_query_value_ref(q,idx)
#endif

int slow_query_size(query *q);
int slow_query_attnum_ref(query *q,int idx);
int slow_query_value_ref(query *q,int idx);

/* Adds "attnum == value" to the query, maintaining the invariant that
   the attnums are stored in ascending order with no duplicates. If attnum
   is already in the query, its corresponding value is overwritten. Else
   the query size is increased by one. */
void add_to_query(query *q,int attnum,int value);

/* It's okay if attnums is out of order... this reorders them.
   If attnums contains duplicates, then the rightmost occurence
   is the value that is remembered */  
query *mk_query(ivec *attnums,ivec *values);

/* Makes a query from the given attnums
   and values. It's an error to call if attnums are not sorted. 
   Important warning... if you want to make an query from unsorted
   atts, you should use mk_query(...).

   Use this if you want some slight extra efficiency over
   mk_query(...) in cases where you happen to know attnums
   will be sorted.  */
query *mk_query_from_sorted_attnums(ivec *attnums,ivec *values);

/* Syntax: A bunch of <attribute> <value> pairs, with (optionally)
   equal-signs and commas as separators. Examples of legal queries..

     "gender=female,state=pa"
     "  gender female     state== pa    , agegroup = young"
     */
query *mk_query_from_string(datset *ds,char *string,char **r_errmess);

/* Syntax as above */
query *mk_query_from_string_array(datset *ds,string_array *sa,
				  char **r_errmess);

char *mk_string_from_query(datset *ds,query *q);
void pquery(datset *ds,query *q);

/* Uses attribute names unless ds is NULL in which case
   just draws raw integers */
void fprintf_query_basic(FILE *s,char *m1,char *equals,
                         datset *ds,query *q,char *m2);

void fprintf_query(FILE *s,char *m1,query *q,char *m2);

void explain_query(datset *ds,query *q);
int query_attnum_to_index(query *q,int attnum);
bool query_contains_attnum(query *q,int attnum);
void query_remove_index(query *q,int idx);
void query_remove_attnum(query *q,int attnum);
void query_unite_second_into_first(query *q1,query *q2);
void query_remove_attnums(query *q,ivec *attnums);
ivec *query_attnums(query *q);
ivec *query_values(query *q);
query *mk_copy_query(query *q);

/* Returns TRUE if and only if "a" refers to a strict
   subset of the attribute/value pairs in "b". */
bool query_strictly_more_general(query *a,query *b);

bool ivec_strictly_increasing(ivec *iv);
void slow_check_attnums_increasing(ivec *attnums);

#ifdef AMFAST
#define check_attnums_increasing(attnums) /* do nothing */
#else
#define check_attnums_increasing(attnums) \
            slow_check_attnums_increasing(attnums)
#endif


#endif /* #ifndef QUERY_H */
