/*
 * REBUILD.C - rebuild index and data files (remove deleted records)
 *
 *                      Copyright (c) 1988, Jim Mischel
 * Modifications:
 *
 * 01/30/88 - jim - initial coding
 */

/* #define DEBUG */

#include "inxdefs.h"
#include <dos.h>

#ifdef DEBUG
#include <conio.h>
#endif

/*
 * Remove deleted records.
 * This is a father/son rebuild.  The resulting index and data files are
 * in optimum search order.
 *
 * The file to be rebuilt should not be open when this function is called.
 *
 * Returns 0 on success, standard error code otherwise.
 *
 * If a file with the same name as new_fname exists, the function will
 * exit with an error.
 */

FILE *f_;
df_rec *new_file_;
char *dat_buff;

int irebuild (char *old_fname, unsigned rec_size, unsigned offset,
	      char dupflag, int (*cmp_rtn)(), char *new_fname)

{
    df_rec *old_file;
    long nrecs;
    void do_build(long min, long left, long right, long max);

    printf("Rebuilding file %s to %s\n",old_fname,new_fname);

    /* If the new file already exists, exit with an error */
    if ((f_ = fopen(new_fname,"r")) != NULL) {
        fclose(f_);
        return(1);
    }

    /* open files */
    if ((old_file = iopen(old_fname,rec_size,offset,dupflag,cmp_rtn)) == NULL)
        return(ierrno);

    /* open dummy data file for writing */
    if ((f_ = fopen("!REBLD!.$$$","wb")) == NULL)
        return(1);
      
    if (istart(old_file,START_FILE,NULL)) 	/* read file sequentially */
        return(ierrno);

    /* allocate temporary record buffer */
    if ((dat_buff = (char *) malloc(rec_size)) == NULL) {
        ierrno = I_NOMEM;
        return(ierrno);
    }

    nrecs = 0;

    /*
     * Rebuild in two steps:
     * 1) copy data records in sequential order to a temporary file.
     * 2) Build new file in balanced fashion.
     */
    puts("Copy data records");
    while (!iread_next(old_file,dat_buff)) {
        if (fwrite(dat_buff,rec_size,1,f_) != 1) {
            ierrno = I_DATWT;
            return(ierrno);
        }
        nrecs++;
    }
    fclose(f_);
    iclose(old_file);
    
    /* open dummy data file for reading */
    if ((f_ = fopen("!REBLD!.$$$","rb")) == NULL)
        return(1);

    /*
     * now do a balanced insert
     */
    if ((new_file_ = iopen(new_fname,rec_size,offset,dupflag,cmp_rtn)) == NULL) {
        iclose(old_file);
        return(ierrno);
    }
    puts("Building new index and data files");
    do_build(0,1,nrecs+1,nrecs+2);

    /*
     * close up shop and exit
     */
    fclose(f_);
    unlink("!REBLD!.$$$");
    iclose(new_file_);
    free(dat_buff);
    return(ierrno);
} /* irebuild */

void do_build(long min, long left, long right, long max)
{
    long dat_pos;
    long node = (left+right)/2;

    if (node > min && node < max) {
#ifdef DEBUG
        printf("node=%ld\n",node);
        if (getch() == 27) {
            ierrno = 1;
            return;
        }
#endif
        dat_pos = (node-1) * new_file_->df_rec_size;
        fseek(f_,dat_pos,SEEK_SET);
        fread(dat_buff, new_file_->df_rec_size,1,f_);
        iwrite(new_file_, dat_buff);
        do_build(min,left,node,node);
        do_build(node,node,right,max);
    }
}
