/*
 * 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 "kadrtable.h"

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

#ifdef _WENGO
#include "p2pp/common/trace.h"
#include "p2pp/node/peer.h"
#endif

#include <math.h>

#define BUCKETSIZE 5

KadRTable::KadRTable() {

  struct timeval curr_time;

  m_iSize = 0;

  //Timers
  m_BT=30;
  m_KArand=90;  //keep-alive timer
  m_RTrand=60;  //routing-table exchange timer
  m_CTrand=60;  //consistency timer

  gettimeofday(&curr_time, NULL);
  srand(curr_time.tv_sec+curr_time.tv_usec);

  setRTTimer(m_expRT);
  setCTTimer(m_expCT);
}//KadRTable


KadRTable::~KadRTable() {
  
}//~KadRTable


uint32 KadRTable::getSize() {
  return m_iSize;
}//getTotalNum



void KadRTable::setKATimer(struct timeval& kat) {
  uint32 temp;
  uint32 myrand;

  //update the keep-alive timer
  gettimeofday(&kat, NULL);

  myrand = rand();
  temp = (m_BT + myrand%m_KArand);

  kat = addtimeval(kat, temp, 0);

}//setKATimer



void KadRTable::setRTTimer(struct timeval& rttimer) {
  gettimeofday(&rttimer, NULL);
  rttimer = addtimeval(rttimer, m_BT + rand()%m_RTrand, 0);
}//setRTTimer


void KadRTable::setCTTimer(struct timeval& rttimer) {
  gettimeofday(&rttimer, NULL);
  rttimer = addtimeval(rttimer, m_BT + rand()%m_CTrand, 0);
  //rttimer = addtimeval(rttimer, 15, 0);
}//setRTTimer


int32 KadRTable::isTimerExpired(const struct timeval& rtimer) {
  struct timeval diff_time, cur_time;
  
  gettimeofday(&cur_time, NULL);

  diff_time = difftimeval(rtimer, cur_time);


  if(0 == diff_time.tv_sec && 0 == diff_time.tv_usec) {
    return 1;
  }

  return 0;
}//isTimerExpired


void KadRTable::setNodeId(uchar* peerid, int32 len, int32 base) {
  
  BigInt b;
  struct Internalpeerinfo p;
  list<Internalpeerinfo> listP;
  int32 temp;

  //set hash size in bytes
  m_HASH_SIZE = len;

  //Base
  m_BASE = base;
  
  //create the bigint out of peerid
  uchar_to_bigint(peerid, len, m_NodeId);

  //Initialize the distance function with base, Id, and hashlen
  m_KadDist.setParams(base, len*8);
  m_KadDist.setKey(m_NodeId);
  
  
  //Now create the routing table
  temp =  (int32)((float)log((float)m_BASE) / (float)log((float)2));
  for(int i=0; i<(len*8/temp); i++) {
    m_KadDist.getKeyAt(i, b);

    m_RT[b] = listP;
  }
  
  //Create a max bigint
  for(int i=0;i<(int)m_HASH_SIZE*8;i++) {
    m_Max.setBitAt(i,1);
  }
  
  //Initialize size
  m_iSize = 0;
  
}//setNodeId



uint32 KadRTable::getNextHop(BigInt, peerinfo&) {

  return 1;
}//getNextHop



/**
   0 this is the hop
   1 check peerinfo for next hop
   2 error
 */
uint32 KadRTable::getNextHop(uchar* peerid, uint32 len, struct peerinfo& stP) {
  BigInt bpeerid, max, result, lpeerid, result1, res2;
  map<BigInt, list<Internalpeerinfo> >::iterator mitr;
  list<Internalpeerinfo>::iterator litr;
  int32 isPresent = 0;
  int32 flag = 0;
  
  //set the distance to a high value
  max=m_Max;

  //create the bigint out of peerid
  uchar_to_bigint(peerid, len, bpeerid);

  //If peerid is the same as our ID
  //We are the hop. This message is received for LookupPeer (consistency check)
  if(bpeerid == m_NodeId) {
    return 0;
  }


  ///////////////////////////////////////////////////
  // CODE to optimize routing table lookup
  ///////////////////////////////////////////////////
  //Find the first non-zero bit in res2 and flip it
  uint32 b1, b2, flag1=0;
  for(int32 j= (m_HASH_SIZE*8-1); j>=0; j--) {
    bpeerid.getBitAt(j, b1);
    m_NodeId.getBitAt(j, b2);
    
    if(0 == flag1) {
      if(b1 != b2) {
	res2.setBitAt(j, b1);
	flag1=1;
      } else {
	res2.setBitAt(j, b2);
      }
    } else {
      res2.setBitAt(j,b2);
    }
  }//end for


  //Find the Id in our routing table
  mitr = m_RT.find(res2);

  if(mitr == m_RT.end() ) {
    cout<<m_NodeId.ToHex()<<endl;
    cout<<bpeerid.ToHex()<<endl;

    printf("getNextHop Error\n");
    return 2;
  }


  //Check if there are existing entries in this row
  //If not, set the iterator to the beginning of the routing table
  if(mitr->second.size() == 0) {
    flag=0;
    mitr = m_RT.begin();
  } else {
    flag=1;
  }


  //iterate over the routing table. the initilization iterator is set before
  for(; mitr!=m_RT.end(); mitr++) {
    
    //iterate over all peers in this row
    for(litr=mitr->second.begin(); litr!=mitr->second.end(); litr++) {

      //Calculate the Kad distance
      m_KadDist.getDistance(litr->ID, bpeerid, result);

      if(result < max) {
        isPresent = 1;
        
        //set the peer info structure
        stP = litr->m_stP; 
        
        //update the max
        max = result;
      }
    }//end list for
    
    //We have searched the correct row. break.
    if(1==flag) {
      break;
    }

  }//end for
  
  
  //Now calculate the distance between myself and the peerid
  m_KadDist.getDistance(bpeerid, m_NodeId, result1);


  if(0 == isPresent)
    return 0;

  if(result1 > max) {
    //we are not the hop
    return 1;
  } else {
    //we are the hop
    return 0;
  }

  return isPresent;

}//getNextHop


/*
  1 if peer is found
  0 otherwise
*/

int32 KadRTable::getAt(int32 index, struct peerinfo& stP) {
  
  map<BigInt, list<Internalpeerinfo> >::iterator mitr;
  list<Internalpeerinfo>::iterator litr;
  int i=0;

  //iterate over the routing table
  for(mitr=m_RT.begin(); mitr!=m_RT.end(); mitr++) {
    
    //iterate over all peers in this row
    for(litr=mitr->second.begin(); litr!=mitr->second.end(); litr++) {

      //found item. return it immediately      
      if(index == i) {
        stP = litr->m_stP;
        return 1;
      }
      
      i++;
    }//end for
    
  }//end for
  
  return 0;
}//getAt


/*
 * Inserts a list of peerinfo objects in routing table
 */

int32 KadRTable::Insert(list<peerinfo>& lstP, int32 updateKA) {
  list<peerinfo>::iterator itr;
  
  for(itr=lstP.begin(); itr!=lstP.end(); itr++) {    
    Insert(*itr, updateKA);
  }//end for
  
  return 1;
}//Insert


/*
 *2 if already exists
 *1 if does not exist
 *0 if error
 */
int32 KadRTable::FindInsertItr(struct peerinfo& stP, map<BigInt, list<Internalpeerinfo> >::iterator& itr, 
                               list<Internalpeerinfo>::iterator& litr,
                               int32 updateKA, struct Internalpeerinfo& stIP) {
  
  map<BigInt, list<Internalpeerinfo> >::iterator mitr;
  list<Internalpeerinfo>::iterator eitr;
  BigInt b, result, max, bindex, lpeerid, res1, res2, res3;  
  int32 len;
  struct timeval curr_time;
  uint32 bucket = BUCKETSIZE;
  
  //The length of hash function in bytes
  len = m_HASH_SIZE;

  //create the bigint out of peerid
  uchar_to_bigint(stP.stpeerid.id, len, b);

  if(m_NodeId == b) {
    TRACE(1, "KadRTable::FindInsertItr...Cannot insert itself\n", "");
    return 0;
  }

  //current time
  gettimeofday(&curr_time, NULL);

  ///////////////////////////////////////////////////
  // CODE to optimize routing table lookup
  ///////////////////////////////////////////////////
  //Find the first non-zero bit in res2 and flip it
  uint32 b1, b2, flag=0;
  for(int32 j= (m_HASH_SIZE*8-1); j>=0; j--) {
    b.getBitAt(j, b1);
    m_NodeId.getBitAt(j, b2);
    
    if(0 == flag) {
      if(b1 != b2) {
        res2.setBitAt(j, b1);
        flag=1;
      } else {
        res2.setBitAt(j, b2);
      }
    } else {
      res2.setBitAt(j,b2);
    }
  }//end for

  //Find the Id in our routing table
  mitr = m_RT.find(res2);

  if(mitr == m_RT.end() ) {
    printf("Route Insertion Error\n");
    return 0;
  }


  //get the distance between row-Id and the node-Id which maybe inserted in this row
  m_KadDist.getDistance( res2, (BigInt&)mitr->first, res3);

  //set the list iterator to the end of the list in this routing-table row
  eitr = mitr->second.end();

  //max
  max = 0;

  //iterate over the peers in this row
  for(litr=mitr->second.begin(); litr!=mitr->second.end(); litr++) {

    if(litr->ID == b) {
      TRACE(1, "KadRTable::FindInsertItr...id already present...updating keepalive timer\n", "");
	
      //update keep-alive timer?
      if(1 == updateKA) {
        //update the keep-alive timer
        setKATimer(litr->m_expKA);
      }

      //update last seen timer
      litr->m_lastseen = curr_time;

      return 2;
    }

    //Compare ID of every node in this row with the row ID and calculate the distance
    //Store the largest distance
    m_KadDist.getDistance( (BigInt&)mitr->first, litr->ID, result);
    if(result > max) {
      eitr = litr;
      max = result;
    }

  }//end list for


  //Now insert in the routing table
  itr = mitr;

  //copy the peerinfo structure
  if(stP.strtt.isPresent){
    stIP.m_tRTT.tv_usec=stP.strtt.utime*1000;
    stIP.m_tRTT.tv_sec=0;
    stP.isPresent=0;
  }
  stIP.m_stP = stP;
  stIP.m_tLastSent=curr_time;

  //the time this node was seen
  stIP.m_lastseen = curr_time;

  //BigInt ID
  len = m_HASH_SIZE;
  uchar_to_bigint(stP.stpeerid.id, len, stIP.ID);

  //set the keepalive, exchange table, and consistency timer
  setKATimer(stIP.m_expKA);
  //setRTTimer(m_expRT);  // this is a global timer
  //setCTTimer(m_expCT);

    
  //BUCKET SIZE is bucket = BUCKETSIZE
  if(itr->second.size() < bucket) { 
    TRACE(1, "KadRTable::FindInsertItr...can insert: %s port: %d\n", stP.staddr.addr[0], stP.staddr.port[0]);

    //DONE in appropriate insert function
    //itr->second.push_back(stIP);

    //Increment the number of elements
    m_iSize++;
  } else if(itr->second.size() == bucket) {

    //If distance between new node ID and row-ID is smaller than the largest distance between
    //row-ID and the IDs of all nodes in this row, remove the peer with largest ID and insert
    //this new node-ID

    if(max > res3 && eitr != itr->second.end() ) {
      TRACE(1, "KadRTable::FindInsertItr...can insert: %s port: %d == 5\n", stP.staddr.addr[0], stP.staddr.port[0]);
      itr->second.erase(eitr);

      //DONE in appropriate insert function
      //itr->second.push_back(stIP);
    } else {
      TRACE(1, "KadRTable::FindInsertItr...max>res3 cannot insert: %s port: %d RT size: \n", stP.staddr.addr[0], stP.staddr.port[0], itr->second.size() );
      return 0;
    }

  } else {    
    TRACE(1, "KadRTable::FindInsertItr...cannot insert: %s port: %d RT size: \n", stP.staddr.addr[0], stP.staddr.port[0], itr->second.size() );
    return 0;
  }

  return 1;
}//FindInsertItr


/*
  1 successful
  0 already present
*/

int32 KadRTable::Insert(struct peerinfo& stP, int32 updateKA) {
  map<BigInt, list<Internalpeerinfo> >::iterator itr;
  list<Internalpeerinfo>::iterator litr;
  struct Internalpeerinfo stIP;
  int32 ret;

  ret=FindInsertItr(stP, itr, litr, updateKA, stIP);
  if(1 == ret) {
    TRACE(1, "KadRTable::Insert...successful insert: %s port: %d\n", stP.staddr.addr[0], stP.staddr.port[0]);
    itr->second.push_back(stIP);
  } 
 
  return ret;
}//Insert


int32 KadRTable::Insert(struct peerinfo& stP, int32 updateKA, uint16 stunPort) {
  map<BigInt, list<Internalpeerinfo> >::iterator itr;
  list<Internalpeerinfo>::iterator litr;
  struct Internalpeerinfo stIP;
  int32 ret;

  ret=FindInsertItr(stP, itr, litr, updateKA, stIP);

  //printf("RET is: %d\n", ret);

  if(1 == ret) {
    stIP.m_iStunPort = stunPort;

    TRACE(1, "KadRTable::Insert...successful insert: %s port: %d stunport: %d\n", stP.staddr.addr[0], stP.staddr.port[0], stunPort);
    itr->second.push_back(stIP);
  } else if(2== ret) {
    //update stun port

    //printf("update stun port: %d\n", stunPort);
    litr->m_iStunPort=stunPort;
  }//end else
 
  return ret;
}//Insert


int32 KadRTable::getTable(list<peerinfo>& lstP) {

  map<BigInt, list<Internalpeerinfo> >::iterator mitr, itr;
  list<Internalpeerinfo>::iterator litr;
  int i=0;

  for(mitr=m_RT.begin(); mitr!=m_RT.end(); mitr++) {
    
    //iterate over all peers in this row
    for(litr=mitr->second.begin(); litr!=mitr->second.end(); litr++) {
      
      litr->m_stP.isPresent=1;

      if( !(litr->m_tRTT.tv_sec == 0 && litr->m_tRTT.tv_usec == 0) ) {

	//TEMP COMMENT
	//litr->m_stP.strtt.isPresent=1;
	//calculate the number of ms
	litr->m_stP.strtt.isPresent=1;
	litr->m_stP.strtt.utime = litr->m_tRTT.tv_sec*1000 + litr->m_tRTT.tv_usec / 1000;
      }

      lstP.push_back(litr->m_stP);
      i++;

      //remove RTT from peerinfo. Not needed everywhere
      litr->m_stP.strtt.isPresent = 0;

    }//end list for
  }//end for

  return i;
  
}//getTable


int32 KadRTable::getTable(list<peerinfo>& lstP, enum transtype tt) {

  map<BigInt, list<Internalpeerinfo> >::iterator mitr;
  list<Internalpeerinfo>::iterator litr;

  struct peerinfo lstpeer;
  int count=0, i, c;
  int flag[1000]={0};
  int rSize=0;
  struct timeval curr_time;
  int32 num;

  //Flag to indicate whether we need to include all entries or only part 
  //of them. If UDP only include part of it
  if(eUDP == tt) rSize = 25; else rSize = m_iSize;
  
  //The total number of entries in routing tables
  num = m_iSize; if(m_iSize>1000) num=1000;

  
  //TEMP CODE BEGINS
  //set the seed
  gettimeofday(&curr_time, NULL);
  srand(curr_time.tv_sec+curr_time.tv_usec);

  //set the array to 0 or 1 depending on isAll flag
  for(i=0; i<1000; i++) {
    if(eUDP == tt) {
      flag[i] = 0;
    } else if(eTCP == tt) {
      flag[i] = 1;
    }
  }


  //Create an array with flags set to 1 or 0 randomly.
  //0 indicates that it should not be included and 1 indicates that it should be included.
  count=1;
  c=0;

  if(eUDP == tt) {
    for(int i=0; i<1000 && count <= rSize; i++) {

      //include random entries if we have more than rSize entries
      //and the transport is UDP
      if(num > rSize) {
	do {
	  c = (int) (rand() % num);
	} while (flag[c] != 0);
      } else {
	c=count-1;
      }
      
      flag[c]=1;
      count++;
    }//end for    
  }
  //random array creation ends

  i=0;
  for(mitr=m_RT.begin(); mitr!=m_RT.end(); mitr++) {
    
    //iterate over all peers in this row
    for(litr=mitr->second.begin(); litr!=mitr->second.end(); litr++) {
      
      litr->m_stP.isPresent=1;

      //FIXME: add last seen timer
      if(1 == flag[i]) {
	
	if( !(litr->m_tRTT.tv_sec == 0 && litr->m_tRTT.tv_usec == 0) ) {
	  //TEMP comment
	  //litr->m_stP.strtt.isPresent=1;
	  //calculate the number of ms
	  litr->m_stP.strtt.isPresent=1;
	  litr->m_stP.strtt.utime = litr->m_tRTT.tv_sec*1000 + litr->m_tRTT.tv_usec / 1000;
	}
	
	lstP.push_back(litr->m_stP);	

	//remove RTT from map
	litr->m_stP.strtt.isPresent = 0;
      }

      //increment the number of entries inserted
      i++;

    }//end list for
  }//end for

  return i;
  
}//getTable





int32 KadRTable::routingConsistency() {
  
  map<BigInt, list<Internalpeerinfo> >::iterator mitr, itr;
  list<Internalpeerinfo>::iterator litr;
  int i=0;
  struct LObject objLO;
  string strtransid;

  objLO.stpl.num=1;
  

  TRACE(3, "KadRTable::routingConsistency...begins\n", "");

  for(mitr=m_RT.begin(); mitr!=m_RT.end() && i<2; mitr++) {
    
    //iterate over all peers in this row
    for(litr=mitr->second.begin(); litr!=mitr->second.end(); litr++) {
      
      litr->m_stP.isPresent=1;

      //Send lookup peer for this peer
      m_pPeer->ComposeLookupPeer(litr->m_stP,objLO,strtransid);
      
      i++;

      //If LookupPeer was sent to two peers break.
      if(2==i) {
        break;
      }

    }//end list for
    
  }//end for
  
  
  return 1;
}//routingConsistency



int32 KadRTable::RemovePeer(char8* pchIP, uint32 port) {

  map<BigInt, list<Internalpeerinfo> >::iterator mitr, itr;
  list<Internalpeerinfo>::iterator litr;

  for(mitr=m_RT.begin(); mitr!=m_RT.end(); mitr++) {
    
    //iterate over all peers in this row
    for(litr=mitr->second.begin(); litr!=mitr->second.end(); litr++) {

      for(int i=0; i<litr->m_stP.staddr.num && litr->m_stP.staddr.isPresent; i++) {
        if(0 == strcmp(litr->m_stP.staddr.addr[i], pchIP) && port == litr->m_stP.staddr.port[i]) {
          //remove the peer from routing table
          TRACE(1, "KadRTable::RemovePeer...removing peer: %s %d\n", pchIP, port);
          
          //remove the peer from the list 
          mitr->second.erase(litr);

          //Decrement the number of elements
          m_iSize--;
          return 1;                     
        }
      }//end address for

    }//end list for    
  }//end for

  return 0;
}//RemovePeer


/*
 * Every 30+[0-90]s, we get routing table of a random node in our routing table
 */

int32 KadRTable::OnTimer() {

  map<BigInt, list<Internalpeerinfo> >::iterator mitr;
  list<Internalpeerinfo>::iterator litr;
  int32 i, index;

  //generate the entry to which exchange table should be sent
  index=rand()%(m_iSize+1);
  i=1;

  //iterate over the routing table
  for(mitr=m_RT.begin(); mitr!=m_RT.end(); mitr++) {
    
    //iterate over all peers in this row
    for(litr=mitr->second.begin(); litr!=mitr->second.end(); litr++) {
      
      //Check if exchange table timer expired
      if( i == index && isTimerExpired(m_expRT) ) {

        TRACE(3, "KadRTable::OnTimer...exchange table expired\n", "");
        if(!(litr->m_tRTT.tv_sec==0 &&litr->m_tRTT.tv_usec==0)){
          litr->m_stP.strtt.isPresent=1;
          litr->m_stP.strtt.utime=litr->m_tRTT.tv_sec*1000 + litr->m_tRTT.tv_usec / 1000;
        }
        m_pPeer->ComposeExchangeTable(litr->m_stP);
        litr->m_stP.strtt.isPresent=0;

        gettimeofday(&(litr->m_tLastSent), NULL);

        //update exchange table timer
        setRTTimer(m_expRT);
	
      } else if( isTimerExpired(litr->m_expKA) ) {        
        TRACE(3, "KadRTable::OnTimer...keep-alive timer expired\n", "");
        //Check if KA timer expired
        if(!(litr->m_tRTT.tv_sec==0 && litr->m_tRTT.tv_usec==0)){
          litr->m_stP.strtt.utime=litr->m_tRTT.tv_sec*1000 + litr->m_tRTT.tv_usec / 1000;
          litr->m_stP.strtt.isPresent=1;
        }
        m_pPeer->ComposeKeepAlive(litr->m_stP);
        litr->m_stP.strtt.isPresent=0;

        gettimeofday(&(litr->m_tLastSent), NULL);

        //update KA timer
        setKATimer(litr->m_expKA);

      } else if( isTimerExpired(m_expCT) ) {
        TRACE(3, "KadRTable::OnTimer...consistency timer expired\n", "");
        routingConsistency();

        setCTTimer(m_expCT);

      } else {

        //If we do not have the stun/turn port, get it now.        
        if(0==litr->m_iStunPort) {
          //printf("GET STUN PORT\n");
	  //FIXME: this was happening too often. fix it.
          //gettimeofday(&(litr->m_tLastSent), NULL);

          //if we do not have the stun/turn port of the peer, get it
          //m_pPeer->m_objRM.LookupStunPort(litr->m_stP, eUDP);
        }//end if

      }//end else

      i++;

    }//end for
    
  }//end for


  return 1;
}//OnTimer


/*
 * 1 It is us or we have this node in our routing table
 * 0 we do not have this node in our routing table
 */

int32 KadRTable::Find(struct peerinfo& stP) {

  map<BigInt, list<Internalpeerinfo> >::iterator mitr, itr;
  list<Internalpeerinfo>::iterator litr, eitr;
  BigInt b, result, bindex, lpeerid, res1, res2, res3;
  int32 len;
  
  //The length of hash function in bytes
  len = m_HASH_SIZE;

  //create the bigint out of peerid
  uchar_to_bigint(stP.stpeerid.id, len, b);

  if(m_NodeId == b) {
    TRACE(1, "KadRTable::Find...we are the node\n", "");
    return 1;
  }  
  
  ///////////////////////////////////////////////////
  // CODE to optimize routing table lookup
  ///////////////////////////////////////////////////
  //Find the first non-zero bit in res2 and flip it
  uint32 b1, b2, flag=0;
  for(int32 j= (m_HASH_SIZE*8-1); j>=0; j--) {
    b.getBitAt(j, b1);
    m_NodeId.getBitAt(j, b2);
    
    if(0 == flag) {
      if(b1 != b2) {
	res2.setBitAt(j, b1);
	flag=1;
      } else {
	res2.setBitAt(j, b2);
      }
    } else {
      res2.setBitAt(j,b2);
    }
  }//end for

  //Find the Id in our routing table
  mitr = m_RT.find(res2);

  if(mitr == m_RT.end() ) {
    printf("Find Error\n");
    return 0;
  }


  //get the distance between row-Id and the node-Id which maybe inserted in this row
  m_KadDist.getDistance( res2, (BigInt&)mitr->first, res3);

  //set the list iterator to the end of the list in this routing-table row
  eitr = mitr->second.end();
  
  //iterate over the peers in this row
  for(litr=mitr->second.begin(); litr!=mitr->second.end(); litr++) {

    if(litr->ID == b) {      
      return 1;
    }
  }//end list for


  return 0;
}//Find






/*
 * 1 It is us or we have this node in our routing table
 * 0 we do not have this node in our routing table
 */

int32 KadRTable::RemoveId(uchar* myid, uint32 myidlen) {

  map<BigInt, list<Internalpeerinfo> >::iterator mitr, itr;
  list<Internalpeerinfo>::iterator litr, eitr;
  BigInt b, result, bindex, lpeerid, res1, res2, res3;
  int32 len;
  
  //The length of hash function in bytes
  len = m_HASH_SIZE;

  //create the bigint out of peerid
  uchar_to_bigint(myid, len, b);

  if(m_NodeId == b) {
    TRACE(1, "KadRTable::Remove...we are the node\n", "");
    return 1;
  }  
  
  ///////////////////////////////////////////////////
  // CODE to optimize routing table lookup
  ///////////////////////////////////////////////////
  //Find the first non-zero bit in res2 and flip it
  uint32 b1, b2, flag=0;
  for(int32 j= (m_HASH_SIZE*8-1); j>=0; j--) {
    b.getBitAt(j, b1);
    m_NodeId.getBitAt(j, b2);
    
    if(0 == flag) {
      if(b1 != b2) {
	res2.setBitAt(j, b1);
	flag=1;
      } else {
	res2.setBitAt(j, b2);
      }
    } else {
      res2.setBitAt(j,b2);
    }
  }//end for

  //Find the Id in our routing table
  mitr = m_RT.find(res2);

  if(mitr == m_RT.end() ) {
    printf("Remove Error\n");
    return 0;
  }


  //get the distance between row-Id and the node-Id which maybe inserted in this row
  m_KadDist.getDistance( res2, (BigInt&)mitr->first, res3);

  //set the list iterator to the end of the list in this routing-table row
  eitr = mitr->second.end();
  
  //iterate over the peers in this row
  for(litr=mitr->second.begin(); litr!=mitr->second.end(); litr++) {

    if(litr->ID == b) {
      //remove it from the table
      mitr->second.erase(litr);
      return 1;
    }
  }//end list for


  return 0;
}//RemovePeer






int32 KadRTable::OnExchangeTable(list<peerinfo>& lstP) {

  list<peerinfo>::iterator itr;
  int32 ret=0;

  for(itr=lstP.begin(); itr!=lstP.end(); itr++) {    
    ret = Find(*itr);
    if(0 == ret) {
      //send keep-alive      
      //Insert((*itr), 0);
      m_pPeer->ComposeKeepAlive( (*itr) );
    } else {
    }
  }//end for  

  return 1;
}//OnExchangeTable


void KadRTable::Show() {

  map<BigInt, list<Internalpeerinfo> >::iterator mitr;
  list<Internalpeerinfo>::iterator litr;
  BigInt b, result, max, bindex, lpeerid;
  int32 len;
  int32 base;
  struct timeval curr_time, diff_time, diffKA_time, diffET_time;

  len = m_HASH_SIZE;

  base=(int32) ((float)log((float)m_BASE) / (float)log((float)2));

  printf("Total entries: %d Total rows: %d\n", m_iSize, len*8/base);

  //current time
  gettimeofday(&curr_time, NULL);

  //difftime
  diffET_time = difftimeval(m_expRT, curr_time);
  printf("Exchange table timer: %u\n", (uint32)diffET_time.tv_sec);

  //Now create the routing table
  for(int i=0; i<(len*8/base); i++) {
    m_KadDist.getKeyAt(i, b);    

    //find b
    mitr = m_RT.find(b);
    
    cout<<"("<<i<<") 0x"<<mitr->first.ToHex()<<"\t"<<"|";

    //Check if there is already an entry. Sign of sum bug if already present
    //iterate over all peers in this row
    for(litr=mitr->second.begin(); litr!=mitr->second.end(); litr++) {
      
      //create the bigint out of peerid
      uchar_to_bigint(litr->m_stP.stpeerid.id, len, lpeerid);
      
      cout<<endl<<"   "<<"0x"<<lpeerid.ToHex()<<" ";

      //calculate the time this node was last seen
      diff_time = difftimeval(curr_time, litr->m_lastseen);
      diffKA_time = difftimeval(litr->m_expKA, curr_time);

      for(int j=0; j<litr->m_stP.staddr.num; j++) {
        cout<<"("<<litr->m_stP.staddr.addr[0]<<" "<<litr->m_stP.staddr.port[0]<<" stun: "<<litr->m_iStunPort <<") ";
        printf("LS: %us KA: %us", (uint32)diff_time.tv_sec, (uint32)diffKA_time.tv_sec);

        //if RTT is present
        printf(" RTT: %u ms ", (uint32)(litr->m_tRTT.tv_sec*1000 + (uint32)(litr->m_tRTT.tv_usec / 1000)) );	
      }
      cout<<";";
      
    }//end for

    printf("\n");
  }//end for

}//Show


void KadRTable::Disconnect() {
  map<BigInt, list<Internalpeerinfo> >::iterator mitr;
  list<Internalpeerinfo>::iterator litr;


  for(mitr=m_RT.begin(); mitr!=m_RT.end(); mitr++) {    
    //remove all entries in the row
    mitr->second.clear();    
  }//end for
  
  //Now remove the entries in table
  m_RT.clear();

}//Disconnect

void KadRTable::updateRTT(const struct peerinfo& stP){

  map<BigInt, list<Internalpeerinfo> >::iterator mitr, itr;
  list<Internalpeerinfo>::iterator litr, eitr;
  BigInt b, result, bindex, lpeerid, res1, res2, res3;
  int32 len;
  struct timeval currtime;

  //The length of hash function in bytes
  len = m_HASH_SIZE;

  //create the bigint out of peerid
  uchar_to_bigint((unsigned char*)stP.stpeerid.id, len, b);

  if(m_NodeId == b) {
    TRACE(1, "KadRTable::updateRTT...we are the node\n", "");
    return;
  }  
  
  ///////////////////////////////////////////////////
  // CODE to optimize routing table lookup
  ///////////////////////////////////////////////////
  //Find the first non-zero bit in res2 and flip it
  uint32 b1, b2, flag=0;
  for(int32 j= (m_HASH_SIZE*8-1); j>=0; j--) {
    b.getBitAt(j, b1);
    m_NodeId.getBitAt(j, b2);
    
    if(0 == flag) {
      if(b1 != b2) {
        res2.setBitAt(j, b1);
        flag=1;
      } else {
        res2.setBitAt(j, b2);
      }
    } else {
      res2.setBitAt(j,b2);
    }
  }//end for

  //Find the Id in our routing table
  mitr = m_RT.find(res2);

  if(mitr == m_RT.end() ) {
    printf("updateRTT Error\n");
    return;
  }


  //get the distance between row-Id and the node-Id which maybe inserted in this row
  //m_KadDist.getDistance( res2, (BigInt&)mitr->first, res3);

  //set the list iterator to the end of the list in this routing-table row
  //eitr = mitr->second.end();
  
  //iterate over the peers in this row
  for(litr=mitr->second.begin(); litr!=mitr->second.end(); litr++) {

    if(litr->ID == b) {      
      if(stP.strtt.isPresent){
        litr->m_tRTT.tv_sec=0;
        litr->m_tRTT.tv_usec=1000*stP.strtt.utime;
      } else {
        gettimeofday(&currtime, NULL);
        litr->m_tRTT = difftimeval(currtime, litr->m_tLastSent);
      }
      return;
    }
  }//end list for

}
