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

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

       Header file of the BUFFER class.

       This class buffers the IO done by the database classes.
       BUFFER neither opens nor closes a stream. Its open function accept
       a file pointer to an already opened stream. Similar, the close()
       function stops the buffering process, but doesn't close the stream.

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

#ifndef __CSBUFF_H
#define __CSBUFF_H

#include "csstr.h"
#include "cstable.h"
#include "cstypes.h"


class BUFFER: public TABLE
{

private:

   FILE *fipo;

   csSTR b_name;    // Name of the buffer system
   int	 is_open;
   int	 bReadOnly;

protected:


   U32 bufbit;


   enum { ST_READ=0, ST_DIRTY=1 };

   typedef struct
   {
      void *prev;
      void *next;
      void **key_add;
      U32  key;
      int  stat;
      int  prior;
   } bcp;	      // Buffer Chain Pointers


   U32	 lbsc_k;      // Load Buffer Short Cut Key
   int	 lbsc_p;      // Load Buffer Short Cut Priority
   int	 lbsc_s;      // Load Buffer Short Cut Status
   void *lbsc_a;      // Load Buffer Short Cut Address

   U32	*bupo;
   U32	*bupn;
   bcp	*buch;	      // Buffer chains
   U16	*buma;	      // Max number of buffer in chain
   U16	*buco;	      // Number of buffers currently in chain


   U32	reco;	      // Number of reads from file
   U32	wrco;	      // Number of writes to file.
   U32	fbco;	      // Number of times a 'force-buffer' was needed.
   U32	llco;	      // Locate and Load count;

   U16	bs;	      // Buffer Size
   U16	nb;	      // Maximum Number of Buffers
   U16	nbm;	      // Minimum Number of Buffers
   U16	na;	      // Number of buffers currently Allocated from OS
   U16	bas;	      // Buffer Allocation Size (bs+sizeof(bcp))

   U16	buf_lim_nr;   // Limits the index blocks down.
   U16	headpagesize; // Size of the first page, containing the header.
   S32	headoff;      // Offset to the first page in file. (Can be negative)
   int	enoug_mem;    // Short-cut in memory allocation.

   int	echo_on;



protected:

////////////////////////// Core functions //////////////////////////////////////
//   Chain
   void connect(bcp &left,bcp &right)	{ left.next=&right; right.prev=&left; }
   void connect(void *left,void *right) { connect(*(bcp *)left,*(bcp *)right); }
   void end_ic(bcp &c,bcp *p)		{ connect(*(bcp *)c.prev,*p); connect(*p,c); }
   bcp *init_bcp(void *d,U32 key,void **add,int prior,int stat);

//   Buffers
   void *i2b(void *p)	       { return ((csCHAR *)p-bs); }
   void *b2i(void *p)	       { return ((csCHAR *)p+bs); }
   void  force_buff(U32 key,void *& data,void ** addr,int prior,int stat);

//   I/O
   U32	 pos_infile(U32 pagnr)		  { return headoff+pagnr*bs; }
   void  file_2_buffer(U32 key,void *buf);
   void  buffer_2_file(U32 key,void *buf);



protected:

   void free_chain(bcp *p);
   void init_allocs(void);
   void init_vars(void);
   void init_defaults(void);

////////////////////////// Miscellaneous ///////////////////////////////////////
   void set_num_page(U32 n);

   int	close2(void);
   void overflow_buf(int prior);
   void buf_show(void);

   void buco_min(int prior)   { buco[prior]--; }

   void buco_plus(int prior)
   {
     if(  buco[prior]==buma[prior]) overflow_buf(prior);
     else buco[prior]++;
   }



////////////////////////////////////////////////////////////////////////////////
////////////////////////			    ////////////////////////////
////////////////////////     P U B L I C	    ////////////////////////////
////////////////////////			    ////////////////////////////
////////////////////////////////////////////////////////////////////////////////


public:

   virtual
  ~BUFFER(void);
   BUFFER(void);

   void echo_IO(int TF) { echo_on=TF; }

////////////////////////// Setup functions /////////////////////////////////////

   void index_limit(U16  nr);
   void header_page_size(U16  n);

   void buffer_size(U16  n);
   void number_buff(U16  maxi,U16  mini=2);

   void number_buff_min(U16  mini);

////////////////// Compatibility ////////////////////////////////////
   void    name(csCHAR *s)	   { e_name(s);       }
   csCHAR *name(void)		   { return e_name(); }


/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////

   void    e_name(csCHAR *s)	   { b_name=s; TABLE::name(s); }
   csCHAR *e_name(void) 	   { return (csCHAR *)b_name; }



////////////////////////// Open & Close ////////////////////////////////////////


   void read_only(void)     { read_only(TRUE);	}
   void read_only(int ToF)  { bReadOnly=ToF;	}
   int	is_read_only(void)  { return bReadOnly; }


   void open(FILE *p);
   int	open(void)	 { return IsOpen(); }

   int	IsOpen(void)	 { return is_open;  }
   void IsOpen(int ToF)  { is_open=ToF;     }

   int	close(void);
//   void zap(void);
   void empty(void);

////////////////////////// Number of Buffers ///////////////////////////////
   U16	number_buff_max(void)	 { return nb;  }
   U16	number_buff_min(void)	 { return nbm; }


////////////////////////// Writing back to disk ////////////////////////////////
// void flush(void);
   void save(void);

////////////////////////// Locate & Load functions /////////////////////////////
   void *locate_buff(U32 key,int prior,int rwl);
   void *load_buff(U32 key,int prior,int rwl);

   void *locate_buff(U32 key)	   { return locate_buff(key,1,ST_READ);  }
   void *load_buff(U32 key)	   { return load_buff(key,2,ST_READ);	 }
   void *locate_buff_d(U32 key)    { return locate_buff(key,3,ST_DIRTY); }
   void *load_buff_d(U32 key)	   { return load_buff(key,4,ST_DIRTY);	 }
   void *load_buff_ld(U32 key)	   { return load_buff(key,31,ST_DIRTY);  }
   void *locate_buff_ld(U32 key)   { return locate_buff(key,31,ST_DIRTY);}
   void *load_buff_l(U32 key)	   { return load_buff(key,31,ST_READ);	 }
   void *locate_buff_l(U32 key)    { return locate_buff(key,31,ST_READ); }

   int	in_ram(U32 key);
   int	in_ram(U32 key,void * &buf);

////////////////////////// Changing Status & Priority //////////////////////////
   void change_stat(void *buf,int prior,int stat);
   void change_stat(void *buf,int prior);
   void change_stat(U32 key,int prior);
   int	priority(void *buf)	    { return ((bcp *)b2i(buf))->prior; }
   void max_with_priority(int prior,U16  number) { buma[prior]=number; }
   int	max_with_priority(int prior)		 { return buma[prior]; }

////////////////////////// Set Clean/Dirty flag ////////////////////////////////
   int	is_dirty(void *buf)	   { return ((bcp *)b2i(buf))->stat;   }
   void dirty(void *buf)	   { ((bcp *)b2i(buf))->stat=ST_DIRTY; }
   void clean(void *buf)	   { ((bcp *)b2i(buf))->stat=ST_READ;  }

   int	is_dirty(U32 key);
   void dirty(U32 key)	   { void *buf; if(in_ram(key,buf)) dirty(buf); }
   void clean(U32 key)	   { void *buf; if(in_ram(key,buf)) clean(buf); }

   int	has_been_updated(void);

///////////////////////// Report writing //////////////////////////////////////
   int	report(csCHAR *name,int sub=1);
   void report(FILE *fipo,int sub);


////////////////////////// Background processing ///////////////////////////////
   int	background(void);

};
#endif
