/*
 * Copyright (c) 2010 TELEMATICS LAB, DEE - Politecnico di Bari
 *
 * SPDX-License-Identifier: GPL-2.0-only
 *
 * Author: Giuseppe Piro  <g.piro@poliba.it>
 * Author: Marco Miozzo <marco.miozzo@cttc.es>
 */

#ifndef LTE_CONTROL_MESSAGES_H
#define LTE_CONTROL_MESSAGES_H

#include "ff-mac-common.h"
#include "lte-rrc-sap.h"

#include "ns3/ptr.h"
#include "ns3/simple-ref-count.h"

#include <list>

namespace ns3
{

class LteNetDevice;

/**
 * @ingroup lte
 *
 * The LteControlMessage provides a basic implementations for
 * control messages (such as PDCCH allocation map, CQI feedbacks)
 * that are exchanged among eNodeB and UEs.
 */
class LteControlMessage : public SimpleRefCount<LteControlMessage>
{
  public:
    /**
     * The type of the message
     * NOTE: The messages sent by UE are filtered by the
     *  LteEnbPhy::ReceiveLteControlMessageList in order to remove the ones
     *  that has been already handoff by the eNB for avoiding propagation of
     *  spurious messages. When new messaged have to been added, consider to
     *  update the switch statement implementing the filtering.
     */
    enum MessageType
    {
        DL_DCI,
        UL_DCI, // Downlink/Uplink Data Control Indicator
        DL_CQI,
        UL_CQI,        // Downlink/Uplink Channel Quality Indicator
        BSR,           // Buffer Status Report
        DL_HARQ,       // UL HARQ feedback
        RACH_PREAMBLE, // Random Access Preamble
        RAR,           // Random Access Response
        MIB,           // Master Information Block
        SIB1,          // System Information Block Type 1
    };

    LteControlMessage();
    virtual ~LteControlMessage();

    /**
     * @brief Set the type of the message
     * @param type the type of the message
     */
    void SetMessageType(MessageType type);
    /**
     * @brief Get the type of the message
     * @return the type of the message
     */
    MessageType GetMessageType();

  private:
    MessageType m_type; ///< message type
};

// -----------------------------------------------------------------------

/**
 * @ingroup lte
 * The Downlink Data Control Indicator messages defines the RB allocation for the
 * users in the downlink
 */
class DlDciLteControlMessage : public LteControlMessage
{
  public:
    DlDciLteControlMessage();
    ~DlDciLteControlMessage() override;

    /**
     * @brief add a DCI into the message
     * @param dci the dci
     */
    void SetDci(DlDciListElement_s dci);

    /**
     * @brief Get dic information
     * @return dci messages
     */
    const DlDciListElement_s& GetDci();

  private:
    DlDciListElement_s m_dci; ///< DCI
};

// ---------------------------------------------------------------------------

/**
 * @ingroup lte
 * The Uplink Data Control Indicator messages defines the RB allocation for the
 * users in the uplink
 */
class UlDciLteControlMessage : public LteControlMessage
{
  public:
    UlDciLteControlMessage();
    ~UlDciLteControlMessage() override;

    /**
     * @brief add a DCI into the message
     * @param dci the dci
     */
    void SetDci(UlDciListElement_s dci);

    /**
     * @brief Get dic information
     * @return dci messages
     */
    const UlDciListElement_s& GetDci();

  private:
    UlDciListElement_s m_dci; ///< DCI
};

// ---------------------------------------------------------------------------

/**
 * @ingroup lte
 * The downlink CqiLteControlMessage defines an ideal list of
 * feedback about the channel quality sent by the UE to the eNodeB.
 */
class DlCqiLteControlMessage : public LteControlMessage
{
  public:
    DlCqiLteControlMessage();
    ~DlCqiLteControlMessage() override;

    /**
     * @brief add a DL-CQI feedback record into the message.
     * @param dlcqi the DL cqi feedback
     */
    void SetDlCqi(CqiListElement_s dlcqi);

    /**
     * @brief Get DL cqi information
     * @return dlcqi messages
     */
    CqiListElement_s GetDlCqi();

  private:
    CqiListElement_s m_dlCqi; ///< DL CQI
};

// ---------------------------------------------------------------------------

/**
 * @ingroup lte
 * The uplink BsrLteControlMessage defines the specific
 * extension of the CE element for reporting the buffer status report
 */
class BsrLteControlMessage : public LteControlMessage
{
  public:
    BsrLteControlMessage();
    ~BsrLteControlMessage() override;

    /**
     * @brief add a BSR feedback record into the message.
     * @param bsr the BSR feedback
     */
    void SetBsr(MacCeListElement_s bsr);

    /**
     * @brief Get BSR information
     * @return BSR message
     */
    MacCeListElement_s GetBsr();

  private:
    MacCeListElement_s m_bsr; ///< BSR
};

// ---------------------------------------------------------------------------

/**
 * @ingroup lte
 * The downlink DlHarqFeedbackLteControlMessage defines the specific
 * messages for transmitting the DL HARQ feedback through PUCCH
 */
class DlHarqFeedbackLteControlMessage : public LteControlMessage
{
  public:
    DlHarqFeedbackLteControlMessage();
    ~DlHarqFeedbackLteControlMessage() override;

    /**
     * @brief add a DL HARQ feedback record into the message.
     * @param m the DL HARQ feedback
     */
    void SetDlHarqFeedback(DlInfoListElement_s m);

    /**
     * @brief Get DL HARQ information
     * @return DL HARQ message
     */
    DlInfoListElement_s GetDlHarqFeedback();

  private:
    DlInfoListElement_s m_dlInfoListElement; ///< DL info list element
};

// ---------------------------------------------------------------------------

/**
 * @ingroup lte
 *
 * abstract model for the Random Access Preamble
 */
class RachPreambleLteControlMessage : public LteControlMessage
{
  public:
    RachPreambleLteControlMessage();

    /**
     * Set the Random Access Preamble Identifier (RAPID), see 3GPP TS 36.321 6.2.2
     *
     * @param rapid the RAPID
     */
    void SetRapId(uint32_t rapid);

    /**
     *
     * @return the RAPID
     */
    uint32_t GetRapId() const;

  private:
    uint32_t m_rapId; ///< the RAPID
};

// ---------------------------------------------------------------------------

/**
 * @ingroup lte
 *
 * abstract model for the MAC Random Access Response message
 */
class RarLteControlMessage : public LteControlMessage
{
  public:
    RarLteControlMessage();

    /**
     *
     * @param raRnti the RA-RNTI, see 3GPP TS 36.321 5.1.4
     */
    void SetRaRnti(uint16_t raRnti);

    /**
     *
     * @return  the RA-RNTI, see 3GPP TS 36.321 5.1.4
     */
    uint16_t GetRaRnti() const;

    /**
     * a MAC RAR and the corresponding RAPID subheader
     *
     */
    struct Rar
    {
        uint8_t rapId;                    ///< RAPID
        BuildRarListElement_s rarPayload; ///< RAR payload
    };

    /**
     * add a RAR to the MAC PDU, see 3GPP TS 36.321 6.2.3
     *
     * @param rar the rar
     */
    void AddRar(Rar rar);

    /**
     *
     * @return a const iterator to the beginning of the RAR list
     */
    std::list<Rar>::const_iterator RarListBegin() const;

    /**
     *
     * @return a const iterator to the end of the RAR list
     */
    std::list<Rar>::const_iterator RarListEnd() const;

  private:
    std::list<Rar> m_rarList; ///< RAR list
    uint16_t m_raRnti;        ///< RA RNTI
};

// ---------------------------------------------------------------------------

/**
 * @ingroup lte
 * @brief Abstract model for broadcasting the Master Information Block (MIB)
 *        within the control channel (BCCH).
 *
 * MIB is transmitted by eNodeB RRC and received by UE RRC at every radio frame,
 * i.e., every 10 milliseconds.
 *
 * \sa LteEnbRrc::ConfigureCell, LteEnbPhy::StartFrame,
 *     LteUeRrc::DoRecvMasterInformationBlock
 */
class MibLteControlMessage : public LteControlMessage
{
  public:
    /**
     * @brief Create a new instance of MIB control message.
     */
    MibLteControlMessage();

    /**
     * @brief Replace the MIB content of this control message.
     * @param mib the desired MIB content
     */
    void SetMib(LteRrcSap::MasterInformationBlock mib);

    /**
     * @brief Retrieve the MIB content from this control message.
     * @return the current MIB content that this control message holds
     */
    LteRrcSap::MasterInformationBlock GetMib() const;

  private:
    LteRrcSap::MasterInformationBlock m_mib; ///< MIB

    // end of class MibLteControlMessage
};

// ---------------------------------------------------------------------------

/**
 * @ingroup lte
 * @brief Abstract model for broadcasting the System Information Block Type 1
 *        (SIB1) within the control channel (BCCH).
 *
 * SIB1 is transmitted by eNodeB RRC and received by UE RRC at the 6th subframe
 * of every odd-numbered radio frame, i.e., every 20 milliseconds.
 *
 * \sa LteEnbRrc::SetSystemInformationBlockType1, LteEnbPhy::StartSubFrame,
 *     LteUeRrc::DoRecvSystemInformationBlockType1
 */
class Sib1LteControlMessage : public LteControlMessage
{
  public:
    /**
     * @brief Create a new instance of SIB1 control message.
     */
    Sib1LteControlMessage();

    /**
     * @brief Replace the SIB1 content of this control message.
     * @param sib1 the desired SIB1 content
     */
    void SetSib1(LteRrcSap::SystemInformationBlockType1 sib1);

    /**
     * @brief Retrieve the SIB1 content from this control message.
     * @return the current SIB1 content that this control message holds
     */
    LteRrcSap::SystemInformationBlockType1 GetSib1() const;

  private:
    LteRrcSap::SystemInformationBlockType1 m_sib1; ///< SIB1

    // end of class Sib1LteControlMessage
};

} // namespace ns3

#endif // LTE_CONTROL_MESSAGES_H
