/*
 * Copyright (C) 2008 The Trustees of Columbia University in the City of New York. 
 * All rights reserved.
 *
 * See the file LICENSE included in this distribution for details.
 */

#include "bamboopeer.h"

#ifndef _WENGO
#include "bamboortable.h"
#include "trace.h"
#endif

#ifdef _WENGO
#include "p2pp/table/bamboortable.h"
#include "p2pp/common/trace.h"
#endif

#define K_FACTOR 16
#define LEVELS (m_HASH_SIZE*8)
#define DIGITS m_BASE
 
void* GlobalTuningOnLookupPeer(void* pN, int32 respcode);

BambooPeer::BambooPeer() {

}

BambooPeer::~BambooPeer() {

}

void BambooPeer::Initialize() {

  m_pRT = new BambooRTable;
  m_pBRT = (BambooRTable*)m_pRT;
  
  m_pNT = new BambooNTable;
  m_pBNT = (BambooNTable*)m_pNT;
  
  m_PushPull=4;
  m_GlobalTuning=20;
  m_LocalTuning=10;

  Peer::Initialize();

}//Initialize

uint32 BambooPeer::getNextHop(uchar* peerid, uint32 len, struct peerinfo& stP) {

  /*handling churn in DHT: USENIX 2004: section 2*/
  uint32 ret;
  struct peerinfo pinfo;
  
  /*first search in neighbour table */
  ret = m_pBNT->getNextHop(peerid, len, stP);
  if(ret==1){
    return ret;
  }
  /*now search in routing table*/
  ret = m_pBRT->getNextHop(peerid, len, pinfo);
  if(ret==1){
    stP = pinfo;
  }
  return ret;
}//getNextHop

void BambooPeer::OnTransactionTimeout(Transaction* pobjTrans) {
  struct peerinfo stpeer;
  LObject objLO;

  //remove failed peer from routing table
  m_pBRT->removePeer(pobjTrans->m_pchIP, pobjTrans->m_uiPort);
  
  TRACE(2, "BambooPeer::OnTransactionTimeout...state %d size: %d\n", m_eState, m_BSP.size() );  

  switch(m_eState) {

  case ePJOIN:
    TRACE(2, "BambooPeer::OnTransactionTimeout...size: %d\n", m_BSP.size() );

    m_BSP.pop_front();

    if(m_BSP.size() > 0) {      

      stpeer = *m_BSP.begin();
      TRACE(2, "BambooPeer::OnTransactionTimeout...Sending Peer Lookup...BSP_self...size: %d\n", m_BSP.size() );
      ComposeJoin(*m_BSP.begin());

    } else {

      m_eState = ePCONNECTED;
      
      setPushPullTimer();
      setGlobalTuningTimer();
      setLocalTuningTimer();
      
      printf("connected state\n");
      //Insert itself as a resource-object in its own
      //resource-object
      m_objRM.PublishUserInfo( (char*)m_USERID, strlen((char*)m_USERID), eUDP );
      //inform the application
      objLO.ritype = eBOOTSTRAP;
      objLO.pApp = m_pApp;
      if(appCallBack){
        appCallBack( (void*)&objLO, 200);
      }
    }
    break;

  case ePCONNECTED:
    m_objRM.OnTransactionTimeout(pobjTrans->m_msgtype, pobjTrans->m_reqoritype, pobjTrans->getTransId(), pobjTrans->m_pchIP, pobjTrans->m_uiPort);
    break;

  default:
    break;
  }//end switch

}//OnTransactionTimeout


void BambooPeer::OnTimer() {
  
  map<string, Transaction*>::iterator itr;
  list<LObject>::iterator i1;
  list<peerinfo>::iterator litr;
  list<string> lint;
  list<string>::iterator listitr;
  struct peerinfo stP;
  list<struct peerinfo> lstP;
  int32 ret=0;
  uint32 rndm_no,rndmlevel, rndmdigit, count;
  LObject objLO,objLO1;
  string strtransid;

  TRACE(5,"BambooPeer::OnTimer - transaction map size: %d\n", m_TMap.size());
  
  //CODE FOR interacting with command line
  for(i1=m_LO.begin(); i1 != m_LO.end(); i1++) {
    if( (*i1).ritype == ePUBLISHOBJECT) {

      if( (*i1).changeID == 0) {
        m_objRM.PublishObject( (char*)(*i1).strKey.c_str(), (*i1).strKey.size(), (char*)(*i1).strVal.c_str(), (*i1).strVal.size(), (*i1).tt, (*i1).callback, (*i1).pApp);
      } else {
        m_objRM.ChangeUserID( (char*)(*i1).strKey.c_str(), strlen( (char*)(*i1).strKey.c_str()) );
      }

    } else if((*i1).ritype == eLOOKUPOBJECT) {
      
      if( (*i1).conttype == eSTRINGVAL) {
        m_objRM.LookupObject((char*)(*i1).strKey.c_str(), (*i1).strKey.size(), (*i1).tt, (*i1).callback, (*i1).pApp);
      } else if( (*i1).conttype == eUSERINFO ) {
        m_objRM.LookupUser((char*)(*i1).strKey.c_str(), (*i1).strKey.size(), (*i1).tt, (*i1).callback, (*i1).pApp);
      }
    } else if( (*i1).ritype == eGETDIAGNOSTICS ) {
      m_objMH.GetDiagnostics( (char*)(*i1).pchIP, (*i1).port, (*i1).tt, (*i1).diagtype, (*i1).callback, (*i1).pApp );
    }else if ( (*i1).ritype == eLEAVE ) {
      if( 1 == (*i1).disconnect) {
	m_eState = ePDISCONNECTED;

	//create a copy of call back function
	objLO1.callback = (*i1).callback;
	objLO1.pApp = (*i1).pApp;
	break;
      }
    }

    
  }//end for

  m_LO.clear();
  //CODE FOR interacting with command line ENDS


  //Transaction management code BEGINS
  //Check if transaction has timedout
  for(itr=m_TMap.begin(); itr!=m_TMap.end(); itr++) {
    ret = itr->second->OnTimer();
    
    //the transaction has expired
    if(0 == ret) {
      OnTransactionTimeout(itr->second);

      TRACE(2, "BambooPeer::OnTimer...deleting transaction state: %d\n", m_eState);

      //The transaction was allocated so it must be deleted
      delete itr->second;
      lint.push_back(itr->first);
    }
  }//end for

  for(listitr=lint.begin(); listitr!=lint.end(); listitr++) {
    itr = m_TMap.find(*listitr);
    if(itr != m_TMap.end() ) {
      m_TMap.erase(itr);
    }
  }//end for

  switch(m_eState){

  case ePBOOTSTRAP:
    ComposeBootstrap();
    m_eState = ePBOOTSTRAPSENT;
    break;
   
  case ePINITIAL:
    break;
    
  case ePCONNECTED:
    //Apply timer to resource object
    m_objRM.OnTimer();

    //check if keep alive timer has expired
    if(isPushPullExpired()){
      TRACE(4, "Bamboo::OnTimer...Push-Pull timer expired\n","");
      //exchange neighbour table with a random node in neighbour table.
      lstP.clear();
      m_pBRT->getTable(lstP);
      if(lstP.size()>0){
	rndm_no = rand()%lstP.size();
	litr=lstP.begin();
	count=0;
	while(litr!=lstP.end()){
	  litr++;
	  count++;
	  if(count != rndm_no ){
	    continue;
	  }
	  TRACE(4,"Bamboo::OnTimer...Push-Pull %s\n",(char*)litr->stpeerid.id);
	  ComposeExchangeTable(*litr);
	}
      }
      setPushPullTimer();
    }//endif

    //check if Global Tuning timer has expired.
    if(isGlobalTuningExpired()){
      TRACE(4, "Bamboo::OnTimer...Global Tuning expired\n", "");
      //select an ID and tune its entry in Routing table
      rndmlevel = rand()%LEVELS;
      rndmdigit = rand()%DIGITS;
      GlobalTuning(rndmlevel, rndmdigit, GlobalTuningOnLookupPeer);
      setGlobalTuningTimer();
    }//endif

    //check if Local Tuning timer has expired.
    if(isLocalTuningExpired()){
      TRACE(4, "Bamboo::OnTimer...Local Tuning timer expired\n", "");
      //select a level and digit, Tune the routing table.
      rndmlevel = rand()%LEVELS;
      rndmdigit = rand()%DIGITS;
      if(m_pBRT->getPeerLevelDigit(rndmlevel,rndmdigit,stP)==1){
	TRACE(4, "Bamboo::OnTimer:LocalTuning...ip: %s\n", stP.staddr.addr[0]);
	//printf( "Bamboo::OnTimer:LocalTuning...ip: %s, %d\n", stP.staddr.addr[0], rndmlevel);
	objLO.stpl.num=rndmlevel;
	objLO.stpl.isPresent=1;
	objLO.stpl.stida.isPresent=1;
	memcpy(objLO.stpl.stida.id, stP.stpeerid.id, m_HASH_SIZE);
	ComposeExchangeTableWithLookupPeer(stP,objLO,strtransid);
	//m_IP[strtransid]=objLO;

	//ComposeExchangeTable(stP);
      }
      
      setLocalTuningTimer();
    }//endif
    break;

  case ePDISCONNECTED:
    TRACE(1, "BambooPeer::OnTimer...Transport disconnecting\n", "");
    m_pobjTransport->Disconnect();
    
    m_objMH.Disconnect(); //Maintenance helper disconnect    
    m_objRM.Disconnect(); //Resource manager disconnect
    m_pBRT->Disconnect(); //Routing table disconnect
    m_pBNT->Disconnect(); //Routing table disconnect

    delete m_pBRT; //delete the routing table object
    delete m_pBNT; //delete the routing table object

    m_BSP.clear();  //clear the bootstrap list

    objLO1.callback( (void*)&objLO1, 200);
    break;

  default:
    break;

  }//end switch

  Peer::OnTimer();
  
  TRACE(5, "BambooPeer::OnTimer\n", "");
}//OnTimer

int32 BambooPeer::OnReceive(uchar* buf, int len, char* pchIP, int32 port, transtype tt) {
  map<uint32, Transaction*>::iterator itr;
  
  //Initialize the message structure
  m_msg.Initialize();

  TRACE(2, "BambooPeer::OnReceive...received\n", "");

  //Parse the message
  m_msg.parse(buf, len);

  //if ACK
  if(1==m_msg.stcmn_hdr.ack){
    OnACK(pchIP, port, tt);
  }else  if(eRESPONSE == m_msg.stcmn_hdr.msgtype 
	    || eRESPONSEACK == m_msg.stcmn_hdr.msgtype) {

    return OnResponse(pchIP, port, tt);    
  }else  if(eREQUEST == m_msg.stcmn_hdr.msgtype) {    
    OnRequest(pchIP, port, tt);
  }

  //Call Peer::OnReceive
  return Peer::OnReceive(buf, len, pchIP, port, tt);

}//OnReceive

int32 BambooPeer::OnACK(char* pchIP, int32 port, transtype tt) {
  map<string, Transaction*>::iterator itr;

  //Find the transaction
  itr=m_TMap.find(m_msg.getTransId());

  //If transaction does not exist, discard the ACK
  if(itr==m_TMap.end() ) {
    TRACE(2, "BambooPeer::OnACK...ACK received...transaction does not exist %d\n", m_msg.stcmn_hdr.transid);
    return 1;
  }
     
  switch(m_msg.stcmn_hdr.msgtype) {
      
  case eREQUEST:
    if(eREQUEST == itr->second->m_msgtype) {
      TRACE(1, "BambooPeer::OnACK...ACK received for REQUEST\n","" );
      itr->second->OnACK(m_msg);
    } else {
      TRACE(1, "BambooPeer::OnACK...expecting ACK for REQUEST but received otherwise\n", "" );
    }
    break;

  case eRESPONSE:
  case eRESPONSEACK:
  case eINDICATION:

    if(eRESPONSE == itr->second->m_msgtype || eRESPONSEACK == itr->second->m_msgtype || 
       eINDICATION == itr->second->m_msgtype) {

      TRACE(1, "BambooPeer::OnReceive....ACK received for RESPONSE, RESPONSEACK or INDICATION...Transaction size: %d\n", m_TMap.size() );
      delete itr->second;
      m_TMap.erase(itr);
      TRACE(2, "BambooPeer::OnReceive.....Transaction removed size: %d\n", m_TMap.size() );
    } else {
      TRACE(2, "BambooPeer::OnACK...expecting ACK for RESP, RESPACK, INDIC but received otherwise\n", "" );
    }
    break;

  default:
    break;
  }//end switch

  return 1;
}//OnACK

int32 BambooPeer::OnRequest(char* pchIP, int32 port, transtype tt) {
  
  list<peerinfo > lstP, nlstP, rlstP;
  struct peerinfo stPSelf, stPNext, stP;

  map<string, Transaction*>::iterator itr;
  list<resourceobject > lstro;
  
  //Find the transaction
  itr=m_TMap.find(m_msg.getTransId());
  
  //retransmission of request received for which response transaction
  //already exists. ignore.
  if(itr != m_TMap.end() && (eRESPONSE == itr->second->m_msgtype || 
                             eRESPONSEACK == itr->second->m_msgtype) ) {

    TRACE(1, "KadPeer::OnRequest...retransmission of request received for which a response transaction already exists", "");
    return 0;
    
  }//end if
  
  switch(m_eState){

  case ePCONNECTED:

    switch(m_msg.stcmn_hdr.reqoritype) {

    case eJOIN:
      stP=m_msg.stpeerinfo;
      m_objMH.OnJoinRequest(m_msg, pchIP, port, tt);
      //Insert if peer
      if(ePEER==m_msg.stcmn_hdr.porc){
	m_pBRT->Insert(stP,1);
	m_pBNT->Insert(stP,1);
      }
      break;

    case eKEEPALIVE:
      ComposeKeepAliveResp(pchIP, port, tt);
      break;
     
    case eLEAVE:
      break;
      
    case eEXCHANGETABLE:
      //this is equivalent to EXCHANGE_LEAF_SET
      lstP.clear();
      if(m_msg.stpl.isPresent==1){
	m_pBRT->getTableLevel(lstP,m_msg.stpl.num);
      }else{
	m_pBNT->getTable(lstP);
      }
      m_pBRT->Insert(m_msg.strt.table,1);
      m_pBNT->Insert(m_msg.strt.table,1);
      ComposeExchangeTableResp(lstP, pchIP, port, tt);
      break;
      
    case ePUBLISHOBJECT:
      //insert not required in Bamboo
      if(ePEER == m_msg.stcmn_hdr.porc) {
        m_pBRT->Insert(m_msg.stpeerinfo,1);
        m_pBNT->Insert(m_msg.stpeerinfo,1);
      }

      m_objRM.OnPublishObjectRequest(m_msg, pchIP, port, tt);
      break;
      
    case eLOOKUPPEER:
      //insert the object in own routing table
      //insert only if it is peer
      if(ePEER == m_msg.stcmn_hdr.porc){
	m_pBRT->Insert(m_msg.stpeerinfo,1);
	m_pBNT->Insert(m_msg.stpeerinfo,1);
      }
      
      //Global tuning
      m_objMH.OnLookupPeerRequest(m_msg, pchIP, port, tt);
      break;

    case eLOOKUPOBJECT:
      //insert the object in out own routing table
      //insert only if it is peer
      if(ePEER == m_msg.stcmn_hdr.porc){
	m_pBRT->Insert(m_msg.stpeerinfo,1);
	m_pBNT->Insert(m_msg.stpeerinfo,1);
      }
      
      m_objRM.OnLookupObjectRequest(m_msg, pchIP, port, tt);
      break;
      
    case eGETDIAGNOSTICS:
      rlstP.clear();
      nlstP.clear();
      m_pBRT->getTable(rlstP);
      m_pBNT->getTable(nlstP);
      m_objRM.getResTable(lstro);
      if(m_msg.stdiagoptions.r==1 || m_msg.stdiagoptions.e==1){
	ComposeDiagnosticsResp(rlstP, lstro, pchIP, port, tt);
      }else if(m_msg.stdiagoptions.n==1){
	ComposeDiagnosticsResp(nlstP, lstro, pchIP, port, tt);
      }
      break;

    default:
      break;
    }//end switch
    break;
    
  default:
    break;
  }//end switch

  return 1;

}//OnRequest

int32 BambooPeer::OnResponse(char* pchIP, int32 port, transtype tt) {

  list<peerinfo >::iterator litr;
  map<string, Transaction*>::iterator itr;
  enum msgtype eMType;
  struct LObject objLO;

  //If received over unreliable transport send the ACK immediately
  if(tt == eUDP || tt == eDTLS) {   
    ComposeACK(pchIP, port);
  }

  TRACE(1, "BambooPeer::OnResponse...Transaction map size: %d state: %d\n", m_TMap.size(), m_eState ); 

  //response or responseACK received. check for matched requests or responses
  itr=m_TMap.find(m_msg.getTransId());
  if(itr != m_TMap.end() ) {

    eMType=itr->second->m_msgtype;
    //If response matches to a request delete the request transaction
    if(eREQUEST == itr->second->m_msgtype ) {
      delete itr->second;
      m_TMap.erase(itr);

      TRACE(1, "BambooPeer::OnResponse.....Transaction terminated. size: %d\n", m_TMap.size() );
    }

    //If response matches to a response or responseACK transaction,
    //then we have received a retransmission of response. Ignore
    if(eRESPONSE == eMType || eRESPONSEACK == eMType) {

      TRACE(1, "BambooPeer::OnResponse.....retransmission of response received %s\n", m_msg.getTransId().c_str() );
      return 1;
      
    }//end if

  } else {
    TRACE(1, "BambooPeer::OnResponse.....Transaction does not exist %d\n", m_TMap.size() );
    return 1;
  }

  switch(m_eState){
    
  case ePBOOTSTRAPSENT:
    if(eBOOTSTRAP==m_msg.stcmn_hdr.reqoritype) {
     //Update global idlen
      idlen = m_msg.stp2poptions.halglen;

      getSelfID();

      //TEMP: set node id in routing table.
      m_pBRT->setNodeId(m_ID, m_msg.stp2poptions.halglen, m_msg.stp2poptions.hbase);
      m_pBNT->setNodeId(m_ID, m_msg.stp2poptions.halglen, m_msg.stp2poptions.hbase, K_FACTOR);

      //Update global idlen
      idlen = m_msg.stp2poptions.halglen;
      
      //Create bootstrap node list
      CreateBNList(m_BSP);

      if(m_msg.stlpeerinfo.size() <= 1) {
	m_eState = ePCONNECTED;
	setPushPullTimer();
	setGlobalTuningTimer();
	setLocalTuningTimer();

        printf("JOIN SUCCESSFUL === Peer-Id: 0x");

        for(int i=0; i<idlen; i++) {
          printf("%02x", m_ID[i]);
        }
        printf("\n");


        //Insert itself as a resource-object in its own
        //resource-object
        m_objRM.PublishUserInfo( (char*)m_USERID, strlen((char*)m_USERID), eUDP );
        
	//inform the application
	objLO.ritype = eBOOTSTRAP;
	objLO.pApp = m_pApp;
	if(appCallBack){
	  appCallBack( (void*)&objLO, 200);
	}
      }else {
	//join process
	m_eState = ePJOIN;
	m_eSubState = eS_PNONE;
	
        TRACE(2, "BambooPeer::OnResponse...Query...num peers: %d\n", m_msg.stlpeerinfo.size() );

        ComposeJoin(*(m_BSP.begin()));
        printf("===========joining=============\n");
	
      }
    }
    break;

  case ePJOIN:
    switch(m_eSubState) {
    case eS_PNONE:
      
      if(302 == m_msg.stcmn_hdr.respcode) {
        TRACE(2, "BambooPeer::OnResponse...302 for Join...Send Join\n", "");
	
        //Insert the peer in routing table

	if(ePEER == m_msg.stcmn_hdr.porc){
	  m_pBRT->Insert(m_msg.stpeerinfo,1);
	  m_pBNT->Insert(m_msg.stpeerinfo,1);
	}	

        //if there is a 302 present
        if(m_msg.stlpeerinfo.size() > 0) {
          litr=m_msg.stlpeerinfo.begin();
	  
          ComposeJoin(*litr);
        } else {
          printf("Error in Join...There was no peerinfo object in 302\n");
        }
	
      } else if(200 == m_msg.stcmn_hdr.respcode) {
        TRACE(2, "BambooPeer::OnResponse...200 for Join\n", "");
        m_eState = ePCONNECTED;
	
        printf("connected state\n");
	
        //Insert the peer in routing table
	if(ePEER == m_msg.stcmn_hdr.porc){
	  m_pBRT->Insert(m_msg.stpeerinfo,1);
	  m_pBNT->Insert(m_msg.stpeerinfo,1);
	}

        //Set the keep-alive and update timers
	setPushPullTimer();
	setGlobalTuningTimer();
	setLocalTuningTimer();
	//Insert itself as a resource-object in its own
	//resource-object
	m_objRM.PublishUserInfo( (char*)m_USERID, strlen((char*)m_USERID), eUDP);
	//inform the application
	objLO.ritype = eBOOTSTRAP;
	objLO.pApp = m_pApp;
	if(appCallBack){
	  appCallBack( (void*)&objLO, 200);
	}
      }
      break;

    case eS_PTUPDATE:
      break;

    default:
      break;
    }//end switch
    break; //end join

  case ePCONNECTED:
    {
      switch(m_msg.stcmn_hdr.reqoritype) {

      case eEXCHANGETABLE:
	//this is equivalent to GET_LEAF_SET
	m_pBRT->Insert(m_msg.strt.table,1);
	m_pBNT->Insert(m_msg.strt.table,1);
	break;
        
      case ePUBLISHOBJECT:
	m_objRM.OnPublishObjectResponse(m_msg);
        break;
	
      case eLOOKUPPEER:
        m_objMH.OnLookupPeerResponse(m_msg);
      	m_pBRT->Insert(m_msg.stlpeerinfo,1);
	      m_pBNT->Insert(m_msg.stlpeerinfo,1);
        //Insert the peer in routing table
	if(ePEER == m_msg.stcmn_hdr.porc){
	  m_pBRT->Insert(m_msg.stpeerinfo,1);
	  m_pBNT->Insert(m_msg.stpeerinfo,1);
	}
	break;

      case eLOOKUPOBJECT:
        m_objRM.OnLookupObjectResponse(m_msg);
        
        //Insert the peer in routing table
	if(ePEER == m_msg.stcmn_hdr.porc){
	  m_pBRT->Insert(m_msg.stpeerinfo,1);
	  m_pBNT->Insert(m_msg.stpeerinfo,1);
        }
	break;

      case eGETDIAGNOSTICS:
	m_objMH.OnGetDiagnosticsResponse(m_msg);
	break;
        
      default:
	break;
      }//end switch
      
      break;
    }//case ePCONNECTED

  default:
    break;

  }//end switch

  return 1;

}//OnReponse

void BambooPeer::setPushPullTimer() {
  gettimeofday(&m_tPushPull, NULL);
  m_tPushPull = addtimeval(m_tPushPull, m_PushPull, 0);
}//setPushPullTimer

int32 BambooPeer::isPushPullExpired() {
  struct timeval cur, difft;
  gettimeofday(&cur, NULL);
  
  //difference between timer and current time
  difft = difftimeval(m_tPushPull, cur);

  if(0 == difft.tv_sec && 0==difft.tv_usec) {
    return 1;
  }
  
  return 0;
}//isPushPullExpired

void BambooPeer::setGlobalTuningTimer() {
  gettimeofday(&m_tGlobalTuning, NULL);
  m_tGlobalTuning = addtimeval(m_tGlobalTuning, m_GlobalTuning, 0);
}//setGlobalTuningTimer

int32 BambooPeer::isGlobalTuningExpired() {
  struct timeval cur, difft;
  gettimeofday(&cur, NULL);
  
  //difference between timer and current time
  difft = difftimeval(m_tGlobalTuning, cur);

  if(0 == difft.tv_sec && 0==difft.tv_usec) {
    return 1;
  }
  
  return 0;
}//isGlobalTuningExpired

void BambooPeer::setLocalTuningTimer() {
  gettimeofday(&m_tLocalTuning, NULL);
  m_tLocalTuning = addtimeval(m_tLocalTuning, m_LocalTuning, 0);
}//setLocalTuningTimer

int32 BambooPeer::isLocalTuningExpired() {
  struct timeval cur, difft;
  gettimeofday(&cur, NULL);
  
  //difference between timer and current time
  difft = difftimeval(m_tLocalTuning, cur);

  if(0 == difft.tv_sec && 0==difft.tv_usec) {
    return 1;
  }
  return 0;
}//isLocalTuningExpired


int32 BambooPeer::Insert(struct peerinfo& stP, int updateKA) {

  m_pBRT->Insert(stP, updateKA);
  m_pBNT->Insert(stP, updateKA);

  return 1;
}//Insert


int32 BambooPeer::Insert(list<peerinfo>& lstP, int updateKA) {
  m_pBRT->Insert(lstP, updateKA);
  m_pBNT->Insert(lstP, updateKA);
  return 1;
}//Insert


int32 BambooPeer::Insert(struct peerinfo& stP, int32 updateKA, uint16 stunPort) {
  //TODO: write code
  return 1;
}//Insert

void BambooPeer::ShowRT() {

  struct peerinfo stP;
  
  getSelfPeer(stP);

  printf("\n");
  printf("Node Id: 0x");
  
  for(int i=0; i<m_HASH_SIZE; i++) {
    printf("%x", m_ID[i]);
  }
  printf(" %s %d\n", stP.staddr.addr[0], stP.staddr.port[0]);
  printf("Routing Table\n");
  printf("-------------\n");

  m_pBRT->Show();

}//ShowRT

void BambooPeer::ShowNT() {
  struct peerinfo stP;
  
  getSelfPeer(stP);

  printf("\n");
  printf("Node Id: 0x");
  
  for(int i=0; i<m_HASH_SIZE; i++) {
    printf("%x", m_ID[i]);
  }
  printf(" %s %d\n", stP.staddr.addr[0], stP.staddr.port[0]);
  printf("Neighbour Table\n");
  printf("-------------\n");

  m_pBNT->Show();

  return;
}//ShowNT

void BambooPeer::ShowRO(){
  m_objRM.ShowRO();
  return;
}//ShowRO

/////////////////////////////////////////
//plookup CALLBACK for Global tuning
//////////////////////////////////////// 
void* GlobalTuningOnLookupPeer(void* pN, int32 respcode) {
  LObject *pLO=(LObject*)pN;

  if(respcode==200){
    BambooPeer *pNode=(BambooPeer*)pLO->pPeer;
    
    if(pNode){
      pNode->m_pRT->Insert(pNode->m_msg.stpeerinfo,1);
    }
  }
  return NULL;
}//GlobalTuningOnPlookup

int32 BambooPeer::GlobalTuning(int32 level, int32 digit, void* (*callback)(void*, int32)) {
  
  uchar pchHash[HASHLEN];
  int32 x=0,i=0;
  uchar t;

  TRACE(4, "BambooPeer::GlobalTuning...Begins\n", "");
  
  for( i=0;i<(level/8);++i){
    pchHash[i]=m_ID[i];
  }
  x=level%8;
  if(digit)
    pchHash[i]= m_ID[i] | (digit<<(8-1-x));
  else
    pchHash[i]= m_ID[i] ^ (digit<<(8-1-x));
  for(i=i;i<m_HASH_SIZE;i++){
    t = rand()%255;
    pchHash[i] = t;
  }
  
  m_objMH.LookupPeer((char8*)pchHash,m_HASH_SIZE, eUDP, callback,NULL);

  return 1;
}//GlobalTuning
/*
void BambooPeer::UpdateRelayList(const list< struct peerinfo> lstP){
  m_objSTI.UpdateRelayList(lstP);
}

*/


