/*******************************************************************
 *                  Light Weight Chord Library 1.0                 *
 *  CopyRight(C) Yoshihide Matsumoto IDEON WorkingGroup 2003,2004  *
 *      matsumoto333@yahoo.co.jp (http://www.matchan.mydns.jp)     *
 *                                                                 *
 * Implementation of chord (Distributed Hash Table)                *
 * This program is distributed under GPL                           *
 * Light Weight Chord Library comes with ABSOLUTELY NO WARRANTY.   *
 * This is free software, and you are welcome to redistribute it   *
 * under certain conditions; read `COPYING' for details.           *
 *******************************************************************/


#ifndef __MCHORD
#define __MCHORD


#include "inc.h"
#include "id_list.h"
#include "task_list.h"

#define MAX_BIT        32 //TODO:extend to 160bit
#define STATISTICS_MAX 10
#define CACHE_DIR_MAX  256

typedef struct _RT {
  int McId;
  int Ip;
  int Port;
}RT;




enum STATE { NONE, CONNECTING, UPDATING, RING_UPDATING, READY, DANGEROUS };


class MChord{
 private:
  TASKLIST *mTaskList;
  int mBeginId;//My Id
  int mEndId;
  IDLIST   *mIdList;
  ADDRESS   mPoolIPAddrList[MAX_BIT];
  STATE     mState;
  RT        mRoutingTable[MAX_BIT];
  int       mIp;
  int       mPort;
  int       mBackRefList[MAX_BIT];
  int       mTimer;
  ADDRESS   mNext;
  ADDRESS   mPrev;
  int       mTmpSessId; //Join <->JoinAccept
  int       mTmpMcId;   //JoinAccept <->RecvAck
  ADDRESS   mTmpNext;   //Join <-> RecvAck
  int       mTmpFunc;   //using Insert
  int       mTmpSessIdLogin; ///using Login
  int       mTmpInsert;
  int       mSeqNo;
  int       mRetransmitMax;
  int       mFlag;//RecvFile
  FILE     *mFP;
  int       mFileSeqNo;
  char      mCacheDir[CACHE_DIR_MAX];
  
  //log
  FILE      *mLogFP;
  int       mLogFlg; //0 = ./PORT.log ,1 = stderr

  //statistics
  int       mSendCount[STATISTICS_MAX];//0 SendAck
  int       mRecvCount[STATISTICS_MAX];//0 RecvAck

 public:

  MChord(int port, char *cache_dir, int log_flg);
  void Join(char *addr);
  void SendJoin(ADDRESS Address);   
  void RecvJoin(ADDRESS Address, int mcid, int sess_id, int seq_no);
  void RecvJoinRedirect(ADDRESS Address, int sess_id, int seq_no, int ip, 
			int port);
  
  void DeleteIdList(int mcid);
  void UpdateRT();
  
  void RecvJoinAccept(ADDRESS Address, int SessId, ADDRESS Next, int EndId, 
		      int seq_no);

  int  UpdateTaskOfFile(TASKLIST *task);
  void SetTaskOfFile(ADDRESS Address, int mcid, int sess_id);
  void RecvFile(ADDRESS Address, int seq_no, int size, int sessid, int mcid, 
		int fileseqno, int flag, char *buff);

  void SendLookupData(char *data);
  void SendLookupKey(int key);
  void RecvLookup(ADDRESS Address, int SessId, int McIdTo, int McIdFrom,
		  int Ttl, int SeqNo, ADDRESS AddressOrg);
  
  void RecvLookupResponse(ADDRESS Address, int SessId, int McId, int SeqNo,
			  int Ans, int Ttl, int McId2);
  
  void SendInsert(int key);
  void RecvInsert(ADDRESS Address, char *data, int size, int mcid);
  
  void SendLeave(ADDRESS Address);
  void RecvLeave(ADDRESS Address, int sessid, ADDRESS next, int BeginId, 
		 int EndId, int SeqNo);
  void RecvLeaveEnd(ADDRESS Address, int sessid, int SeqNo);
  
  unsigned int getBeginId();
  int getPort();
  int setPort(int port);
  ADDRESS LookupRT(int key);
  
  TASKLIST *LookupTaskBySession(int sess_id );
  TASKLIST *SendTask(TASKLIST *task);

  TASKLIST *SetTaskOfData(ADDRESS Address, int func, int sess_id, ADDRESS next,
			  int mcid, int Ans, int Ttl);
  void SetTaskOfEvent(ADDRESS Address, int func, int sess_id);

  void SendTaskBySession(int sess_id);
  //timer
  void TimerFunc();
  TASKLIST *Retransmit(TASKLIST *ptask);
  TASKLIST *CancelSession(int session);

  void RecvAck(ADDRESS Address, int sequenceno);
  
  void PrintStatistics();

  int  GetTimer();  
  int  GetPort();
  char *GetCacheDir();
  int  GetIp();
  int  GetLogFlg();

  //extend
  void SendMessage(ADDRESS Address, char *data);
  void RecvMessage(ADDRESS Address, int SeqNo, char *data);
  void message(char *fmt, ...);


  //quit
  //call by main
  void Quit();
};

#endif
