/***********************************************
*   MDEDIT.C                                   *
*                                              *
*   Program:        Mini-Database              *
*   Written by:     Leor Zolman                *
*   Module:         Edit the Current Database  *
************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "mdb.h"

static void fix_db(void);

#define LIST_RECS   1    /* Edit menu action codes */
#define NEXT        2
#define PREVIOUS    3
#define MODIFY      4
#define NEW         5
#define DELETE      6
#define UNDELETE    7
#define QUIT        8
#define SELECT      9
#define FIX        10

static struct menu_item edit_menu[] = {
    {LIST_RECS, "List Records"},
    {NEXT, "Go to Next Record"},
    {PREVIOUS, "Go to Previous Record"},
    {MODIFY, "Modify Current Record"},
    {NEW, "Add New Record"},
    {DELETE, "Delete Current Record"},
    {UNDELETE, "Un-Delete Current Record"},
    {SELECT, "Select Record (by Record Number)"},
    {FIX, "Fix Up Database"},
    {QUIT, "Return to Main Menu"},
    {'\0'}
};

/**************************************************
 * Function:        edit_db
 * Purpose:         Perform operations on current 
                      Database
 * Parameter:       Database Name
 * Return Value:    None
 */

void edit_db(char *db_name) {
  int     cur_rec = 0; /* current record number */
  struct  record *rp;
  char    buf[150];
  int     i;

  while (1) {
     rp = RECS[cur_rec];
     printf("\nDatabase: %s\n", db_name);
     if (n_recs)
     {
        printf("Current Record is #%d", cur_rec);
        if (!rp->active)
             printf(" (Deleted)");
        printf(":\n");

        printf("Name:   %s %s\n", rp->first, rp->last);
        printf("ID#:    %ld\n", rp->id);
        printf("Age:    %d\n", rp->age);
        printf("Gender: %c\n", rp->gender);
        printf("Salary: $%.2f\n", rp->salary);
      }

      switch(do_menu(edit_menu, "Edit Menu")) {

          case LIST_RECS:
            for(i = 0; i < n_recs; i++)
                 printf("%4d: %s%s\n", i, RECS[i]->last,
                    RECS[i]->active ? "" : " (Deleted)");
            printf("Press RETURN to continue:");
            gets(buf);
            break;
          case NEXT:         /* find next active record: */
            for (i = cur_rec + 1; i < n_recs; i++)
                if (RECS[i]->active)  /* skip inactives  */
                    break;
            if (i == n_recs) {  /* over the top?  */
                 printf("\aAt end of file.\n");
                 break;
              }
            cur_rec = i;
            break;
          case PREVIOUS:   /* find previous active record: */
              for (i = cur_rec - 1; i >= 0; i--)
                 if (RECS[i]->active)    /* skip inactives  */
                     break;
              if (i < 0) {    /* "under the bottom"?  */
                  printf("\aAt beginning of file.\n");
                  break;
              }
              cur_rec = i;
              break;
          case NEW:
              if (n_recs+1 > max_recs) {
                  printf("Maximum # of records ");
                  printf("(%d) reached.\n", max_recs);
                  break;
               }
               if ((rp = alloc_rec()) == NULL) {
                  printf("Out of memory. Try Fixing ");
                  printf("Database first...\n");
                  break;
               }
                          /* make new record current: */
               cur_rec = n_recs++;
               RECS[cur_rec] = rp;
               rp->active = TRUE;
               strcpy(rp->last,""); /* initialize the record  */
               strcpy(rp->first,"");
               rp->id = 0;
               rp->age = 0;
               rp->gender = ' ';
               rp->salary = 0.0F;  /* fall through to MODIFY */
          case MODIFY:
              printf("Last Name [%s]: ", rp->last);
              if (strlen(gets(buf)) > 0)
                  strcpy(rp->last, buf);
              printf("First Name [%s]: ", rp->first);
              if (strlen(gets(buf)) > 0)
                  strcpy(rp->first, buf);
              printf("ID# [%ld]: ", rp->id);
              if (strlen(gets(buf)) > 0)
                  rp->id = atol(buf);
              printf("Age [%d] ", rp->age);
              if (strlen(gets(buf)) > 0)
                  rp->age = atoi(buf);
              printf("Gender [%c]: ", rp->gender);
              if (strlen(gets(buf)) > 0)
                  rp->gender = (char)toupper(*buf);
              printf("Salary [%.2f]: ", rp->salary);
              if (strlen(gets(buf)) > 0)
                  rp->salary = (float) atof(buf);
              break;
          case DELETE:
              if (!rp->active) {
                 printf("Record is already deleted.\n");
                 break;
              }
              printf("Press 'y' to delete record,\n");
              printf("anything else to abort: ");
              gets(buf);
              if (tolower(*buf) == 'y')
                  rp->active = FALSE;
              break;
          case UNDELETE:
              if (rp->active) {
                 printf("Record is not deleted.\n");
                 break;
              }
              rp->active = TRUE;
              printf("Record restored.\n");
              break;
          case SELECT:
              printf("Enter new record number: ");
              i = atoi(gets(buf));
              if (i < 0 || i > n_recs) {
                printf("Record # out of range.\n");
                break;
              }
              cur_rec = i;
              break;
          case FIX:
              fix_db();    /* clean up database  */
              break;
          case QUIT:
              return;
      }
   }
}

/**************************************************
 *
 * Function:        fix_db
 * Purpose:         Purge deleted records, sort db
 * Parameters:      None
 * Return Value:    None
 */

static int compar(const void *a, const void *b);

static void fix_db(void) {     /* File Fix module */
    int i, new_n_recs;

    for (i = 0, new_n_recs = 0; i < n_recs; i++) {
        RECS[new_n_recs] = RECS[i];
        if (RECS[i]->active)
            new_n_recs++;
        else
            free(RECS[i]);
    }
    n_recs = new_n_recs;
    qsort(RECS, new_n_recs, sizeof(struct record *), compar);
}

/**************************************************
 * Function:        compar
 * Purpose:         Comparison function for qsort(),
 *                    sorting simply on last name
 * Parameters:      Two pointers to record pointers
 * Return Value:    As per strcmp()
 */

static int compar(const void *a, const void *b) {
    struct record **p1 = (struct record **)a;
    struct record **p2 = (struct record **)b;
    return strcmp((*p1)->last, (*p2)->last);
}
