/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2009, 2010 MIRKO BANCHI
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as 
 * published by the Free Software Foundation;
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Author: Mirko Banchi <mk.banchi@gmail.com>
 * Author: Tommaso Pecorella <tommaso.pecorella@unifi.it>
 */
#ifndef ORIGINATOR_BLOCK_ACK_AGREEMENT_H
#define ORIGINATOR_BLOCK_ACK_AGREEMENT_H

#include "block-ack-agreement.h"

namespace ns3 {

/* \brief Maintains the state and information about transmitted MPDUs with ack policy block ack
 *        for an originator station.
 */
class OriginatorBlockAckAgreement : public BlockAckAgreement
{
  friend class BlockAckManager;
public:
  OriginatorBlockAckAgreement ();
  OriginatorBlockAckAgreement (Mac48Address recipient, uint8_t tid);
  ~OriginatorBlockAckAgreement ();
  /*                                      receive ADDBAResponse
   *  send ADDBARequest ---------------   status code = success  ---------------
   *  ----------------->|   PENDING    |------------------------>|  ESTABLISHED |-----
   *                    ---------------                          ---------------      |
   *                          |                                    /   ^    ^         |
   *   receive ADDBAResponse  |                receive BlockAck   /    |    |         | receive BlockAck
   *   status code = failure  |           retryPkts + queuePkts  /     |    |         | retryPkts + queuePkts
   *                          v                     <           /      |    |         |           >=
   *                   ---------------     blockAckThreshold   /       |    |         | blockAckThreshold
   *                   | UNSUCCESSFUL |                       /        |    |         |
   *                   ---------------                       v         |    ----------|
   *                                            --------------         |      
   *                                            |  INACTIVE   |        |  
   *                                            --------------         |
   *                        send a MPDU (Normal Ack)   |               |
   *                        retryPkts + queuePkts      |               |
   *                                  >=               |               |
   *                         blockAckThreshold         |----------------
   */                    
   /**
   * Represents the state for this agreement.
   *
   *  PENDING:
   *    If an agreement is in PENDING state it means that an ADDBARequest frame was sent to
   *    recipient in order to setup the block ack and the originator is waiting for the relative
   *    ADDBAResponse frame.
   *  
   *  ESTABLISHED:
   *    The block ack is active and all packets relative to this agreement are transmitted
   *    with ack policy set to block ack.
   *  
   *  INACTIVE:
   *    In our implementation, block ack tear-down happens only if an inactivity timeout occurs
   *    so we could have an active block ack but a number of packets that doesn't reach the value of
   *    m_blockAckThreshold (see ns3::BlockAckManager). In these conditions the agreement becomes
   *    INACTIVE until that the number of packets reaches the value of m_blockAckThreshold again.
   *
   *  UNSUCCESSFUL (not used for now):
   *    The agreement's state becomes UNSUCCESSFUL if:
   *     
   *    - its previous state was PENDING and an ADDBAResponse frame wasn't received from
   *      recipient station within an interval of time defined by m_bAckSetupTimeout attribute
   *      in ns3::WifiMac.
   *    - an ADDBAResponse frame is received from recipient and the Status Code field is set
   *      to failure.
   *    
   *    In both cases for station addressed by BlockAckAgreement::m_peer and for
   *    TID BlockAckAgreement::m_tid block ack mechanism won't be used.
   */
  enum State {
    PENDING,
    ESTABLISHED,
    INACTIVE,
    UNSUCCESSFUL
  };
  void SetState (enum State state);
  bool IsPending (void) const;
  bool IsEstablished (void) const;
  bool IsInactive (void) const;
  bool IsUnsuccessful (void) const;
  /**
   * Notifies a packet's transmission with ack policy Block Ack.
   */
  void NotifyMpduTransmission (uint16_t nextSeqNumber);
  /**
   * Returns true if all packets for which a block ack was negotiated have been transmitted so
   * a block ack request is needed in order to acknowledge them.
   */
  bool IsBlockAckRequestNeeded (void) const;
  void CompleteExchange (void);

private:
  enum State m_state;
  uint16_t m_sentMpdus;
  bool m_needBlockAckReq;
};

} //namespace ns3

#endif /* ORIGINATOR_BLOCK_ACK_AGREEMENT_H */
