/**
* ll-wz.h
*
* Implemented ACK Contrller for Wireless TCP.  It is used to target the issues arised by large RTT variation in wireless links.
*   See Wan's master's thesis for detail.
*/

#ifndef ns_ll_WZ_h
#define ns_ll_WZ_h

#include <ll.h>
#include <list>

using namespace std;

struct PacketInfo
{
	int m_iSeqno;
	double m_dSendTime;     //which is also the time when data packet was recieved at BS.
	double m_dAckTime;
    int m_iNumOfRtm;
    int m_iNumOfDupAcks;

	PacketInfo(int _iSeqno, double _dSendTime)
        : m_iSeqno(_iSeqno), m_dSendTime(_dSendTime)
    {
        m_dAckTime = -1;        //time ACL received.
        m_iNumOfRtm = 0;        //number of retransmissions.
        m_iNumOfDupAcks = 0;    //number of dup-acks.
    }
};

//packet are queued when wireless link is down.
/*struct QueuedPacketInfo
{
	Packet* m_pPacket;
    Handler* m_pHandler;

	QueuedPacketInfo(Packet * _p, Handler * _h)
        : m_pPacket(_p), m_pHandler(_h)
    {
    }
};*/


class LLWzACTimerHandler;
class LLWzWirelessUpTimerHandler;

/**
* Ack Controller for Wireless TCP implemented as a link layer solution with TCP awareness.
*/
class LLWz : public LL {	
	friend class LLWzACTimerHandler;
    friend class LLWzWirelessUpTimerHandler;
    
public:
	LLWz();
	~LLWz();

	virtual void recv(Packet* p, Handler* h);
    
protected:
    double  m_dLastRTT;  //wan not used!!  records the last RTT value.
    int enableAckControl_;  //enable the ack control

    list<PacketInfo> m_lstWiredDataPkt;  //list container for character elements
    Packet* m_pktSampleWirelessAck; //sample wireless ack packet used to generate other acks.
    PacketInfo* m_piNextWiredDataToSend; //the pointer to the packet info of the next wired data packet to send.
    int m_iLastWirelessAck; //last ack number from  wireless end.
    double m_iLastWirelessRcvTime;  //last ack recieved time.
    double m_iWirelessAckRcvAvg;
    int m_iLastAckSent; //last ack number send back to sender.
    double m_dLastAckSentTime;
    LLWzACTimerHandler* m_acTimer;    //ack control timer used to schedule ack to be sent back to sender.
    Event* m_actmPending_;	//pending timeouts
	float m_fWiredDataRate;	//pending timeouts
    int m_iNumOfWiredDataPacketDroped;  //number of retransmitted wireline data packet droped.

    //these are for data queue when wireless link is down.
    list<QueuedPacketInfo> m_lstDelayedWiredDataPkt;  //this is used to queue the packet received when wireless link is done.
    //del double m_dWirelessDownTime;
    //double m_dWirelessDownDuration;
	Event* m_wutmPending_;	//pending timeouts
    LLWzWirelessUpTimerHandler* m_wirelessUpTimer;

	double  m_dSrtt;		/* smoothed rtt estimate */
	double  m_dRttvar;	/* linear deviation */
	double  m_dG;		/* gain in EWMA for srtt_ and rttvar_ */
    TracedInt ackqueuesize_;

    //this number is actually the number of DupAcks to skip before send.  So the redefined DupShresh = m_iRedefine3DupAck + 2.
    int m_iRedefine3DupAck;     
    bool m_bLastAckSent3Dup;    //indicate if the last ack sent is a 3-dup ack.

    //ACK Filter
    int m_iNumOfLastDupAck;
    
private:
	void recordPacket(int iSeqno);
    int receiveWirelessAck2(Packet* p);
    int receiveWirelessAck(Packet* p, Handler *h);
    PacketInfo* getAckedPktSendTime(int iAck);
    double clearDataBuf(int iAck);
    bool updateNextWiredDataToSend(PacketInfo* pNextAck = NULL);
    void calcRtt(double dSendTime);
    /**
    * Construct and transmit a ack packet to sender with ack of iAckToTransmit.
    */
    void sendNextAck();
	double nextAckTime();  //returns the time to send next ack.
    void updateWiredDataRate(int iSeqno, double dRecvTime);

    bool handleWirelessLinkDown(Packet *p, Handler *h);
    void sendQueuedPacketOnWirelessLink();    

    void forwardAck(Packet * p, Handler *h);
    void myRecv(Packet *p, Handler *h, bool bDelayedPacket);
};

/**
* The timer class implimented handle() method to send next ack to FH.
*/
class LLWzACTimerHandler : public Handler {
public:
    LLWzACTimerHandler() : m_llwz(NULL) {}
	LLWzACTimerHandler(LLWz *_wz) : m_llwz(_wz) {}

    void handle(Event *event);
    
protected:
    LLWz *m_llwz;   //the LLWz object which has this timer.
};

/**
* The timer class implimented handle() method to send queued data packet to MH after wireless link is up.
*/
class LLWzWirelessUpTimerHandler : public Handler {
public:
    LLWzWirelessUpTimerHandler() : m_llwz(NULL) {}
	LLWzWirelessUpTimerHandler(LLWz *_wz) : m_llwz(_wz) {}

    void handle(Event *event);

protected:
    LLWz *m_llwz;   //the LLWz object which has this timer.
};


#endif
