#include "transaction.h"

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

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

Transaction::Transaction() {

}

Transaction::~Transaction() {

}



void Transaction::setParams(Transport* objTransport, uint32 transId, uchar* srcId, uint32 srcIdLen, enum msgtype tmsg, enum reqoritype treqori, enum transtype eTrans) {
  
  char temp[2*HASHLEN];

  //set transport pointer
  m_pobjTransport = objTransport;

  //Transaction Id
  m_uiTransId = transId;

  //Source-Id
  uchar_to_hexstring(srcId, srcIdLen, temp);

  //Now compute the (source-Id, trasaction-Id) tuple and store it
  m_srcId = temp;

  //printf("serc id before: %s\n", m_srcId.c_str() );

  sprintf(temp,"%u",m_uiTransId);
  m_srcId += temp;

  //printf("serc id after: %s\n", m_srcId.c_str() );

  //Msgtype
  m_msgtype = tmsg;

  //Request or indication
  m_reqoritype = treqori;

  //transport type TCP, UDP, or TLS
  m_eTransport = eTrans;

  //Initialize retrans
  m_iRetrans = 1;


}//Initialize


void Transaction::setDestId(uchar* dstId, uint32 dstIdLen) {
  char temp[2*HASHLEN];
  
  uchar_to_hexstring(dstId, dstIdLen, temp);

  m_dstId = temp;

  memcpy(m_uchdstId, dstId, dstIdLen);
}//setDestId


/*
  -1 no ACK received
  0 no response received
*/

int32 Transaction::OnTimer() {
  
  struct timeval curr_time, difft;

  gettimeofday(&curr_time, NULL);
  
  switch(m_State) {

  case eT_TRANS_MSG:
    //Check if complete transaction has expired
    difft = difftimeval(m_eTime, curr_time);
  
    //transaction has expired, return immediately
    if(0 == difft.tv_sec && 0 == difft.tv_usec) {
      m_State = eT_FAILURE;
      return 0;
    }
    
    //Check if message send timer has expired
    difft = difftimeval(m_nTime, curr_time);
    //printf("difft time sec: %ld usec: %ld\n", difft.tv_sec, difft.tv_usec);
    //We should resend the request
    if(0 == difft.tv_sec && 0 == difft.tv_usec) {
      
      //double the timer
      m_iRetrans *= 2;
      if(m_iRetrans >= 64) {
        m_iRetrans = 64;
      }
      
      //TRACE(5, "sending\n", "");
      //printf("sending again %s %s to %s : %d\n", preqoritype[m_reqoritype], pmsgtype[m_msgtype], m_pchIP, m_uiPort);
      
      //Send the data to the remote host
      m_pobjTransport->Send(m_buf, m_iSize, m_pchIP, m_uiPort, m_eTransport);
      
      //printf("before time sec: %ld usec: %ld\n", m_nTime.tv_sec, m_nTime.tv_usec);
      //next time
      m_nTime = addtimeval(curr_time, (m_iRetrans*_T1)/1000, 0);

      //printf("after time sec: %ld usec: %ld\n", m_nTime.tv_sec, m_nTime.tv_usec);

      return 1;
    }
    break;
  
  case eT_WAIT_RESP:
    //Check if complete transaction has expired
    difft = difftimeval(m_eTime, curr_time);
  
    //transaction has expired, return immediately
    if(0 == difft.tv_sec && 0 == difft.tv_usec) {
      m_State = eT_FAILURE;
      return 0;
    }
    break;

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

}//OnTimer



int32 Transaction::Send(uchar* buf, int32 size, char8* pchIP, uint32 port) {

  struct timeval curr_time;

  //Send the data to the remote host
  m_pobjTransport->Send(buf, size, pchIP, port, m_eTransport);
  
  
  //Copy the data into localbuf and update size, IP and port
  memcpy(m_buf, buf, size);

  m_iSize = size;
  strncpy(m_pchIP, pchIP, IPADDRLEN);
  m_uiPort = port;


  //Setup the timers
  gettimeofday(&curr_time, NULL);

  //next time
  m_nTime = addtimeval(curr_time, 0, _T1*1000);

  //expire time
  m_eTime = addtimeval(curr_time, _T2, 0);

  //State
  m_State = eT_TRANS_MSG;
  
  return 1;

}//Send



int32 Transaction::OnACK(struct message& msg) {

  struct timeval curr_time;

  TRACE(2, "Transaction::OnACK...OnACK called\n", "");

  m_State = eT_WAIT_RESP;

  //expire time
  gettimeofday(&curr_time, NULL);
  m_eTime = addtimeval(curr_time, _T3, 0);

  return 1;

}//OnReceive


int32 Transaction::OnReceive(struct message& msg) {

  return 1;

}//OnReceive



string Transaction::getTransId() {

  return m_srcId;

}//getTransId

