/*
 * eb_data.c
 *
 * This file belongs to the EasyBase program.
 * It contains the data structure and the lowlevel handling routines.
 *
 * Written by Mark Overmars
 *
 * Version 0.9
 * Last Changed: Sep  7, 1992
 */

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

#include "eb_main.h"


/************************ EXTERNAL VARIABLES ***************************/


RECORD database[MAXRECORD];       /* The database */
int recordnumb;          /* Number of records in the database */
int fieldnumb;           /* Number of fields in a record */
int selectlevel;         /* Level of selection */
int changed;             /* Whether database has been changed by user */
int currentrecord;       /* Index of the current record */
int deletioncount;       /* Level counter for deleted records (<0) */


/************************ EXTERNAL ROUTINES ***************************/


/*******************************************
 *********  UPDATING THE DATABASE  *********
 *******************************************/


/*********
 *  void change_record(int ind, char str[])
 *	Changed the contents of a particular record in the database.
 *		ind		= index of the record
 *		str		= new contents
 *********/

void change_record(int ind, char str[])
{
  int l;
  if (ind >= MAXRECORD)
    printf("Internal Error: record index too large\n");
  else if (ind < 0)
    printf("Internal Error: record index less than 0\n");
  else
  {
    if (database[ind].dsize == 0 || strcmp(str,database[ind].data) != 0)
      changed = 1;
    l = strlen(str)+1;
    if (l>database[ind].dsize)
    {
      if (database[ind].dsize == 0)
        database[ind].data = (char *) malloc(l);
      else
        database[ind].data = (char *) realloc(database[ind].data,l);
      database[ind].dsize = l;
    }
    strcpy(database[ind].data,str);
  }
}


/*********
 *  void append_record()
 *	Appends an empty record after the current record.
 *********/

void append_record()
{
  int i;
  RECORD rec;
  if (recordnumb == MAXRECORD)
    { fl_show_message("Cannot add another record.","",""); return; }
  recordnumb++;
  rec = database[recordnumb];
  for (i=recordnumb; i>currentrecord+1; i--) database[i] = database[i-1];
  currentrecord++;
  database[currentrecord] = rec;
  change_record(currentrecord,"\0");
  database[currentrecord].level = selectlevel;
  changed = 1;
}


/*********
 *  void insert_record()
 *	Inserts an empty record before the current record.
 *********/

void insert_record()
{
  int i;
  RECORD rec;
  if (recordnumb == MAXRECORD)
    { fl_show_message("Cannot insert another record.","",""); return; }
  recordnumb++;
  rec = database[recordnumb];
  for (i=recordnumb; i>currentrecord; i--) database[i] = database[i-1];
  database[currentrecord] = rec;
  change_record(currentrecord,"\0");
  database[currentrecord].level = selectlevel;
  changed = 1;
}
  

/*********
 *  void delete_record()
 *	Deletes the current record.
 *********/

void delete_record()
{
  database[currentrecord].level = deletioncount--;
  changed = 1;
  if (find_next()) return;
  if (find_first()) return;
  while (selectlevel > 0 && !find_first())
  {
    selectlevel--;    
  }
  if (!find_first())
    { currentrecord = recordnumb; append_record(); }
}


/*********
 *  void undelete_record()
 *	Undoes the last deletion.
 *********/

void undelete_record()
{
  int i;
  if (deletioncount == -1)
    { fl_show_message("No deleted records.","",""); return;}
  deletioncount++;
  for (i=1; i <= recordnumb; i++)
    if (database[i].level == deletioncount)
    {
      currentrecord = i;
      database[i].level = selectlevel;
      return;
    }
  printf("Internal Error: Cannot find record to undelete.\n");
}


/*******************************************
 *********      MOVING AROUND      *********
 *******************************************/


/*********
 *  int find_first()
 *	Goes to the first record in the current level. Returns whether 
 *	successful.
 *********/

int find_first()
{
  int i;
  for (i=1; i <= recordnumb; i++)
    if (database[i].level == selectlevel)
      { currentrecord = i; return TRUE; }
  return FALSE;
}


/*********
 *  int find_next()
 *	Goes to the next record in the current level. Returns whether 
 *	successful.
 *********/

int find_next()
{
  int i;
  for (i=currentrecord+1; i<=recordnumb; i++)
    if (database[i].level == selectlevel)
      { currentrecord = i; return TRUE; }
  return FALSE;
}


/*********
 *  int find_previous()
 *	Goes to the previous record in the current level. Returns whether 
 *	successful.
 *********/

int find_previous()
{
  int i;
  for (i=currentrecord-1; i>0; i--)
    if (database[i].level == selectlevel)
      { currentrecord = i; return TRUE; }
  return FALSE;
}


/*********
 *  int find_last()
 *	Goes to the last record in the current level. Returns whether 
 *	successful.
 *********/

int find_last()
{
  int i;
  for (i = recordnumb; i>0; i--)
    if (database[i].level == selectlevel)
      { currentrecord = i; return TRUE; }
  return FALSE;
}


/*********
 *  int find_number(int numb)
 *	Goes to record numb in the current level. Returns whether 
 *	successful.
 *********/

int find_number(int numb)
{
  int i, count = 0;
  for (i=1; i <= recordnumb; i++)
  {
    if (database[i].level == selectlevel) count++;
    if (count == numb) { currentrecord = i; return TRUE; }
  }
  return FALSE;
}


/*******************************************
 *********        INFORMATION      *********
 *******************************************/


/*********
 *  void get_database_info(int *total, int *selected, int *current)
 *	returns some information about the current state of the database.
 *		*total		= total number of (undeleted) records
 *		*selected	= number of selected records
 *		*current	= number of the current record in selection
 *********/

void get_database_info(int *total, int *selected, int *current)
{
  int i;
  *total = 0;
  *selected = 0;
  for (i=1; i <= recordnumb;i++)
  {
    if (database[i].level >= 0) *total += 1;
    if (database[i].level == selectlevel) *selected +=1;
    if (i == currentrecord) *current = *selected;
  }
}


/*********
 *  void get_field_name(int field, char *fieldname)
 *	Returns the name of a field.
 *		field		= the field number (>=1)
 *		fieldname	= string in which name is returned
 *********/

void get_field_name(int field, char *fieldname)
{
  string_to_field(database[0].data,fieldname,field-1);
}

