//    client.h
//       The definition of the data structures of client
//

//#define CLIENTCACHESIZE 2048  // blocks, each 8096 bytes.

#define CLIENT_SCHEME_NONE    0   // no client
#define CLIENT_SCHEME_BASE    1   // noncooperative
#define CLIENT_SCHEME_GLOBAL  2   // global overflow server
#define CLIENT_SCHEME_CHANCE1 3   // 1 chance
#define CLIENT_SCHEME_CHANCER 4   // 1 chance and return-on-hit

struct ClientBlock
{
  unsigned char flag;
  unsigned c_num;   // client id;
  unsigned d_num;   // device number
  unsigned i_num;   // inode number
  unsigned b_num;   // block number
  unsigned refcount; // reference bit
  
  struct ClientBlock * prev;
  struct ClientBlock * next;
  struct ClientBlock * up;
  struct ClientBlock * down;
};

class ClientServer
{
 public:
  struct ClientBlock HT[HASHTABLESIZE];
  struct ClientBlock * UsedList; // a double list with a sentinel
  struct ClientBlock * FreeList; // a single list

 public:
  unsigned putcount;   // the number of blocks received 

  unsigned missblock;   // the number of missed blocks
  unsigned totalblock;  // the number of referenced blocks

  unsigned cachesize;   // the total size of cache
  unsigned globalused;  // the number of blocks used for global scheme

 public:
  ClientServer();
  ClientServer(unsigned csize);
  ~ClientServer();

  // return 1 if find, return 0 otherwise; the reference state is also changed
  virtual int LookUp(unsigned cid, unsigned idev, unsigned inode, unsigned bnum);

  // put data into the cache
  // return 1 means there is free block, return 2 means one block is replaced
  virtual int TransferData(unsigned cid, unsigned idev, unsigned inode, unsigned bnum, unsigned rcount,
			   //unsigned &elapse, unsigned &netcount);
			   TimeBD &elapse, unsigned &netcount);
};


class Client
{
 public:
  unsigned char schememode;

  struct ClientBlock HT[HASHTABLESIZE];
  struct ClientBlock * UsedList; // a double list with a sentinel
  struct ClientBlock * FreeList; // a single list
  
  struct ClientBlock * RefList; // a double list with a sentinel
  struct ClientBlock * FreeRefList; // a single list, 3 times size of FreeList

  unsigned clientid;

  unsigned iocount;     // the number of server accesses caused by cache miss
  unsigned refcount;    // the number of references

  unsigned remotehit;   // the number of hits on other clients
  unsigned missblock;   // the number of missed blocks
  unsigned totalblock;  // the number of referenced blocks

  unsigned cachesize;   // the total size of cache
  unsigned globalused;  // the number of blocks used for global scheme
  unsigned localused;   // the number of blocks used for local disk

 public:
  Client();
  Client(unsigned char mode, unsigned cid, unsigned csize);
  ~Client();

  // return 1 if find, return 0 otherwise
  virtual int LookUp(unsigned cid, unsigned idev, unsigned inode, unsigned bnum);

  // return remote device id if find, return -1 otherwise
  virtual int RLookUp(unsigned cid, unsigned idev, unsigned inode, unsigned bnum);

  // put data into the cache
  // return 1 means there is free block, return 2 means one block is replaced
  // return 0 means rejected
  virtual int TransferData(unsigned cid, unsigned idev, unsigned inode, unsigned bnum, unsigned rcount,
			   //unsigned &elapse, unsigned &netcount);
			   TimeBD &elapse, unsigned &netcount);

  // Read the data from the server, and elapse is the return time
  //    statflag  == 0 means no statistics
  // Return 1 if success, else return 0
  virtual int ReadData(unsigned cid, unsigned idev, unsigned inode, unsigned b_begin, unsigned b_count, 
		       //unsigned &elapse, unsigned &netcount, unsigned char statflag);
		       TimeBD &elapse, unsigned &netcount, unsigned char statflag);

  // the same as ReadData so far
  // Return 1 if success, else return 0
  virtual int WriteData(unsigned cid, unsigned idev, unsigned inode, unsigned b_begin, unsigned b_count, 
			//unsigned &elapse, unsigned &netcount, unsigned char statflag);
			TimeBD &elapse, unsigned &netcount, unsigned char statflag);

  // create a file on the disk
  // Return 1 if success, else return 0
  //virtual int Create(unsigned cid, unsigned idev, unsigned &elapse, 
  //		     unsigned &netcount, unsigned char statflag);

  // remove a file
  // Return 1 if success, else return 0
  //virtual int Unlink(unsigned cid, unsigned idev, unsigned inode, unsigned &elapse, 
  //		     unsigned &netcount, unsigned char statflag);
};

