/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
 * Author: Yu Cao <caoyu08@csnet1.cs.tsinghua.edu.cn>
 */

#ifndef NAMPT_SUBFLOW_H
#define NAMPT_SUBFLOW_H

#include <stdint.h>
#include <queue>
#include "ns3/callback.h"
#include "ns3/ptr.h"
#include "ns3/packet.h"
#include "ns3/ipv4-address.h"
#include "ns3/net-device.h"
#include "nampt-l4-protocol.h"
#include "nampt-socket.h"


namespace ns3 {

class TcpSocketBase;
class TcpHeader;

typedef Callback <void, Ptr<NaMPTSubflow>, Ptr<NaMPTCC> > EnterCWRCallback;

class NaMPTDSN : public Object {
public:
  static TypeId GetTypeId (void);
  NaMPTDSN (uint32_t dataSeq, uint32_t dataLen, uint32_t sfSeq);
  virtual ~ NaMPTDSN (void);
  
  static const uint32_t MaxSize = 32768;

  SequenceNumber32	m_dataSeq;
  uint32_t			m_dataLen;
  SequenceNumber32	m_sfSeq;
  bool				m_bAdvertized;
  SequenceNumber32	m_seqTag;
  SequenceNumber32	m_sfEnd;
  
};


/**
 * \ingroup tcp
 * \brief A sublayer between NaMPTSocket and NaMPTL4Protocol
 * 
 * XXX
*/
typedef std::map<SequenceNumber32, Ptr<NaMPTDSN> > DSNDB_t;

class NaMPTSubflow : public NaMPTL4Protocol {
public:
  static TypeId GetTypeId (void);
  /**
   * \brief Constructor
   */
  NaMPTSubflow ();
  virtual ~NaMPTSubflow ();

private:
friend class TcpSocketBase;
friend class NaMPTSocket;

  // mimic TcpBaseSocket 
  void ForwardUp (Ptr<Packet> packet, Ipv4Header header, 
                      uint16_t port, Ptr<Ipv4Interface> incomingInterface);
  void Destroy (void);
  // mimic TcpL4Protocol. We do not mimic Allocate(), because it is invoked before subflow setups.
  virtual void SendPacket (Ptr<Packet>, const TcpHeader &,
  			Ipv4Address, Ipv4Address, Ptr<NetDevice> oif = 0);
  virtual void DeAllocate (Ipv4EndPoint *endPoint);

  // subflow-related
  Ptr<NaMPTSignal> SendSignal(TcpOptionType_t sigType);
  uint32_t Send(Ptr<Packet> p, const SequenceNumber32& dataSeq);
  uint32_t PeekData(SequenceNumber32& dataSeq);
  Ptr<Packet> Recv(uint32_t maxSize, SequenceNumber32& dataSeq);
  void Close(void);
  void OutputInfo(void);
  void ReceiveDSN(uint32_t dataSeq, uint32_t dataLen, uint32_t sfSeq);
  uint32_t FreeSizeOfIngoingQueue(void);
  uint32_t FreeSizeOfOutgoingQueue(void);
  uint32_t BacklogOfOutgoingQueue(void);
  uint32_t FlightingOfOutgoingQueue(void);
  uint32_t FreeSizeOfSendingWindow(void);
  uint32_t SegmentSize(void);
  uint32_t SegmentRound(uint32_t size);
  

  Ptr<TcpSocketBase> 			m_baseSocket;
  Ptr<NaMPTSocket>				m_namptSocket;
  Ptr<NaMPTL4Protocol>			m_tcp;
  Ptr<RttMeanDeviation>			m_rtt;
  bool							m_bAvailable;
  bool							m_bBypassSending;
  Ipv4Address					m_localAddress;
  Ipv4Address					m_peerAddress;
  std::deque<Ptr<NaMPTSignal> >	m_signalQueue;
  DSNDB_t						m_localDSN;
  DSNDB_t						m_peerDSN;
  SequenceNumber32				m_nextRescheduling;// seq more than or equal to it can be re-scheduling

  Time							m_sampleRTT; // last sample rtt
  Time							m_baseRTT; // min sample rtt observed
  
  SequenceNumber32				m_begSeq; // tag the start point of RTT
  Time							m_minRTT; // min sample rtt during last RTT
  uint32_t						m_cnRTT; // the number of sample rtts during last RTT
  uint64_t						m_sumRTT; // the sum of sample rtts during last RTT, us
  
  uint64_t						m_rounds;
  uint32_t						m_cnAcks; // the number of new acks, used to determine a round
  uint32_t						m_refWin; // used to determine a round

  double						m_gamma; // threshold, when above it, bi-increase exits.
  double						m_weight;
  double						m_equilibrium;
  double						m_instantRate;
  uint32_t					m_minQueueDelay; // us

  uint32_t					m_nCE;
  uint32_t					m_nECE;
  double						m_marking;
  uint32_t					m_cwr; // 0: disable, 1: normal, 2: cwr
  SequenceNumber32			m_cwrHighSeq; // used to determine when to quit from cwr
  EnterCWRCallback			m_enterCWR; // callback functions
  double						m_incCum;
   
  uint64_t					m_cnIncreased;
  uint64_t					m_cnDecreased;
  uint64_t					m_cnUnchanged;

  Time						m_startTime;
  uint64_t					m_rcvPkts;
  uint64_t					m_rcvBytes;
  uint64_t					m_goodBytes;
  uint64_t					m_signalBytes;

  uint64_t					m_cnTimeout;
  uint64_t					m_cnFastRetrans;
  uint64_t					m_cnRescheduling;
  uint64_t					m_byteRescheduling;
  uint64_t					m_sndPackets;  
};

}; // namespace ns3

#endif /* NAMPT_SUBFLOW_H */
