
#include "peer.h"
#include "rmanager.h"

#ifndef _WENGO
#include "genhash.h"
#include "trace.h"
#include "gettimeofday.h"
#endif

#ifdef _WENGO
#include "p2pp/utils/genhash.h"
#include "p2pp/common/trace.h"
#include "p2pp/sys/gettimeofday.h"
#endif

#define DEFAULT_STUN_SERVER_PORT 3478

LObject::LObject() {
  pApp = 0;
  callback = 0;
  strKey = "";

  isOrig = 0;
  
}//LObject


LObject::~LObject() {

  
}//LObject



RManager::RManager() {
  
  
}//RManager



RManager::~RManager() {
  
}//~RManager



void RManager::setParams(Peer* pPeer) {
  
  m_pPeer = pPeer;
  
}//setParams



int32 RManager::findLocal(struct LObject& objLO) {

  map<string, IRO1>::iterator i1;
  map<int32, IRO2>::iterator i2;
  map<string, IRO3, classcomp>::iterator i3;

  char8 temp[2*HASHLEN];
  string str, strowner;
  
  //resource-id
  uchar_to_hexstring(objLO.strl.stresid.id, m_pPeer->m_HASH_SIZE, temp);
  
  //resouce-id in a stl string
  str = temp;

  
  //Search in resource-table
  i1 = m_RT.find(str);
  if(i1 == m_RT.end() ) {
    TRACE(2, "RManager::findLocal...Res-ID not found RT size: %d\n", m_RT.size() );
    return 0;
  }
  
  
  //Search the type
  i2=i1->second.m_YMap.find(objLO.strl.conttype);
  if(i2 == i1->second.m_YMap.end() ) {
    TRACE(2, "RManager::findLocal... Type not found: %d YMap size: %d\n", objLO.strl.conttype, i1->second.m_YMap.size() );
    return 0;
  }//end if
  

  //Search the owner
  if(1==objLO.strl.stowner.isPresent) {
    //TODO
    TRACE(2, "RManager::findLocal...TODO owner is present\n", "");
    
  } else {

    TRACE(2, "RManager::findLocal...return all objects: %d\n", i2->second.m_OMap.size() );

    if(0 == i2->second.m_OMap.size() ) {
      return 0;
    }

    //since owner is not present, return all the objects
    for(i3=i2->second.m_OMap.begin(); i3!=i2->second.m_OMap.end(); i3++) {
      objLO.lstro.push_back(i3->second.stro);
      
    }//end for

  }//end else


  return 1;

}//findLocal



int32 RManager::LookupUser(char8* pchUser, int32 len, enum transtype tt, void* (*callback)(void*, int32), void* pApp) {

  struct peerinfo stNP;  //next peer
  LObject objLO;
  int32 ret, found;
  string strtransid;


  TRACE(4, "RManager::LookupUser...Begins for user: %s\n", pchUser);
  
  objLO.strKey = pchUser;
  objLO.callback = callback;
  objLO.pApp = pApp;
  objLO.isOrig = 1;
  objLO.ttl = 20;
  
  //transport type
  objLO.tt = tt;

  //get the self peerinfo
  m_pPeer->getSelfPeer(objLO.strl.stpeerinfo);

  //TODO: owner is peerinfo. We are searching, therefore we are the owner. 
  objLO.strl.stowner.isPresent=0;


  //BUILD THE RLOOKUP OBJECT
  //Compute the hash of the key and store it in rlookup object
  getHash((uchar*)pchUser, len, (uchar*)objLO.strl.stresid.id, m_pPeer->m_HASH_SIZE, m_pPeer->m_HASH_ALG);
  objLO.strl.stresid.isPresent=1;
  objLO.strl.stresid.stobj.length=idlen;
  //The resource type
  objLO.strl.conttype = eUSERINFO;
  objLO.strl.isPresent = 1;


  //Now the unhashed id
  strcpy( (char*)objLO.strl.stunhashedid.unhashed, (char*)pchUser );
  objLO.strl.stunhashedid.isPresent=1;
  objLO.strl.stunhashedid.stobj.length=strlen(pchUser);

  printf("UserLookup: unhashed-id: %s \n", pchUser);
  /*printf("UserLookup: unhashed: %s hash is: 0x", pchUser);
  for(int i=0; i<idlen; i++) {
    printf("%x", objLO.strl.stresid.id[i]);
  }
  printf("\n");  
  */
  gettimeofday(&objLO.senttime, NULL);

  
  //getNextHop
  ret=m_pPeer->getNextHop(objLO.strl.stresid.id, m_pPeer->m_HASH_SIZE, stNP );

  //check if we have the resource by any chance. search both in
  //resource table and replicated table
  found=findLocal(objLO);

 
  //We have the object. No need to send the request
  if(1 == found ) {
    TRACE(4, "RManager::LookupUser...we have the object...no need to send request\n", "");

    objLO.callback( (void*)(&objLO), 200);
    return 1;
  }

  //where to send
  if(0 == ret) {
    //TRACE(3, "ILHelper::Insert...We are the Insert Node. No need to send\n", "");
    
    printf( "LookupUser...Not found\n");
    //printf( "RManager::LookupUser...Looking at self...Not found\n");
    objLO.callback((void*)(&objLO), 404);

  } else {
    TRACE(3, "RManager::LookupUser...Send it to next node\n", "");
    //send the put message
    printf("To: %s:%d\n", stNP.staddr.addr[0], stNP.staddr.port[0]);
    m_pPeer->ComposeLookupObject(stNP, objLO, strtransid);
    m_IP[strtransid] = objLO;
  }

  TRACE(3, "RManager::LookupUser...ends\n", "");

  return 1;

}//LookupUser

int32 RManager::LookupSIP(char8* pchUser, int32 len, enum transtype tt, void* (*callback)(void*, int32), void* pApp) {

  struct peerinfo stNP;  //next peer
  LObject objLO;
  int32 ret, found;
  string strtransid;


  TRACE(4, "RManager::LookupSIP...Begins for user: %s\n", pchUser);
  
  objLO.strKey = pchUser;
  objLO.callback = callback;
  objLO.pApp = pApp;
  objLO.isOrig = 1;
  objLO.ttl = 20;
  
  //transport type
  objLO.tt = tt;

  //get the self peerinfo
  m_pPeer->getSelfPeer(objLO.strl.stpeerinfo);

  //TODO: owner is peerinfo. We are searching, therefore we are the owner. 
  objLO.strl.stowner.isPresent=0;


  //BUILD THE RLOOKUP OBJECT
  //Compute the hash of the key and store it in rlookup object
  getHash((uchar*)pchUser, len, (uchar*)objLO.strl.stresid.id, m_pPeer->m_HASH_SIZE, m_pPeer->m_HASH_ALG);
  objLO.strl.stresid.isPresent=1;
  objLO.strl.stresid.stobj.length=idlen;
  //The resource type
  objLO.strl.conttype = eSIP;
  objLO.strl.isPresent = 1;


  //Now the unhashed id
  strcpy( (char*)objLO.strl.stunhashedid.unhashed, (char*)pchUser );
  objLO.strl.stunhashedid.isPresent=1;
  objLO.strl.stunhashedid.stobj.length=strlen(pchUser);

  printf("SIPLookup: unhashed-id: %s \n", pchUser);
  gettimeofday(&objLO.senttime, NULL);

  
  //getNextHop
  ret=m_pPeer->getNextHop(objLO.strl.stresid.id, m_pPeer->m_HASH_SIZE, stNP );

  //check if we have the resource by any chance. search both in
  //resource table and replicated table
  found=findLocal(objLO);

 
  //We have the object. No need to send the request
  if(1 == found ) {
    TRACE(4, "RManager::LookupSIP...we have the object...no need to send request\n", "");

    objLO.callback( (void*)(&objLO), 200);
    return 1;
  }

  //where to send
  if(0 == ret) {
    //TRACE(3, "ILHelper::Insert...We are the Insert Node. No need to send\n", "");
    
    printf( "LookupSIP...Not found\n");
    //printf( "RManager::LookupSIP...Looking at self...Not found\n");
    objLO.callback((void*)(&objLO), 404);

  } else {
    TRACE(3, "RManager::LookupSIP...Send it to next node\n", "");
    //send the put message
    printf("To: %s:%d\n", stNP.staddr.addr[0], stNP.staddr.port[0]);
    m_pPeer->ComposeLookupObject(stNP, objLO, strtransid);
    m_IP[strtransid] = objLO;
  }

  TRACE(3, "RManager::LookupSIP...ends\n", "");

  return 1;

}//LookupSIP



int32 RManager::LookupObject(char8* pchKey, int32 len, enum transtype tt, void* (*callback)(void*, int32), void* pApp) {

  struct peerinfo stNP;  //next peer
  LObject objLO;
  int32 ret, found;
  string strtransid;


  TRACE(4, "RManager::LookupObject...Begins for user: %s\n", pchKey);
  
  objLO.strKey = pchKey;
  objLO.callback = callback;
  objLO.pApp = pApp;
  objLO.isOrig = 1;
  objLO.ttl = 20;
  
  //transport type
  objLO.tt = tt;

  //get the self peerinfo
  m_pPeer->getSelfPeer(objLO.strl.stpeerinfo);

  //TODO: owner is peerinfo. We are searching, therefore we are the owner. 
  objLO.strl.stowner.isPresent=0;


  //BUILD THE RLOOKUP OBJECT
  //Compute the hash of the key and store it in rlookup object
  getHash((uchar*)pchKey, len, (uchar*)objLO.strl.stresid.id, m_pPeer->m_HASH_SIZE, m_pPeer->m_HASH_ALG);
  objLO.strl.stresid.isPresent=1;
  objLO.strl.stresid.stobj.length=idlen;
  //The resource type
  objLO.strl.conttype = eSTRINGVAL;
  objLO.strl.isPresent = 1;


  //Now the unhashed id
  strcpy( (char*)objLO.strl.stunhashedid.unhashed, (char*)pchKey );
  objLO.strl.stunhashedid.isPresent=1;
  objLO.strl.stunhashedid.stobj.length=strlen(pchKey);

  printf("LookupObject: unhashed-id: %s \n", pchKey);
  /*printf("LookupObject: unhashed: %s hash is: 0x", pchKey);
  for(int i=0; i<idlen; i++) {
    printf("%x", objLO.strl.stresid.id[i]);
  }
  printf("\n");  
  */
  gettimeofday(&objLO.senttime, NULL);

  
  //getNextHop
  ret=m_pPeer->getNextHop(objLO.strl.stresid.id, m_pPeer->m_HASH_SIZE, stNP );

  //check if we have the resource by any chance? search both in
  //resource table and replicated table
  found=findLocal(objLO);

 
  //We have the object. No need to send the request
  if(1 == found ) {
    TRACE(4, "RManager::LookupObject...we have the object...no need to send request\n", "");

    objLO.callback( (void*)(&objLO), 200);
    return 1;
  }

  //where to send
  if(0 == ret) {
    //TRACE(3, "ILHelper::Insert...We are the Insert Node. No need to send\n", "");
    
    printf( "LookupObject...Not found\n");
    //printf( "RManager::LookupObject...Looking at self...Not found\n");
    objLO.callback((void*)(&objLO), 404);

  } else {
    TRACE(3, "RManager::LookupObject...Send it to next node\n", "");
    //send the put message
    printf("To: %s:%d\n", stNP.staddr.addr[0], stNP.staddr.port[0]);
    m_pPeer->ComposeLookupObject(stNP, objLO, strtransid);
    m_IP[strtransid] = objLO;
  }

  TRACE(3, "RManager::UserLookup...ends\n", "");

  return 1;

}//LookupObject


int32 RManager::LookupSTI(struct peerinfo& stNP, enum transtype tt) {
  struct LObject objLO;  
  string strtransid;

  TRACE(4, "RManager::LookupSTI...Begins for STUN\n", "");

  objLO.callback=NULL;
  objLO.isOrig=1;
  objLO.ttl=20;

  //transport type
  objLO.tt=tt;

  //get self peerinfo
  m_pPeer->getSelfPeer(objLO.strl.stpeerinfo);
  
  //TODO: owner is peerinfo, we are searching, therefore we are the owner
  objLO.strl.stowner.isPresent=0;

  
  //compute the hash of STUN and store in ID
  //  getHash((uchar*)"STUN", len, (uchar*)objLO.strl.stresid.id, m_pPeer->m_HASH_SIZE, m_pPeer->m_HASH_ALG);
  strncpy((char*)objLO.strl.stresid.id, "STUN",4);
  objLO.strl.stresid.isPresent=1;
  objLO.strl.stresid.stobj.length=4;
  
  //the resourse type
  objLO.strl.conttype=eSTUN_TURN_ICE;
  objLO.strl.isPresent=1;
  
  //Now the unhashed id
  /*
  strcpy( (char*)objLO.strl.stunhashedid.unhashed, "STUN" );
  objLO.strl.stunhashedid.isPresent=1;
  objLO.strl.stunhashedid.stobj.length=strlen("STUN");
  */

  TRACE(3, "RManager::LookupSTI...Send it to next node\n", "");
  //send the put message
  printf("To: %s:%d\n", stNP.staddr.addr[0], stNP.staddr.port[0]);
  m_pPeer->ComposeLookupObject(stNP, objLO, strtransid);
  m_IP[strtransid] = objLO;

  TRACE(3, "RManager::LookupSTI...ends\n", "");

  return 1;
  
}//RManager::LookupSTI



int32 RManager::LookupStunPort(struct peerinfo& stNP, enum transtype tt) {
  struct LObject objLO;  
  string strtransid;

  TRACE(4, "RManager::LookupStunPort...Begins for STUN\n", "");

  objLO.callback=NULL;
  objLO.isOrig=1;
  objLO.ttl=20;

  //transport type
  objLO.tt=tt;

  //get self peerinfo
  m_pPeer->getSelfPeer(objLO.strl.stpeerinfo);
  
  //TODO: owner is peerinfo, we are searching, therefore we are the owner
  objLO.strl.stowner.isPresent=0;

  
  //compute the hash of STUN and store in ID
  //  getHash((uchar*)"STUN", len, (uchar*)objLO.strl.stresid.id, m_pPeer->m_HASH_SIZE, m_pPeer->m_HASH_ALG);
  strncpy((char*)objLO.strl.stresid.id, "STUN",4);
  objLO.strl.stresid.isPresent=1;
  objLO.strl.stresid.stobj.length=4;
  
  //the resource type
  objLO.strl.conttype=eSTUN_PORT;
  objLO.strl.isPresent=1;
  

  TRACE(3, "RManager::LookupStunPort...Send it to next node\n", "");
  //send the put message
  //printf("To: %s:%d\n", stNP.staddr.addr[0], stNP.staddr.port[0]);
  m_pPeer->ComposeLookupObject(stNP, objLO, strtransid);
  m_IP[strtransid] = objLO;

  TRACE(3, "RManager::LookupStunPort...ends\n", "");

  return 1;
  
}//LookupStunPort



int32 RManager::OnLookupObjectRequest(struct message& msg, char* pchIP, int32 port, transtype tt) {

  struct LObject objLO;
  int32 found=0, ret;
  int32 respCode;
  struct peerinfo stNP, stPSelf;
  string strtransid;
  struct resourceobject ro;

  //RLookup not present return immediately  
  if(0 == msg.strl.isPresent) {
    TRACE(1, "RManager::OnLookupObjectRequest...RLookup not present\n", "");
    return 0;
  }

  //get self peer
  m_pPeer->getSelfPeer(stPSelf);

  //return stun port response
  if(eSTUN_PORT==msg.strl.conttype) {
    respCode=200;
    ro.conttype=eSTUN_PORT;
    ro.isPresent=1;
    ro.stresid.isPresent=1;
    strncpy((char*)ro.stresid.id, (char*)msg.strl.stresid.id, msg.strl.stresid.stobj.length);
    ro.stresid.stobj.length=msg.strl.stresid.stobj.length;
    ro.staddr.isPresent=1;
    ro.staddr.num=1;
    strncpy(ro.staddr.addr[0], stPSelf.staddr.addr[0],IPADDRLEN);
    ro.staddr.port[0]=m_pPeer->GetStunServerPort(); //DEFAULT_STUN_SERVER_PORT;
    ro.stpeerinfo=stPSelf;
    ro.stpeerinfo.isPresent=1;
    objLO.lstro.push_front(ro);
    //printf( "RManager::OnLookupObjectRequest...sending response %s:%d\n", ro.staddr.addr[0], ro.staddr.port[0]);
    TRACE(3, "RManager::OnLookupObjectRequest...sending response\n", "");
    m_pPeer->ComposeLookupObjectResp(respCode, stPSelf, stNP, pchIP, port, tt, objLO);    
    return 1;
  }
  
  //get the rlookup object
  objLO.strl = msg.strl;

  //Find the object in local tables. If found return 1 and store the
  //object in the resource-object list in objLO
  found=findLocal(objLO);

  //If not found
  if(0 == found) {
    
    //determine the next hop
    ret=m_pPeer->getNextHop(objLO.strl.stresid.id, m_pPeer->m_HASH_SIZE, stNP );

    //If we are the hop and we do not have the object then 404 else 302
    if(0 == ret) {
      respCode = 404;
    } else {
      respCode = 302;
    }

  } else {
    respCode = 200;
  }//end if
  

  //RECURSIVE vs ITERATIVE CODE

  //Send the response if iterative or 200
  if(0 == msg.stcmn_hdr.rori || 200 == respCode || 404 == respCode ) {

    TRACE(3, "RManager::OnLookupObjectRequest...sending response\n", "");
    m_pPeer->ComposeLookupObjectResp(respCode, stPSelf, stNP, pchIP, port, tt, objLO);    
    
  } else if(1 == msg.stcmn_hdr.rori && 302 == respCode) {

    printf("recursive request forwarding lookup object\n");
    
    //1) get a copy of the rlookup object
    //2) get the ip address, port and transport type on which the request
    //was received
    //3) create a new transaction
    //4) this is an inprogress transaction

    //1) 
    objLO.strl = msg.strl;
    
    //2)
    //recursive request
    objLO.pApp = 0;        //this null pointer indicates that we
                           //should send the response upstream instead
                           //of giving it to the application
    strcpy(objLO.pchIP, pchIP);
    objLO.port = port;
    objLO.tt = tt;
      
    //3)    
    m_pPeer->ComposeLookupObject(stNP, objLO, strtransid, msg, tt);

    //4)
    m_IP[strtransid] = objLO;
    
  }//end else


  return 1;

}//OnLookupObjectRequest



int32 RManager::OnLookupObjectResponse(struct message& msg) {

  map<string, LObject>::iterator i1;
  list<struct resourceobject>::iterator i2;

  list<peerinfo>::iterator litr;
  struct LObject objLO;
  string strtransid;
  struct peerinfo stNP;

  
  TRACE(2, "RManager::OnLookupObjectResponse...m_IP map size: %d\n", m_IP.size() );


  //Check if we have already processed this message
  i1=m_IP.find(msg.getTransId());
  if(i1 == m_IP.end() ) {
    TRACE(2, "RManager::OnLookupObjectResponse...response nothing in map_IL respcode: %d transID: %d\n", msg.stcmn_hdr.respcode, msg.stcmn_hdr.transid);
    return 0;
  } 

  //get a local copy of the stored LObject
  objLO = i1->second;
  
  //Now remove from the lookuptable map
  m_IP.erase(i1);
  
  
  //printf("LookupObject: %d response from %s %d\n", msg.stcmn_hdr.respcode, msg.stpeerinfo.staddr.addr[0], msg.stpeerinfo.staddr.port[0]);

  if(302 == msg.stcmn_hdr.respcode) {
    TRACE(2, "RManager::OnLookupObjectRequest...302 for RLookup...send RLookup\n", "");    

    //decrement TTL if TTL expired then return immediately. TTL is set to 20 for iterative
    objLO.ttl--;
    
    if(0 == objLO.ttl) {
      if( 0 != objLO.callback) {
        objLO.callback( (void*)&objLO, 400);
      }
      
      TRACE(2, "RManager::OnLookupObjectResponse...m_IP map size: %d...enough of TTL\n", m_IP.size() );
      
      //FIXME: Update Publish Timer here?
      return 0;
    }


    //if there is a list of peerinfo object
    if(msg.stlpeerinfo.size() > 0) {
      stNP= (*msg.stlpeerinfo.begin() );
   
      m_pPeer->ComposeLookupObject( stNP, objLO, strtransid);

      //Update the object in new map
      m_IP[strtransid] = objLO;
      
    } else {
      printf("Error in LookupObject response...There was no peerinfo object in 302\n");
    }    
    
    
  } else if(200 == msg.stcmn_hdr.respcode || 404 == msg.stcmn_hdr.respcode) {
    TRACE(2, "RManager::OnLookupObjectResponse...%d\n", msg.stcmn_hdr.respcode);
    

    //call the application callback function to inform about the response status
    //TEMP
    //if(0 != objLO.callback) {
    if(0 != objLO.callback) {

      if(200 == msg.stcmn_hdr.respcode) {      
        
        //copy the resource object and ready to pass to application
        for(i2=msg.lstro.begin(); i2 != msg.lstro.end(); i2++) {
          struct resourceobject stro;
          stro = *i2;

          //If request was for a STUN_PORT and addr was present, update
          //the port in routing table

          if(eSTUN_PORT==stro.conttype && 1==stro.staddr.isPresent) {
            m_pPeer->m_pRT->Insert(msg.stpeerinfo, 1, stro.staddr.port[0]);
          }//end if

          objLO.lstro.push_back(stro);
          
        }//end for
      }

      //copy the IP address and port which gave the reply
      strcpy(objLO.pchIP, msg.stpeerinfo.staddr.addr[0]);
      objLO.port=msg.stpeerinfo.staddr.port[0];

      objLO.callback( (void*)&objLO, msg.stcmn_hdr.respcode);
      
    } else {
        
      //If we had sent the request, but application did not call us
      if(1==objLO.isOrig) {
        //copy the resource object and ready to pass to application
        for(i2=msg.lstro.begin(); i2 != msg.lstro.end(); i2++) {
          struct resourceobject stro;
          stro = *i2;

          //If request was for a STUN_PORT and addr was present, update
          //the port in routing table          

          if(eSTUN_PORT==stro.conttype && 1==stro.staddr.isPresent) {
            //printf("INSERTING SALMAN stun: %d\n", stro.staddr.port[0]);
            m_pPeer->Insert(msg.stpeerinfo, 1, stro.staddr.port[0]);
          }//end if
          
        }//end for
      } else {

        TRACE(2, "RManager::OnLookupObjectResponse...sending response upstream\n", "");

        //RECURSIVE MODE: send the response upstream
        m_pPeer->ComposeLookupObjectResp(objLO.pchIP, objLO.port, objLO.tt, msg);
      }

    }//end else

  }//end

  return 1;
  
}//OnLookupObjectResponse




int32 RManager::InsertinRT(const LObject& objLO, struct timeval expt, const struct peerinfo& stP) {
  
  char8 temp[2*HASHLEN];
  struct IRO3 iro3;
  struct IRO2 iro2;
  struct IRO1 iro1;
  map<string, IRO1>::iterator i1;
  map<int32, IRO2>::iterator i2;
  map<string, IRO3, classcomp>::iterator i3;
  string strresid, strpeerid, strownerid;
  list<resourceobject>::iterator itr;
  list<resourceobject> lstro;

  TRACE(3, "RManager::InsertinRT...called for key: %s\n", (char*)objLO.stro.stunhashedid.unhashed );

  lstro=objLO.lstro;
  for(itr=lstro.begin(); itr!=lstro.end(); itr++) {
    //resource-id
    uchar_to_hexstring( (uchar*)itr->stresid.id, m_pPeer->m_HASH_SIZE, temp);
    strresid = temp;
    
    //owner. If no owner then peerid in resource-object. If no peer-id
    //in resource-object, then peer-id of the peer publishing the object.
    if(itr->stowner.isPresent) {
      strownerid = (char*)itr->stowner.id;
    } else if(itr->stpeerinfo.isPresent) {
      uchar_to_hexstring( (uchar*)itr->stpeerinfo.stpeerid.id, m_pPeer->m_HASH_SIZE, temp);
      strownerid = temp;
    } else {
      uchar_to_hexstring( (uchar*)stP.stpeerid.id, m_pPeer->m_HASH_SIZE, temp);
      strownerid = temp;
    }
    
    
    //create a IRO3, IRO2, IRO1 object
    iro3.stro = *(itr);//objLO.stro;
    
    //If no peerinfo add it to resourceobject for USERINFO type
    if(eUSERINFO == itr->conttype && 0 == itr->stpeerinfo.isPresent) {
      iro3.stro.stpeerinfo = stP;
    }
    
    //printf("iro3 is present: %d objLO is present: %d\n", iro3.stro.isPresent, itr->isPresent);
    
    //expires time
    gettimeofday( &(iro3.expt), NULL);
    iro3.expt=addtimeval(iro3.expt, expt.tv_sec, expt.tv_usec);
    
    //If no peerinfo in resource-object, then insert the peerinfo of
    //peer sending the request. This is for USER-INFO and STRINGVAL objects.
    if(1 == itr->stpeerinfo.isPresent) {
      iro3.stP = itr->stpeerinfo;
    } else {
      iro3.stP = stP;
    }
    
    //Its is a resource object
    iro3.stro.stobj.objtype = eRESOURCEOBJECT;
    
    iro2.m_OMap[strownerid] = iro3;
    iro1.m_YMap[itr->conttype] = iro2;
    
    //Find resource-ID
    i1=m_RT.find(strresid);
    
    //If exists
    if(i1 != m_RT.end() ) {
      
      //Find content-type
      i2 = i1->second.m_YMap.find(itr->conttype);
      
      //If content type exists
      if(i2 != i1->second.m_YMap.end() ) {
	
        TRACE(2, "RManager::InsertinRT...ID: %s  and type exist. Owner map size: %d\n", (char*)itr->stunhashedid.unhashed , i2->second.m_OMap.size() );
        //Peer-ID is considered the owner-ID
        i2->second.m_OMap[strownerid] = iro3;
      } else {
	
        TRACE(2, "RManager::InsertinRT...no owner m_YMap size: %d\n", i1->second.m_YMap.size() );
        i1->second.m_YMap[itr->conttype]=iro2;
      }
      
    } else {
      
      TRACE(2, "RManager::InsertinRT...no resource-ID: %s m_RT size: %d\n", (char*)itr->stunhashedid.unhashed , m_RT.size() );
      m_RT[strresid] = iro1;
    }
    
  }//end of for

  return 1;

}//InsertinRT


int32 RManager::InsertinPT(const LObject& objLO, struct timeval expt, const string& strtransid) {

  struct IRO3 iro3;
  char temp[2*HASHLEN];
  string strresid;
  struct timeval ttemp;
  list<struct resourceobject>::iterator itr;
  list<resourceobject> lstro;

  lstro=objLO.lstro;
  for(itr=lstro.begin(); itr!=lstro.end(); itr++) {

    //Create the IRO object containing the resource-object, expires, and transaction-ID
    iro3.stro = *(itr);
    
    //expire time after which a refresh needs to be sent
    gettimeofday(&ttemp, NULL);
    expt=addtimeval(ttemp, expt.tv_sec-5, expt.tv_usec);
    iro3.expt = expt;
    iro3.strtransid = strtransid;
    
    //resource-id
    uchar_to_hexstring( (uchar*)itr->stresid.id, m_pPeer->m_HASH_SIZE, temp);
    strresid = temp;
    
    //Store it in the publish table
    m_PT.insert( pair<string,IRO3>(strresid,iro3) );
  }//end of for 

  return 1;
    
}//InsertinPT

/*UpdatePT(msg) called when a response is received
 *
 *
 */
int32 RManager::UpdatePT(struct message& msg) {
  
  multimap<string, IRO3>::iterator i3;
  string strtransid;
  struct timeval ttemp;

  //If message was a 200 ok and expires was present
  if(200 == msg.stcmn_hdr.respcode && msg.stexpires.isPresent) {

    //get the message transaction id
    strtransid = msg.getTransId();

    for(i3=m_PT.begin(); i3 != m_PT.end();  i3++) {
      
      //If transaction-ID of received and stored is same, update expires
      if(0 == strcmp( (char*)i3->second.strtransid.c_str(), (char*)strtransid.c_str()) ) {

        gettimeofday(&ttemp, NULL);
        //ttemp=addtimeval(ttemp, msg.stexpires.utime-5, 0);
	ttemp=addtimeval(ttemp, EXP_TIME, 0);

        i3->second.expt = ttemp;
      }
      
    }//end for

  }//end if

  return 1;
}//UpdatePT




/*UpdatePT(strtransid) called when no response is received
 *
 *
 */
int32 RManager::UpdatePT(string& strtransid) {
  
  multimap<string, IRO3>::iterator i3;
  struct timeval ttemp;

  for(i3=m_PT.begin(); i3 != m_PT.end();  i3++) {
    
    //If transaction-ID of received and stored is same, update expires
    if(0 == strcmp( (char*)i3->second.strtransid.c_str(), (char*)strtransid.c_str()) ) {
      
      gettimeofday(&ttemp, NULL);
      //ttemp=addtimeval(ttemp, msg.stexpires.utime-5, 0);
      ttemp=addtimeval(ttemp, EXP_TIME, 0);
      
      i3->second.expt = ttemp;
    }
    
  }//end for
  
  return 1;
}//UpdatePT





int32 RManager::PublishUserInfo(char8* pchUser, uint32 len, enum transtype tt) {

  struct resourceobject stro;
  struct peerinfo stNP;  //next peer
  struct peerinfo stPSelf;
  LObject objLO;
  int32 ret;
  string strtransid="";
  struct timeval expt;

  TRACE(4, "RManager::PublishUserInfo...Begins for user: %s\n", pchUser);


  printf("Hash size: %d Hash alg: %s\n", m_pPeer->m_HASH_SIZE, phalg[m_pPeer->m_HASH_ALG] );

  //User name
  objLO.strKey = pchUser;
  objLO.callback = 0;
  objLO.pApp = 0;
  objLO.isOrig = 1;

  //transport  type
  objLO.tt = tt;

  //get the self peerinfo
  m_pPeer->getSelfPeer(stPSelf);
  
  //BUILD THE RESOURCE-OBJECT
  //Compute the hash of the key and store it in resource-object
  getHash((uchar*)pchUser, len, (uchar*)stro.stresid.id, m_pPeer->m_HASH_SIZE, m_pPeer->m_HASH_ALG);
  stro.stresid.isPresent=1;
  stro.stresid.stobj.length=idlen;
  //The resource type
  stro.conttype = eUSERINFO;
  stro.isPresent = 1;

  TRACE(3, "RManager::PublishUserInfo...stro encoded\n", "");

  //Now the unhashed id
  strcpy( (char*)stro.stunhashedid.unhashed, (char*)pchUser);
  stro.stunhashedid.isPresent=1;
  stro.stunhashedid.stobj.length=strlen(pchUser);

  //Now the peerinfo
  stro.stpeerinfo = stPSelf;
  stro.stpeerinfo.isPresent = 1;
  
  printf("PublishObject: user %s hash is: 0x", pchUser);
  for(int i=0; i<idlen; i++) {
    printf("%x", stro.stresid.id[i] );
  }
  printf("\n");
  
  
  //getNextHop
  ret=m_pPeer->getNextHop(stro.stresid.id, m_pPeer->m_HASH_SIZE, stNP );
  objLO.lstro.push_back(stro);

  //clear stRo and add SIP object (if there is one)
  //  memset(&stRo, 0, sizeof(struct resourceobject));
  struct resourceobject stRo2;
  if(m_pPeer->GetSIPObject(stRo2)) {
    //Now the unhashed id
    strcpy( (char*)stRo2.stunhashedid.unhashed, (char*)pchUser);
    //strcat( (char*)stRo2.stunhashedid.unhashed, "-sip");
    stRo2.stunhashedid.isPresent=1;
    stRo2.stunhashedid.stobj.length=strlen(pchUser);
    getHash((uchar*)stRo2.stunhashedid.unhashed, strlen(pchUser), (uchar*)stRo2.stresid.id, m_pPeer->m_HASH_SIZE, m_pPeer->m_HASH_ALG);
    stRo2.stresid.isPresent=1;
    stRo2.stresid.stobj.length=idlen;
    objLO.lstro.push_back(stRo2);
  }
  
  //expires value
  expt.tv_sec = EXP_TIME;
  expt.tv_usec = 0;

  //where to send
  if(0 == ret) {
    printf( "RManager::PublishUserInfo...We store the object. No need to send\n");

    //Update expires
    expt.tv_sec = EXP_TIME_RVAL;
    InsertinRT(objLO, expt, stPSelf);

  } else {
    TRACE(3, "RManager::PublishUserInfo...Send it to next node\n", "");
    //send the put message
    m_pPeer->ComposePublishObject(stNP, objLO, strtransid);

    //This is a in progress transaction
    m_IP[strtransid] = objLO;
  }

  //Insert in publish table. The publish table contains a list of
  //objects that this node has inserted so far and will like to keep
  //refreshing them.

  //update expire time EXP_TIME=30s EXP_TIME_RVAL=5min
  expt.tv_sec = EXP_TIME;
  expt.tv_usec = 0;
  InsertinPT(objLO, expt, strtransid);

  TRACE(3, "RManager::PublishUserInfo...transid: %s\n", strtransid.c_str() );


  return 1;

}//PublishUserInfo



int32 RManager::RePublishUserInfo() {

  struct resourceobject stro;
  struct peerinfo stNP;  //next peer
  struct peerinfo stPSelf;
  LObject objLO;
  int32 ret;
  string strtransid="";
  struct timeval expt;
  int32 len;
  char* pchUser;

  pchUser=(char*)m_pPeer->getUSERID();

  TRACE(4, "RManager::PublishUserInfo...Begins for user: %s\n", pchUser);

  //printf("Hash size: %d Hash alg: %s\n", m_pPeer->m_HASH_SIZE, phalg[m_pPeer->m_HASH_ALG] );

  //User name
  objLO.strKey = pchUser;
  len = strlen(pchUser);
  objLO.callback = 0;
  objLO.pApp = 0;
  objLO.isOrig = 1;

  //transport type is UDP
  objLO.tt = eUDP;

  //get the self peerinfo
  m_pPeer->getSelfPeer(stPSelf);
  
  //BUILD THE RESOURCE-OBJECT
  //Compute the hash of the key and store it in resource-object
  getHash((uchar*)pchUser, len, (uchar*)stro.stresid.id, m_pPeer->m_HASH_SIZE, m_pPeer->m_HASH_ALG);
  stro.stresid.isPresent=1;
  stro.stresid.stobj.length=idlen;
  //The resource type
  stro.conttype = eUSERINFO;
  stro.isPresent = 1;

  TRACE(3, "RManager::PublishUserInfo...stro encoded\n", "");

  //Now the unhashed id
  strcpy( (char*)stro.stunhashedid.unhashed, (char*)pchUser);
  stro.stunhashedid.isPresent=1;
  stro.stunhashedid.stobj.length=strlen(pchUser);

  //Now the peerinfo
  stro.stpeerinfo = stPSelf;
  stro.stpeerinfo.isPresent = 1;
  
  printf("PublishObject: user %s hash is: 0x", pchUser);
  for(int i=0; i<idlen; i++) {
    printf("%x", stro.stresid.id[i] );
  }
  printf("\n");
  
  
  //getNextHop
  ret=m_pPeer->getNextHop(stro.stresid.id, m_pPeer->m_HASH_SIZE, stNP );
  objLO.lstro.push_back(stro);

  //clear stRo and add SIP object (if there is one)
  //  memset(&stRo, 0, sizeof(struct resourceobject));
  struct resourceobject stRo2;
  if(m_pPeer->GetSIPObject(stRo2)) {
    //Now the unhashed id
    strcpy( (char*)stRo2.stunhashedid.unhashed, (char*)pchUser);
    //strcat( (char*)stRo2.stunhashedid.unhashed, "-sip");
    stRo2.stunhashedid.isPresent=1;
    stRo2.stunhashedid.stobj.length=strlen(pchUser);
    getHash((uchar*)stRo2.stunhashedid.unhashed, strlen(pchUser), (uchar*)stRo2.stresid.id, m_pPeer->m_HASH_SIZE, m_pPeer->m_HASH_ALG);
    stRo2.stresid.isPresent=1;
    stRo2.stresid.stobj.length=idlen;
    objLO.lstro.push_back(stRo2);
  }
  
  //expires value
  expt.tv_sec = EXP_TIME;
  expt.tv_usec = 0;

  //where to send
  if(0 == ret) {
    printf( "RManager::PublishUserInfo...We store the object. No need to send\n");

    //Update expires
    expt.tv_sec = EXP_TIME_RVAL;
    InsertinRT(objLO, expt, stPSelf);

  } else {
    TRACE(3, "RManager::PublishUserInfo...Send it to next node\n", "");
    //send the put message
    m_pPeer->ComposePublishObject(stNP, objLO, strtransid);

    //This is a in progress transaction
    m_IP[strtransid] = objLO;
  }

  //Insert in publish table. The publish table contains a list of
  //objects that this node has inserted so far and will like to keep
  //refreshing them.

  //NO NEED TO INSERT NOW SINCE WE ARE REPUBLISHING
  //update expire time EXP_TIME=30s EXP_TIME_RVAL=5min
  //expt.tv_sec = EXP_TIME;
  //expt.tv_usec = 0;
  //InsertinPT(objLO, expt, strtransid);

  TRACE(3, "RManager::PublishUserInfo...transid: %s\n", strtransid.c_str() );

  return 1;

}//RePublishUserInfo









int32 RManager::PublishObject(char8* pchKey, uint32 klen, char8* pchValue, uint32 vlen, enum transtype tt, void* (*callback)(void*, int32), void* pApp) {

  struct peerinfo stNP;  //next peer
  struct peerinfo stPSelf;
  LObject objLO;
  int32 ret;
  string strtransid="";
  struct timeval expt;
  struct resourceobject stro;

  TRACE(4, "RManager::PublishObject...Begins for key: %s\n", pchKey);

  //Key
  objLO.strKey = pchKey;
  objLO.callback = callback;
  objLO.pApp = pApp;
  objLO.isOrig = 1;

  //transport type
  objLO.tt = tt;

  //get the self peerinfo
  m_pPeer->getSelfPeer(stPSelf);


  //BUILD THE RESOURCE-OBJECT
  //Compute the hash of the key and store it in resource-object
  getHash((uchar*)pchKey, klen, (uchar*)stro.stresid.id, m_pPeer->m_HASH_SIZE, m_pPeer->m_HASH_ALG);
  stro.stresid.isPresent=1;
  stro.stresid.stobj.length=idlen;
  //The resource type
  stro.conttype = eSTRINGVAL;
  stro.subtype = 0;
  stro.isPresent = 1;


  //resourceobjectvalue  
  strcpy( (char8*)stro.strov.value, pchValue);
  stro.strov.stobj.length = vlen;
  stro.strov.isPresent=1;


  //Now the unhashed id
  strcpy( (char*)stro.stunhashedid.unhashed, (char*)pchKey);
  stro.stunhashedid.isPresent=1;
  stro.stunhashedid.stobj.length=strlen(pchKey);

  
  printf("PublishObject: key %s \n", pchKey);
  /*printf("PublishObject: key %s hash is: 0x", pchKey);
  for(int i=0; i<idlen; i++) {
    printf("%x", objLO.stro.stresid.id[i] );
  }
  printf("\n");
  */
  gettimeofday(&objLO.senttime, NULL);
  
  //getNextHop
  ret=m_pPeer->getNextHop(stro.stresid.id, m_pPeer->m_HASH_SIZE, stNP );

  objLO.lstro.push_back(stro);

  //expires value
  expt.tv_sec = EXP_TIME_RVAL;
  expt.tv_usec = 0;

  //where to send
  if(0 == ret && ePEER == m_pPeer->m_NODE_TYPE) {
    printf( "RManager::PublishObject...We store the object. No need to send\n");
    InsertinRT(objLO, expt, stPSelf);

  } else {
    TRACE(3, "RManager::PublishObject...Send it to next node\n", "");
    //send the put message
    m_pPeer->ComposePublishObject(stNP, objLO, strtransid);

    //This is a in progress transaction
    m_IP[strtransid] = objLO;
  }

  TRACE(3, "RManager::PublishObject...transid: %s\n", strtransid.c_str() );

  return 1;

}//PublishObject




int32 RManager::OnPublishObjectRequest(struct message& msg, char* pchIP, int32 port, transtype tt) {
  struct peerinfo stPSelf, stNP;
  int32 ret;
  struct LObject objLO;
  struct timeval expt;
  int32 respCode;
  string strtransid;
  
  //set the expires EXP_TIME_RVAL
  expt.tv_sec = EXP_TIME_RVAL; expt.tv_usec=0;

  //get self peer
  m_pPeer->getSelfPeer(stPSelf);

  //get next hop
  ret=m_pPeer->getNextHop( (*msg.lstro.begin()).stresid.id, m_pPeer->m_HASH_SIZE, stNP );

  //Determine the next hop
  if(0 == ret) {
    respCode=200;

    //copy the resource-object list in objLO
    objLO.lstro=msg.lstro;

    //Store the resource object
    InsertinRT(objLO, expt, msg.stpeerinfo);

    TRACE(2, "RManager::OnPublishObjectRequest...Inserting Object\n", "");
    
  } else {
    respCode = 302;

    TRACE(2, "RManager::OnPublishObjectRequest...Redirecting\n", "");
    //printf("INSERT sending respcode %d %s %d isaddr: %d\n", respCode, stPNext.staddr.addr[0], stPNext.staddr.port[0], stPNext.isPresent);
  }

  //Check if TTL hops exceeded, send 410 TTL hops exceeded response
  if(302 == respCode && 0 == msg.stcmn_hdr.ttl) {
    TRACE(2, "RManager::OnPublishObjectRequest...410 (TTL hops exceeded)\n", "");
    respCode = 410;
  }


  //Send the response if iterative or 200
  if(0 == msg.stcmn_hdr.rori || 200 == respCode || 410 == respCode) {
    m_pPeer->ComposePublishObjectResp(respCode, stPSelf, stNP, pchIP, port, tt, expt, msg);
    
  } else if(1 == msg.stcmn_hdr.rori && 302 == respCode) {

    printf("recursive request forwarding\n");
    
    //1) get a copy of the object
    //2) get the ip address, port and transport type on which the request
    //was received
    //3) create a new transaction
    //4) this is an inprogress transaction

    //1) 
    objLO.lstro = msg.lstro; //*(msg.lstro.begin());
    
    //2)
    //recursive request
    objLO.pApp = 0;        //this null pointer indicates that we
                           //should send the response upstream instead
                           //of giving it to the application
    strcpy(objLO.pchIP, pchIP);
    objLO.port = port;
    objLO.tt = tt;
      
    //3)    
    m_pPeer->ComposePublishObject(stNP, objLO, strtransid, msg, tt);

    //4)
    m_IP[strtransid] = objLO;
    
  }//end else

  return 1;

}//OnPublishObjectRequest




int32 RManager::OnPublishObjectResponse(struct message& msg) {
  
  map<string, LObject>::iterator i1;
  map<string, IRO3, classcomp>::iterator i2;

  list<peerinfo>::iterator litr;
  struct LObject objLO;
  string strtransid;
  struct peerinfo stNP;
  
  
  TRACE(2, "RManager::OnPublishObjectResponse...m_PT size: %d m_IP size: %d\n", m_PT.size(), m_IP.size() );
  
  
  //Check if we have already processed this message
  i1=m_IP.find(msg.getTransId());
  if(i1 == m_IP.end() ) {
    TRACE(2, "RManager::OnPublishObjectResponse...response nothing in map_IL respcode: %d transID: %d\n", msg.stcmn_hdr.respcode, msg.stcmn_hdr.transid);
    return 0;
  } 

  //get a local copy of the LObject
  objLO = i1->second;
  
  //Now remove from the lookuptable map
  m_IP.erase(i1);
  
  //printf("PublishObject: %d response from %s %d\n", msg.stcmn_hdr.respcode, msg.stpeerinfo.staddr.addr[0], msg.stpeerinfo.staddr.port[0]);  

  if(302 == msg.stcmn_hdr.respcode) {
    TRACE(2, "RManager::OnPublishObjectResponse...302 for PublishObject...send PO\n", "");

    //decrement TTL if TTL expired then return immediately. TTL is set to 20 for iterative
    objLO.ttl--;
    
    if(0 == objLO.ttl) {
      if( 0 != objLO.callback) {
        objLO.callback( (void*)&objLO, msg.stcmn_hdr.respcode);
      }
      
      TRACE(2, "RManager::OnPublishObjectResponse...m_IP map size: %d...enough of TTL\n", m_IP.size() );
      
      //FIXME: Update Publish Timer here?
      return 0;
    }

    //if there is a list of peerinfo object
    if(msg.stlpeerinfo.size() > 0) {
      stNP=*(msg.stlpeerinfo.begin());
   

      TRACE(2, "RManager::OnPublishObjectResponse...302 IP: %s port: %d\n", stNP.staddr.addr[0], stNP.staddr.port[0] );

      m_pPeer->ComposePublishObject( stNP, objLO, strtransid);
      
      //Update the object according in new map
      m_IP[strtransid] = objLO;
      
    } else {
      printf("Error in PublishObject response...There was no peerinfo object in 302\n");
    }    
    
    
  } else if(200 == msg.stcmn_hdr.respcode) {
    TRACE(2, "RManager::OnPublishObjectResponse...%d\n", msg.stcmn_hdr.respcode);


    //call the application callback function to inform about the response status
    if(0 != objLO.callback) {
      objLO.callback( (void*)&objLO, msg.stcmn_hdr.respcode);

      //Update the expires value
      UpdatePT(msg);
      
    } else {
        
      if(1 == objLO.isOrig) {
	
        //Update the expires value
        UpdatePT(msg);
        //update relay list in STI manager
        //printf("RManager::OnPublishObjectResponse...msg.strt.table.size=%d\n", msg.strt.table.size());
        m_pPeer->UpdateRelayList((const list< struct peerinfo>)msg.strt.table);
      } else {
        
        TRACE(2, "RManager::OnPublishObjectResponse...sending response upstream\n", "");

        //RECURSIVE MODE: send the response upstream
        m_pPeer->ComposePublishObjectResp(objLO.pchIP, objLO.port, objLO.tt, msg);
      }

    }//end else

  }//end

  
  return 1;
}//OnPublishObjectResponse



/**
 * Handles two types of timers. 
 * USERINFO refresh OnPublishTimer()
 * Remove resources whose timer has expired OnRTTimer()
*/

int32 RManager::OnTimer() {

  OnPublishTimer();

  OnRTTimer();
  
  return 1;
}//OnTimer



int32 RManager::OnPublishTimer() {
  
  multimap<string, IRO3>::iterator i1;
  struct timeval ttemp, expt, curr;
  string strtransid;
  struct peerinfo stNP, stPSelf;
  int32 ret;
  struct LObject objLO;

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

  //get self peer
  m_pPeer->getSelfPeer(stPSelf);
  

  for(i1=m_PT.begin(); i1!=m_PT.end(); i1++) {    

    //expires time
    expt.tv_sec = EXP_TIME; expt.tv_usec = 0;

    
    ttemp=difftimeval(i1->second.expt, curr);

    //If publish timer has expired then refresh it
    if(0 == ttemp.tv_sec && 0 == ttemp.tv_usec) {      

      TRACE(2, "RManager::OnPublishTimer...expired for resource: %s\n", (char*)i1->second.stro.stunhashedid.unhashed);

      //printf("resource timer expired\n");

      //Modify content of resource object if it has changed.
      if(i1->second.stro.conttype==eSIP) {
        struct resourceobject stRo2;
        if(m_pPeer->GetSIPObject(stRo2)) {
          if(strcmp(stRo2.staddr.addr[0], i1->second.stro.staddr.addr[0])!=0 || 
            i1->second.stro.staddr.port[0]!=stRo2.staddr.port[0]) {
              strncpy(i1->second.stro.staddr.addr[0], stRo2.staddr.addr[0], IPADDRLEN);
              i1->second.stro.staddr.port[0]=stRo2.staddr.port[0];
          }
        }
      } else if(i1->second.stro.conttype==eUSERINFO) {
        //get the self peerinfo
        m_pPeer->getSelfPeer(stPSelf);
        i1->second.stro.stpeerinfo=stPSelf;
      }

      //getNextHop
      ret=m_pPeer->getNextHop(i1->second.stro.stresid.id, m_pPeer->m_HASH_SIZE, stNP );      
      
      //get the resource object
      objLO.lstro.push_back(i1->second.stro);
      objLO.isOrig=1;
    
      //We are not the hop. send the object
      if(0 != ret) {
        m_pPeer->ComposePublishObject(stNP, objLO, strtransid);

        //the transaction is now in progress
        m_IP[strtransid] = objLO;
      } else {
        //Store the resource object as we are the hop
        if(eCLIENT!=m_pPeer->m_NODE_TYPE) {
          //update timer
          expt.tv_sec = EXP_TIME_RVAL;
          InsertinRT(objLO, expt, stPSelf);
        }
      }
      
      //Update publish timer for that object
      gettimeofday(&ttemp, NULL);
      //ttemp=addtimeval(ttemp, msg.stexpires.utime-5, 0);
      ttemp=addtimeval(ttemp, EXP_TIME, 0);      
      i1->second.expt = ttemp;        

      //Update publish table
      
      //keep-alive timer
      //expt.tv_sec = EXP_TIME;

      //UpdatePT(strtransid);
      //InsertinPT(objLO, expt, strtransid);
    }

  }//end for

  return 1;
}//OnPublishTimer



//possible BUG
//only removing values in owner and not the upper fields
//

int32 RManager::OnRTTimer() {

  struct IRO3 iro3;
  struct IRO2 iro2;
  struct IRO1 iro1;
  map<string, IRO1>::iterator i1;
  map<int32, IRO2>::iterator i2;
  map<string, IRO3, classcomp>::iterator i3;
  list<string> lowner;
  list<string>::iterator litr;
  struct timeval ttemp1, ttemp;


  TRACE(3, "RManager::OnRTTimer...called\n", "");

  //gettimeofday
  gettimeofday(&ttemp, NULL);

  
  for(i1=m_RT.begin(); i1 != m_RT.end(); i1++ ) {
    
    for(i2=i1->second.m_YMap.begin(); i2!=i1->second.m_YMap.end(); i2++) {

      //clean the list
      lowner.clear();

      //TRACE(2, "RManager::OnRTTimer...OMap size: %d\n", i2->second.m_OMap.size() );

      for(i3=i2->second.m_OMap.begin(); i3!=i2->second.m_OMap.end(); i3++) {

        //Potential source of error; otherwise call gettimeofday here
        ttemp1 = ttemp;

        TRACE(2, "RManager::OnRTTimer...ID: %s before sec: %u usec %u after sec: %u usec: %u\n", i3->second.stro.stunhashedid.unhashed, (uint32)i3->second.expt.tv_sec, (uint32)i3->second.expt.tv_usec, (uint32)ttemp1.tv_sec, (uint32)ttemp1.tv_usec);
        
        ttemp1 = difftimeval(i3->second.expt, ttemp1);

        //The object has expired. Remove it now
        if(0 == ttemp1.tv_sec && 0 == ttemp1.tv_usec) {
          lowner.push_back(i3->first);
        }
        
      }//end for

      //Now remove the expired objects from the list
      for(litr=lowner.begin(); litr!=lowner.end(); litr++) {

        TRACE(2, "RManager::OnRTTimer...expired for resource: %s\n", (char*)(*litr).c_str() );

        i3=i2->second.m_OMap.find(*litr);
        i2->second.m_OMap.erase(i3);
      }//end for


    }//end for
    
  }//end for

  return 1;

}//OnRTTimer



int32 RManager::OnTransactionTimeout(enum msgtype mtype, enum reqoritype ritype, string strtransid, char* pchIP, int32 port) {
  
  //PublishObject
  //LookupObject
  
  map<string, LObject>::iterator i1;
  struct timeval expt;
  struct LObject objLO;

  i1=m_IP.find(strtransid);
  if(i1 == m_IP.end() ) {
    TRACE(2, "RManager::OnTransactionTimeout...no corresponding transaction\n", "");
    return 1;
  }//end if
  

  switch(ritype) {
  
  case eLOOKUPOBJECT:

    if(0 != i1->second.callback ) {
      i1->second.callback( (void*)(&(i1->second)), 413);
    }
    break;

  case ePUBLISHOBJECT:
    
    //We did not receive a response for PublishObject. Update the
    //expires. After expiration, we will resend the publish request
    if(i1->second.stro.conttype == eUSERINFO) {
      expt.tv_sec=EXP_TIME; expt.tv_usec=0;
      objLO = i1->second;

      //Update the timer based on transaction-id
      UpdatePT(strtransid);

    } else {
      
      if(0 != i1->second.callback ) {
        i1->second.callback( (void*)(&(i1->second)), 413);
      }
    }
    break;

  default:
    break;

  }//end switch


  //erase from the inprogress map
  m_IP.erase(i1);

  return 1;

}//OnTransactionTimeout


void RManager::ShowRO() {

  map<string, IRO1>::iterator i1;
  map<int32, IRO2>::iterator i2;
  map<string, IRO3, classcomp>::iterator i3;

  int32 count=1;  //variable for counting the entries in RT

  TRACE(3, "RManager::ShowRO...called RT size: %d\n", m_RT.size() );

  printf("Resource Table\n--------------\n" );

  
  for(i1=m_RT.begin(); i1 != m_RT.end(); i1++ ) {

    TRACE(3, "RManager::ShowRO...YMap size: %d\n", i1->second.m_YMap.size() );    

    for(i2=i1->second.m_YMap.begin(); i2!=i1->second.m_YMap.end(); i2++) {

      TRACE(3, "RManager::ShowRO...called OMap size: %d\n", i2->second.m_OMap.size() );
      for(i3=i2->second.m_OMap.begin(); i3!=i2->second.m_OMap.end(); i3++) {

        printf("(%d) ID 0x%s type: %s ", count, (char8*)i1->first.c_str(), pcontent_type[i2->first] );

        if(eUSERINFO == i2->first) {

	  //print the user-ID if present
	  if(i3->second.stro.stunhashedid.isPresent) {
	    printf("%s ", i3->second.stro.stunhashedid.unhashed);
	  }

          printf("%s %d\n", i3->second.stP.staddr.addr[0], i3->second.stP.staddr.port[0]);

        } else if(eSTRINGVAL == i2->first) {
          printf("%s %s inserted by: %s %d\n", (char*)i3->second.stro.stunhashedid.unhashed, i3->second.stro.strov.value, i3->second.stP.staddr.addr[0], i3->second.stP.staddr.port[0]) ;
        } else if(eSIP == i2->first) {
	  //print the user-ID if present
	  if(i3->second.stro.stunhashedid.isPresent) {
	    printf("%s ", i3->second.stro.stunhashedid.unhashed);
	  }
          printf("%s %d\n", i3->second.stro.staddr.addr[0], i3->second.stro.staddr.port[0]);
	}

	count++; //counter that counts the number of objects in the resource table
        
      }//end for

    }//end for
    
  }//end for
  

}//ShowRO

void RManager::getResTable(list<resourceobject >& lstro){
  
  map<string, IRO1>::iterator i1;
  map<int32, IRO2>::iterator i2;
  map<string, IRO3, classcomp>::iterator i3;

  TRACE(3, "RManager::getResTable...called RT size: %d\n", m_RT.size() );

  for(i1=m_RT.begin(); i1 != m_RT.end(); i1++ ) {

    for(i2=i1->second.m_YMap.begin(); i2!=i1->second.m_YMap.end(); i2++) {

      for(i3=i2->second.m_OMap.begin(); i3!=i2->second.m_OMap.end(); i3++) {
        lstro.push_back(i3->second.stro);
      }//end for

    }//end for
    
  }//end for
  
}//getResTable


void RManager::getResTable(list<resourceobject >& lstro, transtype tt) {
  
  map<string, IRO1>::iterator i1;
  map<int32, IRO2>::iterator i2;
  map<string, IRO3, classcomp>::iterator i3;
  struct timeval curr_time;
  int32 flag[1000], count=0, rSize, c, num;

  TRACE(3, "RManager::getResTable...called RT size: %d\n", m_RT.size() );


  ///////////////////////////////////////////////
  //TEMP CODE BEGINS for random number generation
  ///////////////////////////////////////////////
  //set the seed
  gettimeofday(&curr_time, NULL);
  srand(curr_time.tv_sec+curr_time.tv_usec);
      
  //set the array to 0
  for(int i=0; i<1000;i++) {
    if(eUDP == tt) {
      flag[i] = 0;
    } else {
      flag[i] = 1;
    }
  }
      

  //Flag to indicate whether we need to include all entries or only part
  //of them. If UDP only include part of it
  //TOTAL MAXIMUM ENTRIES are 15 FOR UDP
  if(eUDP == tt) rSize = 15; else rSize = m_RT.size();
  
  //The total number of entries in routing tables
  num = m_RT.size(); if(m_RT.size() > 1000) num=1000;


  count=1;
  c = 0;

  if(eUDP == tt) {
    for(int i=0; i<num && i<1000 && count <= 15; i++) {
      if(num > rSize) {
	do {
	  c = (int) (rand() % num);
	} while (flag[c] != 0);
      } else {
	c=count-1;
      }
      
      flag[c]=1;
      count++;
    }//end for
  }//end if
  
  ///////////////////////////////////////////////
  //TEMP CODE ENDS for random number generation
  ///////////////////////////////////////////////

  count=0;
  
  for(i1=m_RT.begin(); i1 != m_RT.end(); i1++ ) {

    for(i2=i1->second.m_YMap.begin(); i2!=i1->second.m_YMap.end(); i2++) {

      for(i3=i2->second.m_OMap.begin(); i3!=i2->second.m_OMap.end(); i3++) {

        //If we should include this id in the table
	//if(1 == flag[count]) {
	  lstro.push_back(i3->second.stro);
	  //}

	count++;

      }//end for

    }//end for
    
  }//end for
  
}//getResTable





int32 RManager::ChangeUserID(char8* pchUser, int32 len) {

  LObject objLO;
  struct peerinfo stPSelf;
  struct timeval expt;
  multimap<string, struct IRO3>::iterator i1;
  struct IRO3 iro3;
  char temp[2*HASHLEN];
  string strresid;

  //User name
  objLO.strKey = pchUser;
  objLO.callback = 0;
  objLO.pApp = 0;
  objLO.isOrig = 1;  

  //get the self peerinfo
  m_pPeer->getSelfPeer(stPSelf);
  
  //BUILD THE RESOURCE-OBJECT
  //Compute the hash of the key and store it in resource-object
  getHash((uchar*)pchUser, len, (uchar*)objLO.stro.stresid.id, m_pPeer->m_HASH_SIZE, m_pPeer->m_HASH_ALG);
  objLO.stro.stresid.isPresent=1;
  objLO.stro.stresid.stobj.length=idlen;
  //The resource type
  objLO.stro.conttype = eUSERINFO;
  objLO.stro.isPresent = 1;

  TRACE(3, "RManager::PublishUserInfo...stro encoded\n", "");

  //Now the unhashed id
  strcpy( (char*)objLO.stro.stunhashedid.unhashed, (char*)pchUser);
  objLO.stro.stunhashedid.isPresent=1;
  objLO.stro.stunhashedid.stobj.length=strlen(pchUser);

  //Now the peerinfo
  objLO.stro.stpeerinfo = stPSelf;
  objLO.stro.stpeerinfo.isPresent = 1;

  //expires value
  expt.tv_sec = EXP_TIME;
  expt.tv_usec = 0;


  //Remove the previous user-ID from the map
  for(i1=m_PT.begin(); i1!=m_PT.end(); i1++) {
    if ( eUSERINFO == i1->second.stro.conttype ) {
      break;
    }
  }

  m_PT.erase(i1);  
  

  //Create the IRO object containing the resource-object, expires, and transaction-ID
  iro3.stro = objLO.stro;
  
  //expire time after which a refresh needs to be sent
  gettimeofday(&expt, NULL);  
  iro3.expt = expt;  //expire immediately  

  //resource-id
  uchar_to_hexstring( (uchar*)objLO.stro.stresid.id, m_pPeer->m_HASH_SIZE, temp);
  strresid = temp;
  
  //Store it in the publish table
  m_PT.insert( pair<string,IRO3>(strresid,iro3) );
  //m_PT[strresid]=iro3;

  return 1;
}//ChangeUserID



void RManager::Disconnect() {
  //erase the publish timer objects
  m_PT.clear();

  //erase the objects that we stored
  m_RT.clear();

  //in progress transactions
  m_IP.clear();
  
}//Disconnect
