/////////////////////////////////////////////////////////
//     Implementation file of database class: DEMO.
//                                                          
//     Source generated by: CSDBGEN version 1.6.5.
//     Date of generation:  Monday, 9 June 1997.
//     Time of generation:  10:01:40.
//                                                          
//                                                          
//     The next lines represent the database definition     
//     file used as input for CSDBGEN.                      
//                                                          
//                                                          
////////////// Start of the .def file //////////////////
/*
class: DEMO
record: Record
file: DBdemo
field: name s 50 Y
field: data s 32 Y
*/
/////////////// End of .def file //////////////////////////////////////////////
/*




                 ллллл     л                       л        
                лл   лл   лл                      лл        
                ллл      лллл     ллл   лл ллл   лллл       
                  ллл     лл        лл   ллл лл   лл        
                    ллл   лл     ллллл   лл       лл        
                лл   лл   лл л  лл  лл   лл       лл л      
                 ллллл     лл    ллл лл  лл        лл       
                                                            
                                                            
             лллл     лллл  лл  лл  лл ллл   ллллл   лллл   
            лл       лл  лл лл  лл   ллл лл лл   л  лл  лл  
             лллл    лл  лл лл  лл   лл     лл      лллллл  
                лл   лл  лл лл  лл   лл     лл   л  лл      
             лллл     лллл   ллл лл  лл      ллллл   ллллл  
                                                            



*/
//////////////////////////////////////////////////////////////////////////////


#include "csmess.h"
#include "csendian.h"
#include "demodb.h"

#ifdef _CP_010
extern unsigned _stklen=7000;   // Under DOS, a large stack is needed.
#endif



Record *record_p; 


///////////////////////////////// Constructor ////////////////////////////////
DEMO::DEMO(void) 
{ 
    static_rec=(Record *)malloc(sizeof(Record));
    if(!static_rec) { csmess_p(" Out of memory "); exit(12); } 
    is_open=FALSE; 
    current=1; 
    NeedSync=TRUE; 
    errnr=0;;
    e_name="DEMO-class";
    use_lock_file(TRUE); 
}

///////////////////////////////// Destructor /////////////////////////////////
DEMO::~DEMO(void) 
{ 
    close();
    free(static_rec);
}

///////////////////////////////// Errors /////////////////////////////////////
int DEMO::error_nr(void) 
{

    int RC=0;
    int RCT;

    RCT=in1.error_nr(); if(RCT) RC=RCT;
    RCT=in2.error_nr(); if(RCT) RC=RCT;

    RCT=db.error_nr();  if(RCT) RC=RCT;

    if(errnr) { RC=errnr; errnr=0; }

    return RC; 
}

///////////////////////////////// Display Error //////////////////////////////
U16 DEMO::display_error(void) 
{

    int RC;

    RC=db.display_error(); 

    if(!RC) RC=in1.display_error(); 
    if(!RC) RC=in2.display_error(); 


    if(!RC && errnr) { RC=errnr; csmess_p(RC,e_name); }

    error_nr();  // Just to reset all error variables.

    return RC; 
}


///////////////////////////////// Messages ///////////////////////////////////
void DEMO::visible_error(int ErrorNr,char *Parm) 
{ 
    csmess_p(ErrorNr,e_name,Parm);
    error_nr(ErrorNr);
}

///////////////////////////////// Test for Empty DB //////////////////////////
void DEMO::te(void) 
{ 
    if(numrec()) return;
    visible_error(30010);
    close(); 
    exit(8); 
}

///////////////////////////////// test Begin Of File /////////////////////////
int DEMO::tBOF(void) 
{
    if(!numrec()) return TRUE;  
    if(NeedSync) synch_index();
    return (this->*bof_fun)(); 
}

///////////////////////////////// test End Of File /////////////////////////
int DEMO::tEOF(void) 
{
    if(!numrec()) return TRUE;  
    if(NeedSync) synch_index();
    return (this->*eof_fun)(); 
}

///////////////////////////////// Read Only //////////////////////////////////
int DEMO::read_only(int ToF) 
{
    if(already_open()) { visible_error(30063); return FALSE; }

    db.read_only(ToF);

    in1.read_only(ToF); 
    in2.read_only(ToF); 

    return TRUE; 
}

///////////////////////////////// Use lock files /////////////////////////////
int DEMO::use_lock_file(int ToF) 
{

    db.use_lock_file(ToF);

    in1.use_lock_file(FALSE); 
    in2.use_lock_file(FALSE); 

    return TRUE; 
}

///////////////////////////////// Lock file exist/////////////////////////////
int DEMO::lock_file_exist(void) 
{

    if(db.lock_file_exist("DBdemo.dbf")) return TRUE; 

    return FALSE; 
}

///////////////////////////////// remove lock file ///////////////////////////
int DEMO::remove_lock_file(void) 
{

    db.remove_lock_file("DBdemo.dbf"); 

    return TRUE;  
}

///////////////////////////////// Sync Index /////////////////////////////////
void DEMO::synch_index(void) 
{

     switch(order())
     {
         case UNSORTED:
                  break; 
         case DEMO_NAME_INDEX:
                 find1(static_rec->_name); 
                 break; 
         case DEMO_DATA_INDEX:
                 find2(static_rec->_data); 
                 break; 
     }
     NeedSync=FALSE; 
}

///////////////////////////////// reindex ////////////////////////////////////
int DEMO::reindex(void) 
{
    if(!already_open()) { visible_error(30051); return FALSE; }

    write_rec();

    U32 l=current;  
    Record *rp;  

    in1.empty(); 
    in2.empty(); 
    for(current=numrec(); current>0; current--)  
    {                          
       rp=locate_curr(); 
       in1.insert(rp->_name,&current); 
       in2.insert(rp->_data,&current); 
    }                          
    current=l;                 
    NeedSync=TRUE;             

    return TRUE;               
}

///////////////////////////////// skip ///////////////////////////////////////
int  DEMO::skip0(int delta) 
{
     long old_current=current; 
     current=pMax(pMin(current+delta,db.numrec()),1); 
     return (int)(current-old_current); 
}

int  DEMO::skip(int delta) 
{
     int rc; 

     if(numrec()==0) return 0; 

     if(NeedSync) synch_index();

     write_rec(); 
     rc=(this->*skip_fun)(delta); 
     read_rec(); 

     return rc; 
}
/////////////// go_to ////////////////////////////////////////////
int DEMO::go_to(long n) 
{
    if(n<1 || n>numrec()) return FALSE; 

    write_rec(); 
    current=n; 
    read_rec(); 

    NeedSync=(order()!=UNSORTED);

    return TRUE;
}

/////////////// bottom() /////////////////////////////////////////
int DEMO::bottom(void ) 
{
    if(numrec()==0) return FALSE; 

    write_rec(); 
    (this->*bottom_fun)();
    read_rec(); 

    NeedSync=FALSE;

    return TRUE;
}

/////////////// top() ////////////////////////////////////////////
int DEMO::top(void ) 
{
    if(numrec()==0) return FALSE; 

    write_rec(); 
    (this->*top_fun)();
    read_rec(); 

    NeedSync=FALSE;

    return TRUE;
}

/////////////// search() /////////////////////////////////////////
int DEMO::search(void *k) 
{
    if(numrec()==0) return FALSE; 

    int RC;      
    write_rec(); 
    if(0==(RC=(this->*search_fun)(k))) bottom(); 
    read_rec(); 

    NeedSync=FALSE;

    return RC;
}

/////////////// append blank//////////////////////////////////////
void DEMO::append_blank(void) 
{
    append();
    in1.insert(static_rec->_name,&current); 
    in2.insert(static_rec->_data,&current); 
    NeedSync=FALSE;
}

///////////////////////////////// append /////////////////////////////////////
// This function doesn't update the indexes, which can save some 
// disk I/O because you are likely to alter the fields 
// immediately after you have appended the record.
// However, if you have an index on a field you don't update, this 
// record will NOT appear in that particular index! 
// The 'append_blank' function does update all indexes, which 
// makes it a safer, but slower option. 
//  
void DEMO::append(void) 
{
    write_rec();
    memset(static_rec,0,sizeof(Record)); 
    current=db.append_rec(static_rec); 
    dirty=TRUE;    
    NeedSync=TRUE;
}

///////////////////////////////// open ///////////////////////////////////////
int DEMO::open(int kBbuf) 
{
     if(already_open()) { visible_error(30061); return FALSE; } 

     int   needs_reindex=FALSE;        
     char *iname;        

     dirty=FALSE;     
     current=1;       

     int fre=kBbuf/5; //kBbuf default = 100 Kb.  

     if(!db.open("DBdemo.dbf",fre)) 
     {
         visible_error(30020,"DBdemo.dbf");
         error_nr(db.error_nr());
         return FALSE;
     }
     if(db.lengthrec()!=sizeof(Record)) 
     {
         visible_error(30030);
         db.close(); 
         exit(1); 
     }

     iname="DBdemo01.idx";

     if(!file_exist(iname))
     { 
       in1.multiple_keys(TRUE);
       in1.define(iname,DEMO_NAME_LENGTH+1,sizeof(long));
       needs_reindex=TRUE; 
     } 
     if(!in1.open(iname,fre*2))
     { 
         visible_error(30040,iname);
         error_nr(in1.error_nr());
         goto OnOpenError;
     } 
  

     iname="DBdemo02.idx";

     if(!file_exist(iname))
     { 
       in2.multiple_keys(TRUE);
       in2.define(iname,DEMO_DATA_LENGTH+1,sizeof(long));
       needs_reindex=TRUE; 
     } 
     if(!in2.open(iname,fre*2))
     { 
         visible_error(30040,iname);
         error_nr(in2.error_nr());
         goto OnOpenError;
     } 
  
     is_open=TRUE; 
     if(needs_reindex) reindex(); 
     read_rec(); 
  
     order(UNSORTED);  

     return TRUE;    
  
  
  
OnOpenError: 

     close2();

     return FALSE;    

}

///////////////////////////////// close //////////////////////////////////////
int DEMO::close2(void) 
{

     write_rec();
     db.close(); 
     in1.close();
     in2.close();

     return TRUE;   
}



int DEMO::close(void) 
{
     if(!already_open()) return TRUE; 

     int RC=close2(); 

     is_open=FALSE; 

     return RC;   
}

///////////////////////////////// define /////////////////////////////////////
int  DEMO::define(void) 
{
     if(already_open()) { visible_error(30062); return FALSE; }

     int RC;

     RC=db.define("DBdemo.dbf",sizeof(Record)); 

     in1.multiple_keys(TRUE);
     RC&=in1.define("DBdemo01.idx",DEMO_NAME_LENGTH+1,sizeof(long));
     in2.multiple_keys(TRUE);
     RC&=in2.define("DBdemo02.idx",DEMO_DATA_LENGTH+1,sizeof(long));

     if(!RC) visible_error(30070); 

     return RC; 
}

///////////////////////////////// pack ///////////////////////////////////////
int DEMO::pack(void) 
{
     if(!is_open) { visible_error(30052); return FALSE; }

     write_rec(); 
     db.pack();
     reindex();
     top();

     return TRUE;
}

///////////////////////////////// order //////////////////////////////////////
int DEMO::order(int nr) 
{
     if(!is_open) { visible_error(30053); return FALSE; }

     switch(nr)
     {
         case UNSORTED:		//Unsorted 
                  bof_fun   =&DEMO::bof0;
                  eof_fun   =&DEMO::eof0;
                  skip_fun  =&DEMO::skip0;
                  top_fun   =&DEMO::top0;
                  bottom_fun=&DEMO::bottom0;
                  search_fun=&DEMO::search0;
                  NeedSync=FALSE;
                  break; 
         case DEMO_NAME_INDEX:	//Index on field name
                  bof_fun   =&DEMO::bof1;
                  eof_fun   =&DEMO::eof1;
                  skip_fun  =&DEMO::skip1;
                  top_fun   =&DEMO::top1;
                  bottom_fun=&DEMO::bottom1;
                  search_fun=&DEMO::search1;
                  NeedSync=TRUE;
                  break; 
         case DEMO_DATA_INDEX:	//Index on field data
                  bof_fun   =&DEMO::bof2;
                  eof_fun   =&DEMO::eof2;
                  skip_fun  =&DEMO::skip2;
                  top_fun   =&DEMO::top2;
                  bottom_fun=&DEMO::bottom2;
                  search_fun=&DEMO::search2;
                  NeedSync=TRUE;
                  break; 
         default: { visible_error(30080); return FALSE; }
     }
     iOrder=nr;

     return TRUE;
}
/////////////////////////////reading record  ///////////////////////////////
void DEMO::read_rec(void) 
{
    if(numrec()==0) return; 
    *static_rec=*locate_curr(); 
}
/////////////////////////////writing record  ///////////////////////////////
void DEMO::write_rec2(void) 
{
    Record *recp=locate_curr(); 
    if(strcmp(recp->_name,static_rec->_name)) 
    { 
      in1.delet(recp->_name,&current); 
      in1.insert(static_rec->_name,&current); 
    } 
    if(strcmp(recp->_data,static_rec->_data)) 
    { 
      in2.delet(recp->_data,&current); 
      in2.insert(static_rec->_data,&current); 
    } 
    db.write_rec(current,static_rec); 
    dirty=FALSE;   
}

///////////////////////////////// export /////////////////////////////////////
int  DEMO::export(char *s) 
{
     if(!is_open) { visible_error(30054,s); return FALSE; }

     write_rec();

     FILE *fo=fopen(s,"w"); 
     if(fo==NULL) { visible_error(30071,s); return FALSE; }

     fprintf(fo,"class:  DEMO");
     fprintf(fo,"\nrecord: Record");
     fprintf(fo,"\nfile:   DBdemo");
     fprintf(fo,"\nfield:  name s 50 Y   ");
     fprintf(fo,"\nfield:  data s 32 Y   ");

     if(ferror(fo)) { fclose(fo); visible_error(30072,s); return FALSE; } 

     Record *rp;
     U32 lmax=numrec();
     U32 l;
     for(l=1;l<=lmax;l++) 
     {
        rp=( Record * )db.locate_rec(l);
        fprintf(fo,"\n%c",12);
        fprintf(fo,"\n%s",rp->_name);
        fprintf(fo,"\n%s",rp->_data);
        fprintf(fo,"\n"); //Additional linefeed

        if(ferror(fo)) { fclose(fo); visible_error(30072,s); return FALSE; } 
     }

     if(fclose(fo)) { visible_error(30072,s); return FALSE; }

     return TRUE;  
}

///////////////////////////////// import /////////////////////////////////////
int DEMO::import(char *s) 
{   
 
      if(!is_open) { visible_error(30055,s); return FALSE; }

      FILE *fr=fopen(s,"r"); 
      if(fr==NULL) { visible_error(30091,s); return FALSE; }
  
  
      const MAX_NUM_FIELDS= 100;  //Increase this to allow more fields    
      const MAX_FIELD_LEN = 500;  //Increase this to allow longer fields  
 
      int *finu;
      finu=(int *)malloc(MAX_NUM_FIELDS*sizeof(int));
      if(finu==NULL) { fclose(fr); visible_error(30092); return FALSE; }  
 
      char *fibu;    
      fibu=(char *)malloc(MAX_FIELD_LEN);
      if(fibu==NULL) 
      {
         fclose(fr); 
         free(finu); 
         visible_error(30092); 
         return FALSE; 
      }
 
      *fibu=0;  
 
      char *fipo=fibu+strlen("field:");  
      char *cp; 
      int  ifieldnr=0;    
      int  ofieldnr; 
 
      int  RC=TRUE; 
      int  InDef=TRUE; 
 
      memset(finu,0,MAX_NUM_FIELDS*sizeof(int));
 
      fgets(fibu,MAX_FIELD_LEN,fr); 
      while(!strchr(fibu,12))  
      {    
        if(feof(fr))
        { 
           if(!InDef)   
           visible_error(30093,s); 
           RC=FALSE;
           break; 
        } 
        pStrlwr(fibu);     //Converting to lower case.
        notabs(fibu);      //Removing tabs.
        trim_string(fibu); //Removing heading & trailing spaces.
        if(!strchr(fibu,':') && *fibu) InDef=FALSE;   
        if(strstr(fibu,"field:"))   
        {  
           ifieldnr++;  
           trim_string(fipo);    
           if((cp=strchr(fipo,' '))!=NULL) *cp=0;
           if     (!strcmp(fipo,"name"))	ofieldnr=1;
           else if(!strcmp(fipo,"data"))	ofieldnr=2;
           else ofieldnr=0; 
           finu[ifieldnr]=ofieldnr; 
        }  
        fgets(fibu,MAX_FIELD_LEN,fr);    
      }    
 
 
      if(RC) 
      for(;;)   
      {    
        if(!strchr(fibu,12))   
        {  
           ifieldnr++; 
           if(ifieldnr<MAX_NUM_FIELDS) 
             switch(finu[ifieldnr])   
             {  
                case 0:  break;
                case 1:
                         fibu[DEMO_NAME_LENGTH]=0;
                         name(fibu);
                         break;
                case 2:
                         fibu[DEMO_DATA_LENGTH]=0;
                         data(fibu);
                         break;
             }  
        }  
        else    
        {  
           ifieldnr=0; 
           append_blank();
        }  
        if(feof(fr)) break;    
        fgets(fibu,MAX_FIELD_LEN,fr);    
        cp=fibu+(pMax(1,strlen(fibu))-1); 
        if(*cp=='\n') *cp=0;  //removing the line feed 
      }    
 
 
      fclose(fr); 
      free(fibu); 
      free(finu); 
 
      return RC; 
 
}

///////////////////////////////// export to dBASE compatible file. ///////////
int DEMO::to_DBASE(char *s) 
{   
 
      if(!is_open) { visible_error(30056,s); return FALSE; }
 
      char bufje[12];
 
      write_rec(); 
      FILE *fo=fopen(s,"wb"); 
      if(fo==NULL) { visible_error(30095,s); return FALSE; }
  
      int i;
  
      csDATE d_upda;
      d_upda.sem_jul(db.sj_updated());
      fputc(03,fo);  
      
      fputc(d_upda.year() % 100,fo);  
      fputc(d_upda.month(),fo);  
      fputc(d_upda.day(),fo);  
 
      long nr_record=numrec(); 
      fwrite(&nr_record,sizeof(long),1,fo); 
      WriteU16l(fo,98);		//Header length 
      WriteU16l(fo,83);		//Length of data record 
      for(i=0;i<20;i++) fputc(0,fo); // 20 dummy bytes 


// Writing definition of field name to dbase file header.
      memset(bufje,0,11);
      strcpy(bufje,"NAME");
      fwrite(bufje,11,1,fo);
      fputc('C',fo); 
      for(i=0;i<4;i++) fputc(0,fo); // 4 dummy bytes 
      fputc(50,fo); 
      fputc(0,fo); 
      for(i=0;i<14;i++) fputc(0,fo); // 14 dummy bytes 

// Writing definition of field data to dbase file header.
      memset(bufje,0,11);
      strcpy(bufje,"DATA");
      fwrite(bufje,11,1,fo);
      fputc('C',fo); 
      for(i=0;i<4;i++) fputc(0,fo); // 4 dummy bytes 
      fputc(32,fo); 
      fputc(0,fo); 
      for(i=0;i<14;i++) fputc(0,fo); // 14 dummy bytes 


      fputc(13,fo);  //Field terminator 
      fputc(0,fo); 

// By now we have written the definition of the 
// record structure to the file header. 
// From here on we will export the records. 

     Record *rp;
     U32 lmax=numrec();
     U32 l;
     for(l=1;l<=lmax;l++) 
     {

        if(ferror(fo)) 
        { 
           fclose(fo); 
           visible_error(30096,s); 
           return FALSE; 
        } 

        rp=(Record *)db.locate_rec(l);

        if(db.is_delet(l)) fputc(42,fo); 
        else               fputc(32,fo); 

/////////////////////// writing field name /////////////
        fprintf(fo,"%-50s",rp->_name);
/////////////////////// writing field data /////////////
        fprintf(fo,"%-32s",rp->_data);
     }
     fputc(26,fo);  //End of File 
     fclose(fo); 
 
     if(ferror(fo)) 
     { 
        visible_error(30096,s); 
        return FALSE; 
     } 
 
     return TRUE; 
}