/* *
   File:        join.h
   Author:      Andrew W. Moore
   Created:     Sun Jul 18 09:17:40 EDT 1999
   Description: Header for Joing of two datasets through 1 or more linked attributes

   Copyright 1999, Schenley Park Research
*/


#ifndef JOIN_H
#define JOIN_H
#include "compat.h"
#include "command.h"
#include "dsut.h"

/* PRE: attnums1 is a list (not just set) of attnums in ds1
        attnums2 is a list (not just set) of attnums in ds2
        order matters in both sets of attnums
        both sets of attnums must be symbolic
        both sets must be the same size
        For any i, Let
           a1 = attnums1[i]
           a2 = attnums2[i]
        Then we insist that the a1'th attribute of ds1 has the same shape
          as the a2'th attribute of ds2: i.e. the same arity, and the k'th
          value of the a1'th attribute of ds1 must have the same name as 
          the k'th value of the a2'th attribute of ds2.
        Finally we insist that in ds2 no two records have the same joint
        values of the attnums2 attributes.

   POST: For each attribute that exists in ds2 that is NOT included in
         attnums2, a new attribute with the same name will be added to ds1.
         Suppose attnum is an attribute in ds2 that's not mentioned in attnums2.
         Then attnum will be a new attribute in ds1 and the value of it on the
         k'th record in ds1 will be the same as the value that attnum has in
         the unique record in ds2 for which the values of all the things in attnums2
         are bthe same as all the things in attnums1.
*/
void ds_join(datset *ds1,datset *ds2,
	     ivec *attnums1,ivec *attnums2,
	     char **r_errmess);

string_array *mk_miner_file_exts(void);

void run_join_command(datset *ds,command *c);

/* Re-orders the rows of the datset according to permute.
   The i'th row of the old datset becomes the permute[i]'th
   row of the new datset. 

  PRE: permute must be a permutation (i.e. some ordering
  of the integers 0, 1, 2 , .. ds_num_rows(ds);-1 ); */
void ds_permute(datset *ds,ivec *permute);

ivec *mk_anti_permute(const ivec *permute);

/* Returns permute such that if ds was permuted according to
   permute it would be in lexicographic sorted order where the
   primary lexicographic key is attnums[0], 2ndary is
   attnums[1] etc. 

   Rows which are equal according to this lexicography remain
   in the same relative order. */
ivec *mk_sorted_datset_permute(datset *ds,ivec *attnums);

/* Sorts ds in lexicographic order
   primary lexicographic key is attnums[0], 2ndary is
   attnums[1] etc. 

   Rows which are equal according to this lexicography remain
   in the same relative order. */
void ds_sort(datset *ds,ivec *attnums);

bool ds_values_are_same(datset *ds,int row1,int row2,int attnum);

bool rows_are_identical_in_attributes(datset *ds,ivec *attnums,
				      int row1,int row2);

/* Deletes all the records mentioned in "rows", thus reducing
   the dataset size by ivec_size(rows).

    Note that the relative ordering of the remaining records is
    unchanged.
*/
/* rows may be null meaning "delete all records" */
void ds_delete_rows(datset *ds,ivec *rows);

/* Consider the k'th record in the dataset. If there is some i such
   that
     i < k
   and
     forall j = 0 , 1 , .. n-1
        ds[i,attnums[j]] == ds[k,attnums[j]]

   (in English, if there is some earlier record that matches the j'th
    record in each of the attributes mentioned in attnums....)

    ....then the k'th record is removed. 

    This process occurs for all k. Thus at the end, there will
    be no duplications in combined values for attnums[0]...attnums[S-1]
    between any pair of records.

    Note that the relative ordering of the remaining records is
    unchanged.
*/
void ds_remove_duplicates(datset *ds,ivec *attnums);

/* Increases the length of ds1 by ading in copies of the entire
   contents of ds2. 

   ds2 is almost unchanged. (some of the attributes might be compatibalized
   with ds1).

   If succeeds, sets *r_errmess to NULL.

   If fails, sets *r_errmess to a null terminated string (which must be
   free_string()'d) explaining why it couldn't concatenate.

   It will fail if the datsets have different shapes.

   If rename_ds2_atts is FALSE it will fail if the i'th attribute of 
   ds2 has a different name than the i'th attribute of ds1.

   If rename_ds2_atts is TRUE it will succeed if they have different
   shapes provided the attributes can be compatibalized.
 
   (see ds_compat documentation to see what it means for two attributes
   to be compatibalized).
*/
void ds_concatenate(datset *ds1,datset *ds2,
		    bool rename_ds2_atts,char **r_errmess);

/* Just the same as ds_concatenate except my_error()'s if there's a problem.
   This does rename attributes if necessary to ensure compatibility. */
void ds_concatenate_simple(datset *ds1,datset *ds2);

void run_concatenate_command(datset *ds,command *c);

/* Updates ds by adding from "filename". Alters ds's shape if necessary
   so that it's compatted with filename. If impossible to concat, does 
   nothing, but sets *r_errmess to be an AM_MALLOCKED string (that
   must be freed with free_string). If no problem, sets *r_errmess
   to be NULL */
void ds_concatenate_from_file(datset *ds,const char *filename,char **r_errmess);

/* Sets *r_errmess to NULL if no problem.

   Returns NULL and sets *r_errmess to a string that
   must eventually be free_string'd if there's a problem. */
datset *mk_datset_from_filenames(string_array *filenames,char **r_errmess);


/* Returns an attnum or else -1 denoting "no attribute".

   Default may be -1 denoting "default is none"

   options is a string:

      if contains 'n' allows the user to state "none"
      if contains 'r' allows the user to select real attribute
      if contains 's' allows the user to select symbol attribute
      if contains 'm" allows the user to select attribute with missing values
    If on entry, *okay is FALSE, this function does nothing, and returns -77

    If user cancels, or not possible satisfy constraints, set *okay to FALSE,
    prints an error message and returns -77.
*/
int attnum_from_command(command *c,datset *ds,char *key,char *options,int default_attnum,
                        bool *okay);

void ds_delete_row(datset *ds,int row);

void ds_remove_missing_rows_and_atts(datset *ds);

void ds_remove_unused_values(datset *ds,int attnum);

void ds_add_cartesian_attribute(datset *ds,char *name,ivec *attnums);

/* Returns TRUE if changes datset */
bool run_add_cartesian_attribute(command *c,datset *ds);

datset *mk_sheared_datset(datset *base,int row_attnum,
                          int col_attnum,int cell_attnum);

datset *mk_sheared_from_command(command *c,datset *ds);

/* Returns NULL if there's a problem */
datset *mk_run_transpose(command *c,datset *ds);

/* XXX DOES NOT BELONG HERE */
void ivec_swap_elements(ivec *iv,int i,int j); /* XXX This belongs in amiv.c */

#endif /* #ifndef JOIN_H */
