/*
 * 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.
 */

#ifndef _MSG_HEADER_H
#define _MSG_HEADER_H

#ifndef _WENGO
#include "types.h"
#include "socketi.h"
#include "bigint.h"
#endif

#ifdef _WENGO
#include "p2pp/common/types.h"
#include "p2pp/net/socketi.h"
#include "p2pp/bigint/bigint.h"
#endif

#include <stdio.h>
#include <string.h>
#include <list>

using namespace std;


#define IDMAX 64
#define ADDRMAX 255
#define HASHLEN 512
#define CERTLEN 1000


extern int idlen;

const char pmsgtype [][20] = {"Request", "Indication", "Response", "ResponseACK"};
enum msgtype {eREQUEST=0, eINDICATION, eRESPONSE, eRESPONSEACK};

const char pnodetype [][20] = {"Client", "Peer"};
//enum nodetype {eCLIENT=0, ePEER=1};

const char prouttype[][20] = {"Iterative", "Recursive"};
enum routtype {eITERATIVE=0, eRECURSIVE=1};

const char pcontent_type[][20] = {"User-Info", "STUN", "STUN+TURN", "STURN+TURN+ICE", "STRINGVAL", "SIP-CONTACT", "eSTUN_PORT"};
enum content_type {eUSERINFO=0, eSTUN, eTURN, eSTUN_TURN_ICE, eSTRINGVAL, eSIP, eSTUN_PORT};

enum reqoritype {eENROLL=0, eAUTHENTICATE, eBOOTSTRAP, eJOIN, eLEAVE, 
              eKEEPALIVE, eLOOKUPPEER, eEXCHANGETABLE, eQUERY, 
              ePUBLISHOBJECT, eLOOKUPOBJECT, eREMOVEOBJECT, 
              eREPLICATE, eTRANSFER, eTUNNEL, eCONNECT, eGETDIAGNOSTICS, eSET, eRESET};

const char preqoritype[][20] = {"Enroll", "Authenticate", "Bootstrap", "Join", "Leave", 
                             "Keep-alive", "LookupPeer", "ExchangeTable", "Query",
                             "PublishObject", "LookupObject", "RemoveObject", 
                             "Replicate", "Transfer", "Tunnel", "Connect", "GetDiagnostics", "Set", "Reset",};


enum objtype {ePEERINFO=0, ePEERID, eADDRESSINFO, eUNHASHEDID, eUPTIME, 
              eP2POPTIONS, eREQUESTOPTIONS, eDIAGNOSTICSOPTIONS, 
              eROUTINGTABLE, eNEIGHBORTABLE, ePLOOKUP, 
              eRESOURCEID, eRLOOKUP, eRESOURCEOBJECT, eEXPIRES, eOWNER,
              eCSR, eX509, eSIGNATURE, 
              eTIMEWINDOW, eCONNECTIONS, eNODERESOURCEUTIL, eMSGRCVD, eAS,
              eERROR, eRESOURCEOBJECTVALUE, eDIAGNOSTICS, 
              eBW, eRTT, eCPUUTIL, eMEMORY, eNODEVAL, eTURNALLOC, eRELAYLIST};


const char pobjtype[][20]={"PEERINFO", "PEERID", "ADDRESSINFO", "UNHASHEDID", "UPTIME", 
                            "P2POPTIONS", "REQUESTOPTIONS", "DIAGNOSTICSOPTIONS", 
                           "ROUTINGTABLE", "NEIGHBORTABLE", "PLOOKUP", 
                           "RESOURCEID", "RLOOKUP", "RESOURCEOBJECT", "EXPIRES", "OWNER",
                           "CSR", "X509", "SIGNATURE", 
                           "TIMEWINDOW", "CONNECTIONS", "NODERESOURCEUTIL", "MSGRCVD", 
                           "AS", "ERROR", "RESOURCEOBJECTVALUE", "DIAGNOSTICS", "BW", "RTT",
                           "CPUUTIL", "MEMORY", "NODEVAL", "TURNALLOC", "RELAYLIST"};


enum addrtype {eHOST=0, eSERVERREFLEXIVE, ePEERREFLEXIVE, eRELAYED};

//const char paddrtype[][20] = {"host", "server-reflexive", "peer-reflexive", "relayed"};
const char paddrtype[][30]= {"host", "server-reflexive", "peer-reflexive", "relayed"}; 


enum halg {eNONE=0, eA_SHA1, eA_SHA256, eA_SHA512, eA_MD4, eA_MD5};

const char phalg [][10] = {"None", "SHA1", "SHA256", "SHA512", "MD4", "MD5"};


enum p2palg {eCHORD=0, eCAN=1, eKADEMLIA=2, ePASTRY=3, eBAMBOO=4, eTAPESTRY=5, eACCORDION=6, 
             eSKIPNET=7, eMERCURY=8, eGIA=9};

const char pp2palg[][20] = {"Chord", "CAN", "Kademlia", "Pastry", "Bamboo", "Tapestry",
                            "Accordion", "Skipnet", "Mercury", "Gia"};

struct common_hdr {  
  uint32 version:2;
  uint32 msgtype:2;
  uint32 ack:1;
  uint32 porc:1;
  uint32 rori:1;
  uint32 respcode:9;
  uchar  reqoritype;
  uchar  ttl;
  
  uint32 magic_cookie;
  uint32 transid;
  uint32 length;

  uchar srcid[HASHLEN];
  uchar respid[HASHLEN];
  uint32 slen;
  uint32 rlen;

public:
  common_hdr();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
  string getTransId();
};


struct obj_hdr {

  uchar objtype;  
  
  uchar A:1;
  uchar B:1;

  uchar r1:6;

  uint16 length;  

public:
  void Initialize();
  int encode(uchar* buf, int size, int& cur);
  int parse(uchar* buf, int size, int& cur);
};


struct obj {
  struct obj_hdr stobj;
  int isPresent;

  obj() {
    stobj.A=0;
    stobj.B=0;
    stobj.objtype=0;
    stobj.length=0;
    isPresent=0;
  }
  
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
};



struct csr:obj {
  uchar certreq[CERTLEN];
public:
  csr();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);

};


struct x509:obj {
  uchar cert[CERTLEN];  
public:
  x509();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);  
};


struct signature:obj{
  
  uchar sign[CERTLEN];
public:
  signature();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
};

struct expires:obj {

  uint32 utime;

public:

  expires();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);  

};


struct uptime:obj {

  uint32 utime;

public:

  uptime();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
  
};


struct bw:obj {
  uint32 sbw;
  uint32 rbw;
  uchar ismach; //bw is for program or machine

public:

  bw();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
  
};

struct cpuutil:obj {
  uint16 cpuusage;
  uchar ismach; //bw is for program or machine

public:

  cpuutil();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
  
};

struct memory:obj {
  uint32 mem;
  uchar ismach; //bw is for program or machine

public:

  memory();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
  
};


struct unhashedid:obj {

  uchar unhashed[HASHLEN];

public:

  unhashedid();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
  
};


struct peerid:obj {
  uchar id[HASHLEN];

public:

  peerid();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
};


struct resourcelist:obj{
  uchar num;
  list<uchar> lrestype;

public:
  resourcelist();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
};

struct addressinfo:obj {

  uchar num;
  uchar  R[16];
  uchar  ipver[16];
  uchar  foundation[16];
  uchar  compid[16];
  uint32 priority[16];
  uchar  ht[16];
  uchar  tt[16];
  uint16 port[16];
  char8  addr[16][IPADDRLEN];  
  uint16 rport[16];
  char8  raddr[16][IPADDRLEN];

public:
  addressinfo();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
};



struct requestoptions:obj {
  uchar p:1; //parallel lookups
  uchar r:1; //request routing table
  uchar n:1; //request neighbor table
  uchar e:1; //in seperate request
  uchar a:1; //partial reply
  uchar s:1; //request sent to immediate neighbors of the newly
             //joining peer
  uchar l:1; //route log
  

public:
  requestoptions();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
};


struct diagnosticsoptions:obj {
  uchar r:1; //request routing table
  uchar n:1; //request neighbor table
  uchar e:1; //resource table
  uchar bwf:1; //bw flag
  uchar rl:1; //relaylist flag
  uchar ta:1; //TURN allocations flag

public:
  diagnosticsoptions();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
};


struct p2poptions:obj {
  //uint32 r:2;
  uint32 halg;
  uint32 halglen;
  uint32 p2palg;
  uint32 hbase;
  uint32 oidlen;
  uchar  oid[255];

public:
 
  p2poptions();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);  

};



struct timewindow:obj {

  uint32 utime;

public:

  timewindow();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);  

};

struct asnumber:obj {
  uint32 as;

public:
  asnumber();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);  
};


struct connections:obj {
  uint16 numneighbor;
  uint16 numrout;
  uint16 numclients;

public:
  connections();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);  
};


struct noderesutil:obj {
  uint32 peerbw;
  uchar cpuutil;
  uchar bwutil;

public:
  noderesutil();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);  
};


struct msgsrcvd:obj {
  uchar  msgtype[20];
  uint32 rcvd[20];

public:
  msgsrcvd();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);  
};


struct rtt:obj {

  uint32 utime;

public:

  rtt();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);  

};


struct peerinfo:obj {

  //uchar peerid[HASHLEN];  

  struct peerid stpeerid;
  struct unhashedid stunhashed;
  struct uptime stuptime;
  struct addressinfo staddr;
  struct resourcelist streslist;
  struct x509 stx509;
  struct rtt strtt;

public:
  peerinfo();
  //peerinfo(const peerinfo& lstpeer);
  bool operator < (peerinfo& rhs) {
    BigInt rhs_bigint, my_bigint;
    uchar_to_bigint((uchar*)stpeerid.id, idlen, my_bigint);
    uchar_to_bigint((uchar*)rhs.stpeerid.id, idlen, rhs_bigint);
    return my_bigint < rhs_bigint;
  }
 
  bool operator == (peerinfo rhs) {
    BigInt rhs_bigint, my_bigint;
    uchar_to_bigint((uchar*)stpeerid.id, idlen, my_bigint);
    uchar_to_bigint((uchar*)rhs.stpeerid.id, idlen, rhs_bigint);
    return (my_bigint == rhs_bigint);
  }
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
  void Initialize();

  //peerinfo& operator=(const peerinfo& lstpeer);

};

struct plookup:obj{
  uchar num;
  uchar E:1;
  uchar R:1;

  struct peerid stida;
  struct peerid stidb;

public:
  plookup();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
};


struct resourceobjectvalue:obj {
  uchar value[HASHLEN];

public:
  resourceobjectvalue();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
};

struct owner:obj {
  uchar id[HASHLEN];

public:
  owner();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
};

struct resourceid:obj {
  uchar id[HASHLEN];

public:

  resourceid();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
};


struct rlookup:obj {
  uchar conttype;
  uchar subtype;  
  
  struct resourceid stresid;
  struct owner stowner;
  struct peerinfo stpeerinfo;
  struct unhashedid stunhashedid;

  public:
  rlookup();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
};


struct resourceobject:obj {
  uchar conttype;
  uchar subtype;  

  //storing and management of raw buffer
  uchar rbuf[BUFSIZE];
  int32 rbuflen;
  uchar isrbuf;

  struct resourceid stresid;
  struct owner stowner;
  struct peerinfo stpeerinfo;  
  struct unhashedid stunhashedid;
  struct signature stsignature;
  struct expires stexpires;
  struct x509 stx509;
  struct resourceobjectvalue strov;
  struct addressinfo staddr;

 public:
  resourceobject();
  void Initialize();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
};


struct routingtable:obj {
  uchar num;
  list<peerinfo> table;

public:
  routingtable();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);  
};


struct neighbortable:obj {
  uchar num;
  list<peerinfo> table;

public:
  neighbortable();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);  
};

struct turnalloc:obj {

  uint16 relayport;
  struct bw stbw;
  struct addressinfo staddr;

public:
  turnalloc();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar* buf, int size, int& cur);
};

struct diagnosticsobject:obj {
  struct neighbortable stnt;
  struct routingtable strt;
  list <resourceobject> lstro;
  struct bw stbw;             //current send and receive bw of the program
  struct cpuutil stcpuutil;   //program cpu utilization
  struct cpuutil sttcpuutil;  //total cpu utilization
  list <struct turnalloc> stlturnalloc;
  list <struct peerinfo> stlrelaylist;

  public:
  diagnosticsobject();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar*buf, int size, int& cur);
};


struct nodeval:obj {
  //program bandwidth, cpuutilization, memory
  struct bw stbw;
  struct cpuutil stcpuutil;
  struct memory stmem;

  //total bandwidth, total cpuutilization, total memory
  struct bw sttbw;
  struct cpuutil sttcpuutil;
  struct memory sttmem;

public:
  nodeval();
  int parse(uchar* buf, int size, int& cur);
  int encode(uchar*buf, int size, int& cur);
};

struct message {

  struct common_hdr stcmn_hdr;
  struct obj_hdr stobj_hdr;

  struct peerinfo stpeerinfo;
  list<peerinfo> stlpeerinfo;
  struct expires stexpires;  
  struct p2poptions stp2poptions;
  struct requestoptions streqoptions;
  struct routingtable strt;
  struct neighbortable stnt;  
  list<resourceobject> lstro;
  struct plookup stpl;
  struct rlookup strl;
  struct diagnosticsoptions stdiagoptions;
  struct diagnosticsobject stdiagnostics;
  struct nodeval stnodeval;

public:
  message();
  void Initialize();
  int parse(uchar* buf, int size);
  int encode(uchar* buf, int size);

  string getTransId();

};


#endif
