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

                      CSDB Library, Free Evaluation Version 2.0.5 
                                       Release: January 22th 1997 

       Header file of the OLAY class.

                                           Copyright(c) 1994-1997 
                                                          ComBits 
                                                  The Netherlands 
***********************************************************************/

#ifndef __CSOLAY_H
#define __CSOLAY_H

#include "cspage.h"
#include "csoli.h"


//#ifdef _CP_001

#ifdef feof
  // The feof() macro defined for ANSI C, makes it impossible
  // to declare a member function with that name.
  // Because there is also a feof() function defined, we
  // can savely 'undef' it.
  #undef feof
#endif

//#endif


#ifdef _CP_002
  #pragma warning(disable: 4270 4067 4018)
#endif



     struct olpo_os
     {
        U32  pos;
        U32  page;
        S16  offset;
     };              // OLay-POs



class OLAY: public PAGE
{

 protected:

     typedef struct
     {
        U32  p_page;
        U32  n_page;
        S16  used;      //Number of bytes in use on this page.
     } olhe;            //OLay HEad

    typedef struct olpo_os olpo;


     OLAYI table;
     U32   lr_page;       //Last Referred Page
     int   lr_dirty;      //..............page dirty
     csCHAR *lr_add ;     //..............Address



protected:

     olpo current;
     U32  last_page;
     U32  last_pos;
     U32  first_page;
     U16  per_page;
     U32  o_empty;
     U32  tel_empty;


  protected:


     void init_vars(void);
     void init_defaults(void) {}

     void prev_page_a(olpo &olp); // To the first byte in the previous page
     void next_page_a(olpo &olp);
     void next_page_a(olhe *hp,olpo &olp)
     {
         olp.pos+=left_used(hp,olp.offset);
         olp.page=next_page_num(hp);
         olp.offset=mini_off();
     }

     void start_page(olpo &olp)
     {
        olp.pos-=olp.offset-mini_off();
        olp.offset=mini_off();
     }

//////////////////////// Page manipulation ///////////////////////////////

     olpo insert_page(olpo &olp);
     void unchain_page(olpo &pos);
     void append_page(void);
     U32  new_page(void);

//////////////////////// Skip  //////////////////////////////////////////

     void skip_plus(olpo &olp,U32  delta);
     void skip_min(olpo &olp,U32  delta);

     void skip_t(olpo &pos,S32 delta)
     {
        if(delta>0) skip_plus_t(pos,delta);
        else        skip_min_t(pos,-delta);
     }

     void skip_plus_t(olpo &pos,U32 delta)
     {
        if(delta>1500) go_to(pos,pos.pos+delta);
        else           skip_plus(pos,delta);
     }

     void skip_min_t(olpo &pos,U32 delta)
     {
        if(delta>1500) go_to(pos,pos.pos-delta);
        else           skip_min(pos,delta);
     }


//////////////////////// Disk access ////////////////////////////////////


     csCHAR *load_page_h(U32 page)
     {
        if(page==lr_page) return lr_add;
        lr_dirty=FALSE;
        return lr_add=load_page(lr_page=page);
     }

     csCHAR *load_page_hd(U32 page)
     {
        if(page==lr_page)
        {
            if(!lr_dirty) { dirty(lr_add); lr_dirty=TRUE; }
            return lr_add;
        }
        lr_dirty=TRUE;
        return lr_add=load_page_d(lr_page=page);
     }


     olhe *HP(U32 page)  { return (olhe *)load_page_h(page); }
     olhe *HPd(U32 page) { return (olhe *)load_page_hd(page); }

/////////////////////////// DB Header ///////////////////////////////////
     virtual int read_header(void);
     virtual int write_header(void);



/////////////////////////  Modifying page header //////////////////////////////////

     void modify_head(U32 page,U32 p_page,U32 n_page)
          {olhe *p=HPd(page); p->p_page=p_page; p->n_page=n_page;}
     void modify_head(U32 page,U32 p_page,U32 n_page,U16 used)
          {olhe *p=HPd(page); p->p_page=p_page; p->n_page=n_page;p->used=used; }
     void modify_p_page(U32 page,U32 p_page) { HPd(page)->p_page=p_page; }
     void modify_n_page(U32 page,U32 n_page) { HPd(page)->n_page=n_page;}


/////////////////////////  Prev/Next page number //////////////////////////////////

     U32  prev_page_num(olpo& olp) { return prev_page_num(olp.page); }
     U32  prev_page_num(U32 page)  { return HP(page)->p_page; }

     U32  next_page_num(olpo& olp) { return next_page_num(olp.page); }
     U32  next_page_num(U32  page) { return HP(page)->n_page; }
     U32  next_page_num(olhe *hp)  { return hp->n_page; }


/////////////////////////  Pointers ///////////////////////////////////////////////

     csCHAR *pos_po(olpo &olp)  { return load_page_h(olp.page)+olp.offset; }
     csCHAR *pos_pod(olpo &olp) { return load_page_hd(olp.page)+olp.offset; }
     csCHAR *pos_pod_last(void)
     {
        olhe *h=HPd(last_page);
        return ((csCHAR *)h)+h->used+mini_off();
     }

/////////////////////////  Amount of data on a page ///////////////////////////////

     U16  is_used(olpo &olp)  { return is_used(olp.page); }
     U16  is_used(U32  page)  { return HP(page)->used; }

     void modify_used(olpo &pos,U16 use)         { HPd(pos.page)->used=use; }
     void modify_used(U32 page,U16 use)          { HPd(page)->used=use; }
     void modify_used_delta(olpo &pos,S16 delta) { HPd(pos.page)->used+=delta; }
     void modify_used_delta(U32 page,S16 delta)  { HPd(page)->used+=delta; }

// Can become negative!
     S16  left_used(olpo &olp)           { return left_used(HP(olp.page),olp.offset); }
     S16  left_used(olhe *hp,U16 offset) { return hp->used-(offset-mini_off()); }

     U16  space_free(olpo &olp) { return max_free()-is_used(olp); }
     U16  space_free(U32 page)  { return max_free()-is_used(page); }

/////////////////////////  Locating //////////////////////////////////////////////

     void go_to(olpo &pos,U32 new_pos);
     olpo go_to(U32  pos);

     void last(olpo &pos)
     {
          pos.page=last_page;
          pos.pos=last_pos;
          pos.offset=mini_off()+is_used(last_page);
     }
/////////////////////////  Auxiliary //////////////////////////////////////////////

     U16  mini_off(void)   { return sizeof(olhe); }
     U16  max_free(void)   { return per_page; } //Set during open()
     void ola_copy(olpo &p2,olpo &p1,U16 len);

     virtual void set_id(void);
     virtual int check_id(U32 id);


/////////////////////////  Support for public functions ////////////////////////////

     void del_mod_use(olpo &pos,U16 new_used);
     int  insert(olpo &pos,void *p,U32 len);
     U32  read(olpo &pos, void *p,U32 len);
     int  replace(olpo &pos,U32 old_len,void *p_new,U32 new_len);
     U16  stil_fit(olpo &pos) { return page_size()-pos.offset; }
     U16  stil_fit(U16 used ) { return max_free()-used; }
     int  writea(olpo &pos,void *p,U32 len);
     int  write(olpo &pos,void *p,U32 len);

     int inserta(olpo &pos,void *p,U32 len)
         {
            if (pos.pos==bottom()) return append(pos,p,len);
            else                   return insert(pos,p,len);
         }

/////////////////////////  Table functions ////////////////////////////////////////

     int  table_look(U32  pos,olpo& op);
     void table_insert(olpo& op)                { table.insert(op.pos,op.page); }
     void table_insert(U32 pa,U32 po)           { table.insert(po,pa); }
     void table_delete_update(olpo& op,U32 len) { table.upd_delet(op.pos,len); }
     void table_insert_update(olpo& op,U32 len) { table.upd_insert(op.pos,len); }
     void table_unchain_update(olpo &pos)       { table.delet(pos.pos); }


////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
////////////////////// PUBLIC FUNCTIONS ////////////////////////////////
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////


  public:
     OLAY(void);
     virtual
    ~OLAY(void);

//////////////////////// Compatibility function /////////////////////////////
     U32  numbytes(void)      { return bottom()-1; }

//////////////////////// Definition //////////////////////////////////////////
/* Inherited
     void page_size(U16 t)
     void header_page_size(U16  n);
*/
     int  define(csCHAR *name,U16 page_length=2048);

//////////////////////// Open & Close ////////////////////////////////////////
/* Inherited
     int  already_open(void);
*/
     int  open(csCHAR *name,S16 kb_buf=30);
     int  save(void);
     int  close(void);

//////////////////////// Read & Write ////////////////////////////////////////
     U32  read(U32  pos,void *p,U32 len)
          { olpo op=go_to(pos); return read(op,p,len); }

     int  write(U32  pos,void *p,U32 len)
          { olpo op=go_to(pos); return write(op,p,len); }

     int  writea(U32 pos,void *p,U32 len)
          { olpo op=go_to(pos); return writea(op,p,len); }

//////////////////////// Append  /////////////////////////////////////////////
     int  append(void *p,U32 amount);
     int  append(olpo &pos,void *p,U32 amount);

//////////////////////// Replace /////////////////////////////////////////////
     int  replace(U32 pos,U32 old_len,void *p_new,U32 new_len)
          { olpo op=go_to(pos); return replace(op,old_len,p_new,new_len); }

//////////////////////// Delete //////////////////////////////////////////////

     S32  delet(U32  pos,S32 len)
          { olpo op=go_to(pos);  return delet(op,len); }
     S32  delet(olpo &pos,S32 len);

//////////////////////// Insert //////////////////////////////////////////////
     int  insert(U32  pos,void *p,U32 len)
          { olpo op=go_to(pos); return insert(op,p,len); }
     int  inserta(U32 pos,void *p,U32 len)
          { if (pos==bottom()) return append(p,len);
            else               return insert(pos,p,len);  }

//////////////////////// Last position /////////////////////////////////////////
     U32  bottom(void)        { return last_pos; }

//////////////////////// Number of bytes in File ///////////////////////////////
     U32  filesize(void)      { return bottom()-1; }

//////////////////////// Import & Export //////////////////////////////////////
     int  import_bin(csCHAR *name)  { return import(name,TRUE);  }
     int  import_asc(csCHAR *name)  { return import(name,FALSE); }
     int  import(csCHAR *name,int bin_mode=TRUE);

     int  export_bin(csCHAR *name)  { return export(name,TRUE);  }
     int  export_asc(csCHAR *name)  { return export(name,FALSE); }
     int  export(csCHAR *name,int bin_mode=TRUE);

//////////////////////// Data in Header Page /////////////////////////////////
  /* Inherited
     int  data_2_header(void * ptr,U16 length);
     int  header_2_data(void * ptr,U16 length);
     U16  max_data_in_header(void);
  */

////////////////////////// Reports /////////////////////////////////////////////
     int  report(csCHAR *name,int sub=1);
     void report(FILE *fp,int sub=1);


////////////////////////// Sequential IO ///////////////////////////////////////
// The next functions are intended to mimic the classical
// sequential IO, which its typical notion of a file pointer
// which increases with the amount of data read or written.
// IMPORTANT:
//     All the other functions are complete unaware of this
//     (the file pointer that is) and don't update it.
//     So, every time you have used one of the functions outside
//     this category, you should re-use the fseek to
//     correctly position this (virtual) file pointer.
//

    int   fseek(long offset,int origin=SEEK_SET);
    long  ftell(void)  { return current.pos-1; }
    int   feof(void)   { return (current.pos==bottom()); }
    int   fgetc(void);
    int   fputc(int c);
    int   fread( void *buf,int size,int count);
    int   fwrite(void *buf,int size,int count);
    csCHAR *fgets(csCHAR *str,int num);
    int   fputs(csCHAR *str) { return !fwrite(str,strlen(str),1); }


// The next two functions are our additions to support insertions
// and deletions.
//
// The delete function leaves the file pointer unchanged, which means
// pointing to the same offset as before the delete. Note however, that
// the data 'underneath' the pointer is no longer the same.
// If an attempt is made to delete more data then there is left in
// the file (from the file pointer to the end), all the remaining
// data is deleted and no error is produced.
//
// The insert function increments the file pointer with the amount of
// data inserted.
//
// The insert functions returns zero on failure and nonzero on succes.
// The delete functions returns the amount of data actually deleted.
//
    long  fdelete(long amount);
    int   finsert(void *buf,long amount);

////////////////////////// Miscellaneous ///////////////////////////////////////
/* Inherited
     int  background(void)
*/
     int  pack(void);
     int  empty(void);
     void info(void);


     void fflush(void)           { BUFFER::save(); }
     virtual int class_ID(void)  { return CS_CLID_OLAY; }


};





#ifdef _CP_002
  #pragma warning(default: 4270 4067 4018)
#endif




#endif
