/* Adressregister                                   */
/* l�nka i LARGE MODEL med BULLET_L.LIB             */

#include <dos.h>
#include <bios.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include <string.h>
#include <io.h>
#include <fcntl.h>
#include <bullet.h>

struct memorypack MP;
struct initpack IP;
struct exitpack EP;
struct createdatapack CDP;
struct createkeypack CKP;
struct dosfilepack DFP;
struct openpack OP;
struct accesspack AP[5];
struct statdatapack SDP;
struct exitpack EP;



struct adrrectype {
       char tag;
       char e_namn[20];
       char f_namn[20];
       char adress[30];
       char p_adress[35];
       char telnr[35];
       char fax[15];
       char nyckelord[35];
       char komment[50];
};
struct adrrectype adrrec;

struct fielddesctype fieldlist1[8];

int     rez, level;
div_t   div_rez;

char    tmpstr[129];

char adrDATname[] = "ADRESS.DBF";

char *adrIDXname[2] = {
       "E_F_NAMN.IDX\0",
       "F_NAMN.IDX\0",
};

char *adrIDXkey[2] = {
       "SUBSTR(E_NAMN,1,10)+SUBSTR(F_NAMN,1,10)\0",
       "SUBSTR(F_NAMN,1,10)\0"
};

unsigned int adrDAThandle, adrIDXhandle[2];

char adrkeybuf[64];

char *exceed_msg[2] = {
       "Du �r redan vid slutet av registret!                                           ",
       "Du �r redan vid b�rjan av registret!                                           "
};


int key,scan;

#define S_E_FNAMN 0
#define S_FNAMN  1

char *smodestr[2] = {"Efternamn","F�rnamn"};

#define YES 0x24
#define NO 49
#define QUIT 16

#define ADDMODE 0
#define EDITMODE 1

char gettmp[82];

int main(int argc, char **argv)
{
       init();

       while(1)
       {
               clrscr();
               HideCur();
               printf("ADRESSREGISTER");
               printf("                                             %d poster i basen\n",getrecordno(adrDAThandle));
               printf("--------------\n\n");
               printf("(1) S�k Efternamn\n");
               printf("(2) S�k F�rnamn\n");
               printf("(3) L�gg till post(-er)\n");
               printf("(4) Komprimera databas\n");
               printf("(5) Re-indexera databas\n");
               printf("\n<ESC> Avsluta program\n");

               scan = (bioskey(0) >> 8) & 0xff;
               switch(scan){
                       case 1: quit();break;
                       case 2: search(S_E_FNAMN);break;
                       case 3: search(S_FNAMN);break;
                       case 4: add_edit_record(ADDMODE);break;
                       case 5: pack();break;
                       case 6: reindex();break;
               }
       }
}


search(int mode)
{
       clrscr();
       ShowCur();

       printf("S�k %s: ",smodestr[mode]);

       gets(adrkeybuf);
       HideCur();
       if(strlen(adrkeybuf) == 0) return;

       if(getequal(&AP[0],adrIDXhandle[mode],&adrrec,adrkeybuf) != 0)
               getnext(&AP[0],adrIDXhandle[mode],&adrrec,adrkeybuf);

       clrscr();
       while(1)
       {
               if((AP[0].stat != 202) && (AP[0].stat != 203))
                       draw_info_scr();
               else {
                       gotoxy(1,25);
                       printf(exceed_msg[AP[0].stat-202]);
               }

               scan = (bioskey(0) >> 8) & 0xff;

               switch(scan){
                       case 81:   getnext(&AP[0],adrIDXhandle[mode],&adrrec,adrkeybuf);
                                                 break;
                       case 73:   getprev(&AP[0],adrIDXhandle[mode],&adrrec,adrkeybuf);
                                                 break;
                       case 0x13: del_undel_record(mode);
                                                 break;
                       case 0x12: add_edit_record(EDITMODE);
                                                 break;
                       case 1:    return;
               }
       }
}

draw_info_scr()
{
       clrscr();
       gotoxy(1,5);
       draw_record_info();
       gotoxy(1,25);
       printf("(E) Editera  (R) Radera/O-Radera  (PgUp) F�reg�ende  (PgDn) N�sta  (ESC) Avbryt");
}

draw_record_info()
{
       printf("  EFTERNAMN  %.20s",adrrec.e_namn);
       if(adrrec.tag == '*')
               printf("                          *** RADERAD ***");
       printf("\n");
       printf("    F�RNAMN  %.20s\n",adrrec.f_namn);
       printf("     ADRESS  %.30s\n",adrrec.adress);
       printf(" POSTADRESS  %.35s\n",adrrec.p_adress);
       printf("    TELEFON  %.35s\n",adrrec.telnr);
       printf("        FAX  %.15s\n",adrrec.fax);
       printf("  NYCKELORD  %.35s\n",adrrec.nyckelord);
       printf("  KOMMENTAR  %.50s\n",adrrec.komment);
}

add_edit_record(int mode)
{
int i;
long recnr;

       while(1)
       {
               clrscr();

               if(mode == ADDMODE)
                       clear_fields();

               while(1)
               {
                       clrscr();
                       draw_record_info();
                       printf("\n\n---------------------------------------------------------------------\n\n");

                       printf("Ange f�lt, eller (S) Spara (ESC) Avbryt\n\n");
                       printf("(1) Efternamn\n");
                       printf("(2) F�rnamn\n");
                       printf("(3) Adress\n");
                       printf("(4) Postadress\n");
                       printf("(5) Telefon\n");
                       printf("(6) Fax\n");
                       printf("(7) Nyckelord\n");
                       printf("(8) Kommentar\n\n");

                       scan = (bioskey(0) >> 8) & 0xff;

                       switch(scan){
                               case 2:         printf("Efternamn: ");
                                                       newgets(adrrec.e_namn,20);
                                                       break;
                               case 3:         printf("F�rnamn: ");
                                                       newgets(adrrec.f_namn,20);
                                                       break;
                               case 4: printf("Adress: ");
                                                       newgets(adrrec.adress,30);
                                                       break;
                               case 5: printf("Postadress: ");
                                                       newgets(adrrec.p_adress,35);
                                                       break;
                               case 6:         printf("Telefon: ");
                                                       newgets(adrrec.telnr,35);
                                                       break;
                               case 7:  printf("Fax: ");
                                                       newgets(adrrec.fax,15);
                                                       break;
                               case 8:  printf("Nyckelord: ");
                                                       newgets(adrrec.nyckelord,35);
                                                       break;
                               case 9: printf("Kommentar: ");
                                                       newgets(adrrec.komment,50);
                                                       break;

                       case 0x1f:  if(mode == ADDMODE)         /* S */
                                                       {
                                                               adrrec.tag = ' ';

                                                               for(i=0;i<2;i++){
                                                                       AP[i].func = INSERTXB;
                                                                       AP[i].handle = adrIDXhandle[i];
                                                                       AP[i].recptr = &adrrec;
                                                                       AP[i].keyptr = adrkeybuf;
                                                                       AP[i].nextptr = &AP[i+1];
                                                               }
                                                               AP[1].nextptr = NULL;
                                                               if((rez = BULLET(&AP)) == 0) {
                                                                       if(AP[0].stat != 0)
                                                                               error(); }
                                                               else
                                                                       error();

                                                               printf("Post sparad!\n");
                                                               delay(1000);

                                                               clrscr();
                                                               printf("L�gg till fler poster (j/n)?");
                                                               while(1) {
                                                                       scan = (bioskey(0) >> 8) & 0xff;
                                                                       if((scan == 0x24) || (scan == 0x31)) break;
                                                               }
                                                               if(scan == 0x31)
                                                                       goto avbrutet;
                                                               else
                                                                       clear_fields();
                                                       }
                                                       else
                                                       {
                                                               recnr = AP[0].recno;
                                                               for(i=0;i<2;i++) {
                                                                       AP[i].func = UPDATEXB;
                                                                       AP[i].handle = adrIDXhandle[i];
                                                                       AP[i].recno = recnr;
                                                                       AP[i].recptr = &adrrec;
                                                                       AP[i].keyptr = adrkeybuf;
                                                                       AP[i].nextptr = &AP[i+1];
                                                               }
                                                               AP[1].nextptr = NULL;
                                                               level = 9000;
                                                               if((rez = BULLET(&AP)) == 0) {
                                                                       if(AP[0].stat != 0)
                                                                               error(); }
                                                               else
                                                                       error();

                                                               goto avbrutet;
                                                       } break;
                       case 0x01:  printf("Avbrutet!\n");
                                                       delay(1000);
                                                       goto avbrutet;
                       }
               }
       }
avbrutet:
;
}

del_undel_record(int mode)
{
int i;
       if(adrrec.tag == ' ')
               deleterecord(&AP[0],adrDAThandle,AP[0].recno);
       else
               undeleterecord(&AP[0],adrDAThandle,AP[0].recno);

       if(adrrec.tag == ' ')
               adrrec.tag = '*';
       else
               adrrec.tag = ' ';
}

pack()
{
int i;

       printf("\nKomprimerar databas...");

       packrecords(adrDAThandle);
       reindex();
}

reindex()
{
int i;

       level = 1210;
       printf("\nRe-indexerar databas... ");

       for(i=0;i<2;i++)
       {
               AP[i].func = REINDEXXB;
               AP[i].handle = adrIDXhandle[i];
               AP[i].nextptr = &AP[i+1];
       }
       AP[1].nextptr = NULL;

       if((rez = BULLET(&AP)) != 0){
         rez = AP[rez-1].stat;
         error();
       }
}

init()
{
int i;
int  handle;

       level = 100;
       MP.func = MEMORYXB;
       rez = BULLET(&MP);
       if (MP.memory < 40000l) {
               rez = 8;
               error();
       }

       level = 110;
       IP.func = INITXB;
       IP.jftmode = 0;
       if((rez = BULLET(&IP)) != 0) error();

       if ((handle = open(adrDATname, O_RDONLY)) == -1)
       {
               strcpy(fieldlist1[0].fieldname,"E_NAMN");
               strcpy(fieldlist1[0].fieldtype,"C");
               fieldlist1[0].fieldlen = 20;
               fieldlist1[0].fielddc = 0;

               strcpy(fieldlist1[1].fieldname,"F_NAMN");
               strcpy(fieldlist1[1].fieldtype,"C");
               fieldlist1[1].fieldlen = 20;
               fieldlist1[1].fielddc = 0;

               strcpy(fieldlist1[2].fieldname,"ADRESS");
               strcpy(fieldlist1[2].fieldtype,"C");
               fieldlist1[2].fieldlen = 30;
               fieldlist1[2].fielddc = 0;

               strcpy(fieldlist1[3].fieldname,"P_ADRESS");
               strcpy(fieldlist1[3].fieldtype,"C");
               fieldlist1[3].fieldlen = 35;
               fieldlist1[3].fielddc = 0;

               strcpy(fieldlist1[4].fieldname,"TELNR");
               strcpy(fieldlist1[4].fieldtype,"C");
               fieldlist1[4].fieldlen = 35;
               fieldlist1[4].fielddc = 0;

               strcpy(fieldlist1[5].fieldname,"FAX");
               strcpy(fieldlist1[5].fieldtype,"C");
               fieldlist1[5].fieldlen = 15;
               fieldlist1[5].fielddc = 0;

               strcpy(fieldlist1[6].fieldname,"NYCKELORD");
               strcpy(fieldlist1[6].fieldtype,"C");
               fieldlist1[6].fieldlen = 35;
               fieldlist1[6].fielddc = 0;

               strcpy(fieldlist1[7].fieldname,"KOMMENTAR");
               strcpy(fieldlist1[7].fieldtype,"C");
               fieldlist1[7].fieldlen = 50;
               fieldlist1[7].fielddc = 0;

               createdbf(adrDATname,8,&fieldlist1);
       }
       else
               close(handle);

       opendbf(adrDATname,&adrDAThandle);

       for(i=0;i<2;i++)
       {
               if ((handle = open(adrIDXname[i], O_RDONLY)) == -1)
                       createidx(adrIDXname[i],adrIDXkey[i],adrDAThandle,cCHAR);
               else close(handle);
       }

       for(i=0;i<2;i++)
               openidx(adrIDXname[i],adrDAThandle,&adrIDXhandle[i]);

}

quit()
{
       printf("\nVill du verkligen sluta (j/n)?");

       while(1) {
               scan = (bioskey(0) >> 8) & 0xff;
               if((scan == 0x24) || (scan == 0x31)) break;
       }

       if(scan == 0x24)
       {
               EP.func = EXITXB;
               rez = BULLET(&EP);
               clrscr();
               ShowCur();
               exit(0);
       }
}

error()
{
       printf("Error: %u at level %u while performing ",rez,level);
       switch (level) {
       case 100:
         printf("a memory request of 140K.\n");
         break;
       default:
         printf("(See source)\n");    /* just check the source */
       }
       ShowCur();
       exit(1);
}

newgets(char *s,int len)
{
       ShowCur();
       memset(gettmp,32,80);
       gets(gettmp);
       gettmp[strlen(gettmp)] = 32;
       strncpy(s,gettmp,len);
       HideCur();
}


clear_fields()
{
       adrrec.tag = ' ';
       memset(adrrec.e_namn,32,20);
       memset(adrrec.f_namn,32,20);
       memset(adrrec.adress,32,30);
       memset(adrrec.p_adress,32,35);
       memset(adrrec.telnr,32,35);
       memset(adrrec.fax,32,15);
       memset(adrrec.nyckelord,32,35);
       memset(adrrec.komment,32,50);
}


createdbf(char far *fname,unsigned nofields,char far *fieldlist)
{
       CDP.func = CREATEDXB;
       CDP.filenameptr = fname;
       CDP.nofields = nofields;
       CDP.fieldlistptr = fieldlist;
       CDP.fileid = 3;

       if((rez = BULLET(&CDP)) != 0) error();
}
createidx(char far *idxname,char far *idxkey, unsigned dathandle,unsigned keyflags)
{
       level = 1100;
       CKP.func = CREATEKXB;
       CKP.filenameptr = idxname;
       CKP.keyexpptr = idxkey;
       CKP.xblink = dathandle;
       CKP.keyflags = keyflags;
       CKP.codepageid = -1;
       CKP.countrycode = -1;
       CKP.collateptr = NULL;
       rez = BULLET(&CKP);
       if (rez !=0) error();
}

opendbf(char far *fname,unsigned *handle)
{
       level = 1010;
       OP.func = OPENDXB;
       OP.filenameptr = fname;
       OP.asmode = READWRITE | DENYNONE;
       if((rez = BULLET(&OP)) != 0) error();
       *handle = OP.handle;
}
openidx(char far *fname, unsigned dathandle, unsigned *idxhandle)
{
       OP.func = OPENKXB;
       OP.filenameptr = fname;
       OP.asmode = READWRITE | DENYNONE;
       OP.xblink = dathandle;
       if( (rez = BULLET(&OP)) != 0) error();
       *idxhandle = OP.handle;
}


getequal(struct accesspack *accpptr, unsigned idxhandle,char far *recbuf, char far *keybuf)
{
       accpptr->func = GETEQUALXB;
       accpptr->handle = idxhandle;
       accpptr->recptr = recbuf;
       accpptr->keyptr = keybuf;
       if((rez = BULLET(accpptr)) != 0) {
               if(rez == 200)
                       return(200);
               else
                       error();
       }
       else
               return(0);
}
getnext(struct accesspack *accpptr, unsigned idxhandle,char far *recbuf, char far *keybuf)
{
       accpptr->func = GETNEXTXB;
       accpptr->handle = idxhandle;
       accpptr->recptr = recbuf;
       accpptr->keyptr = keybuf;
       if((rez = BULLET(accpptr)) != 0) {
               if(rez != 202) error();
       }
       else
               return(0);
}
getprev(struct accesspack *accpptr, unsigned idxhandle,char far *recbuf, char far *keybuf)
{
       accpptr->func = GETPREVXB;
       accpptr->handle = idxhandle;
       accpptr->recptr = recbuf;
       accpptr->keyptr = keybuf;
       if((rez = BULLET(accpptr)) != 0) {
               if(rez != 203) error();
       }
       else
               return(0);
}

deleterecord(struct accesspack *accpptr,unsigned dathandle,long recno)
{
       accpptr->func = DELETERECORDXB;
       accpptr->handle = dathandle;
       accpptr->recno = recno;
       if((rez = BULLET(accpptr)) != 0) error();
}
undeleterecord(struct accesspack *accpptr,unsigned dathandle,long recno)
{
       accpptr->func = UNDELETERECORDXB;
       accpptr->handle = dathandle;
       accpptr->recno = recno;
       if((rez = BULLET(accpptr)) != 0) error();
}


packrecords(unsigned dathandle)
{
       AP[0].func = PACKRECORDSXB;
       AP[0].handle = dathandle;
       if((rez = BULLET(&AP)) != 0) error();
}

getrecordno(int dathandle)
{
       SDP.func = STATDXB;
       SDP.handle = dathandle;
       rez = BULLET(&SDP);
       return(SDP.recs);
}

HideCur()
{
         asm{
                 push ax
                 push cx

                 mov ah,01h
                 mov ch,00100110b
                 mov cl,00000111b
                 int 10H

                 pop cx
                 pop ax
         }
}

ShowCur()
{
         asm{
                 push ax
                 push cx

                 mov ah,01H
                 mov ch,00000110b
                 mov cl,00000111b
                 int 10H

                 pop cx
                 pop ax
         }
}