/*
 * eb_select.c
 *
 * This file belongs to the EasyBase program.
 * It contains routines for making selections in the data.
 *
 * Written by Mark Overmars
 *
 * Version 1.0
 * Last Changed: Sep 18, 1992
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>

#include "eb_main.h"


/*******************************************
 *********        SELECTING        *********
 *******************************************/


/*********
 *  void level_up()
 *	Go up one level in the selection hierarchy.
 *********/

void level_up()
{
  int i;
  if (selectlevel == 0) return;
  for (i=1; i <= recordnumb; i++)
    if (database[i].level == selectlevel) database[i].level--;
  selectlevel--;
}


/*********
 *  void level_zero()
 *	Go up to level 0 in the selection hierarchy.
 *********/

void level_zero()
{
  int i;
  if (selectlevel == 0) return;
  for (i=1; i <= recordnumb; i++)
    if (database[i].level > 0) database[i].level = 0;
  selectlevel = 0;
}


/*********
 *  static int do_test(char fdata[],  char pat[],  int oper)
 *	Performs test oper on field data and pattern. Returns wherther
 *	successful.
 *		fdata		= the contents of the field
 *		pat		= the selection pattern with which to compare
 *		oper		= the operation (see below)
 */
 
static int do_test(char fdata[],  char pat[],  int oper)
{
    switch (oper) {
	case 0:  /* Contains */
	  return (strstr(fdata,pat) != NULL);
	case 1:  /* Equal */
	  return (strcmp(fdata,pat) == 0);
	case 2:  /* Smaller */
	   (strcmp(fdata,pat) < 0);
	case 3:  /* Smaller or Equal */
	  return (strcmp(fdata,pat) <= 0);
	case 4:  /* Numeric Equal */
	  return (atof(fdata) == atof(pat));
	case 5:  /* Numeric Smaller */
	  return (atof(fdata) < atof(pat));
	case 6:  /* Numeric Smaller or Equal */
	  return (atof(fdata) <= atof(pat));
      }
   
}

/*********
 * void make_selection(int extend, int field, int oper, int inverse, char pat[])
 *	Makes a selection in the database, either extending or restricting
 *	the current selection.
 *		extend		= whether to extend the selection
 *		field		= the field on which to select (>=1)
 *		oper		= the operation (see below)
 *		inverse		= whether to inverse the operation
 *		pat		= the selection pattern with which to compare
 *********/

void make_selection(int extend, int field, int oper, int inverse, char pat[])
{
  int i,j, ok;
  char fdata[MAXFIELDLENGHT];
  if (extend && selectlevel > 0) selectlevel--;
  for (i=1; i <= recordnumb; i++)
    if (database[i].level == selectlevel)
    {
      if (field < 0)
      {
	  ok = 0;
	  for (j=0; j<fieldnumb && !ok; j++)
	  {
	    string_to_field(database[i].data, fdata, j);
	    ok = do_test(fdata, pat, oper);
	  }
      }
      else
      {
        string_to_field(database[i].data, fdata, field);
        ok = do_test(fdata, pat, oper);
      }
      if (inverse) ok = !ok;
      if (ok) database[i].level++;
    }
  selectlevel++;

  /* Check whether anything has been selected. */
  for (i=1; i <= recordnumb; i++)
    if (database[i].level == selectlevel)
      return;
  fl_show_message("No records selected!","",""); selectlevel--;
}


/*******************************************
 *********         SORTING         *********
 *******************************************/

/*********
 * void sort_database(int field, int increasing, int style)
 *	Sort the complete database using a (stable) merge sort.
 *		field		= field on which to sort (>=1)
 *		increasing	= whether increasing
 *		style		= 0 (normal) 1 (case insensitive) 2 (numeric)
 *********/

static RECORD ttt[MAXRECORD];	/* For merging */

static void sortit(int low, int high, int field, int incr, int style)
/* Sort the piece from low to high */
{
  int mid,i,j,k;
  float res;
  char fdata[MAXFIELDLENGHT];
  char fdata2[MAXFIELDLENGHT];
  if (low>=high) return;
  /* Recursice calls */
  mid = (low+high)/2;
  sortit(low,mid,field,incr,style);
  sortit(mid+1,high,field,incr,style);
  /* Merge them */
  i = low; j = mid+1; k = low;
  while (i<=mid || j<=high)
  {
    if (i>mid) ttt[k++] = database[j++];
    else if (j>high) ttt[k++] = database[i++];
    else
    {
      string_to_field(database[i].data,fdata,field);
      string_to_field(database[j].data,fdata2,field);
      if (style == 0)
        res = strcmp(fdata,fdata2);
      else if (style == 1)
        res = strcasecmp(fdata,fdata2);
      else
	res = atof(fdata) - atof(fdata2);
      if ((incr && res<=0) || (!incr && res>=0))
        ttt[k++] = database[i++];
      else
        ttt[k++] = database[j++];
    }
  }
  for (i=low; i<=high; i++) database[i] = ttt[i];
}

void sort_database(int field, int increasing, int style)
{
  sortit(1,recordnumb,field,increasing,style);
  find_first();
}

