/*
 * Copyright (c) 2020 Orange Labs
 *
 * SPDX-License-Identifier: GPL-2.0-only
 *
 * Authors: Rediet <getachew.redieteab@orange.com>
 *          Sébastien Deronne <sebastien.deronne@gmail.com> (for logic ported from wifi-phy)
 *          Mathieu Lacage <mathieu.lacage@sophia.inria.fr> (for logic ported from wifi-phy)
 */

#ifndef DSSS_PHY_H
#define DSSS_PHY_H

#include "ns3/phy-entity.h"

#include <vector>

/**
 * @file
 * @ingroup wifi
 * Declaration of ns3::DsssPhy class.
 */

namespace ns3
{

/**
 * @brief PHY entity for HR/DSSS (11b)
 * @ingroup wifi
 *
 * Refer to IEEE 802.11-2016, clause 16 (HR/DSSS).
 * Note that DSSS rates (clause 15) are a subset
 * of HR/DSSS rates.
 */
class DsssPhy : public PhyEntity
{
  public:
    /**
     * Constructor for HR/DSSS PHY
     */
    DsssPhy();
    /**
     * Destructor for HR/DSSS PHY
     */
    ~DsssPhy() override;

    WifiMode GetSigMode(WifiPpduField field, const WifiTxVector& txVector) const override;
    const PpduFormats& GetPpduFormats() const override;
    Time GetDuration(WifiPpduField field, const WifiTxVector& txVector) const override;
    Time GetPayloadDuration(uint32_t size,
                            const WifiTxVector& txVector,
                            WifiPhyBand band,
                            MpduType mpdutype,
                            bool incFlag,
                            uint32_t& totalAmpduSize,
                            double& totalAmpduNumSymbols,
                            uint16_t staId) const override;
    Ptr<WifiPpdu> BuildPpdu(const WifiConstPsduMap& psdus,
                            const WifiTxVector& txVector,
                            Time ppduDuration) override;
    uint32_t GetMaxPsduSize() const override;

    /**
     * Initialize all HR/DSSS modes.
     */
    static void InitializeModes();
    /**
     * Return a WifiMode for HR/DSSS
     * corresponding to the provided rate.
     *
     * @param rate the rate in bps
     * @return a WifiMode for HR/DSSS
     */
    static WifiMode GetDsssRate(uint64_t rate);
    /**
     * Return a WifiMode for DSSS at 1 Mbps.
     *
     * @return a WifiMode for DSSS at 1 Mbps
     */
    static WifiMode GetDsssRate1Mbps();
    /**
     * Return a WifiMode for DSSS at 2 Mbps.
     *
     * @return a WifiMode for DSSS at 2 Mbps
     */
    static WifiMode GetDsssRate2Mbps();
    /**
     * Return a WifiMode for HR/DSSS at 5.5 Mbps.
     *
     * @return a WifiMode for HR/DSSS at 5.5 Mbps
     */
    static WifiMode GetDsssRate5_5Mbps();
    /**
     * Return a WifiMode for HR/DSSS at 11 Mbps.
     *
     * @return a WifiMode for HR/DSSS at 11 Mbps
     */
    static WifiMode GetDsssRate11Mbps();

    /**
     * Return the WifiCodeRate from the DSSS or HR/DSSS mode's unique
     * name using ModulationLookupTable. This is mainly used as a
     * callback for WifiMode operation.
     *
     * @param name the unique name of the DSSS or HR/DSSS mode
     * @return WifiCodeRate corresponding to the unique name
     */
    static WifiCodeRate GetCodeRate(const std::string& name);
    /**
     * Return the constellation size from the DSSS or HR/DSSS mode's
     * unique name using ModulationLookupTable. This is mainly used
     * as a callback for WifiMode operation.
     *
     * @param name the unique name of the DSSS or HR/DSSS mode
     * @return constellation size corresponding to the unique name
     */
    static uint16_t GetConstellationSize(const std::string& name);
    /**
     * Return the data rate corresponding to
     * the supplied TXVECTOR.
     * This function is mainly used as a callback
     * for WifiMode operation.
     *
     * @param txVector the TXVECTOR used for the transmission
     * @param staId the station ID (only here to have a common signature for all callbacks)
     * @return the data bit rate in bps.
     */
    static uint64_t GetDataRateFromTxVector(const WifiTxVector& txVector, uint16_t staId);
    /**
     * Return the data rate from the DSSS or HR/DSSS mode's unique name and
     * the supplied parameters. This function is mainly used as a callback
     * for WifiMode operation.
     *
     * @param name the unique name of the DSSS or HR/DSSS mode
     * @param modClass the modulation class, must be either WIFI_MOD_CLASS_DSSS or
     * WIFI_MOD_CLASS_HR_DSSS
     *
     * @return the data bit rate of this signal in bps.
     */
    static uint64_t GetDataRate(const std::string& name, WifiModulationClass modClass);
    /**
     * Check whether the combination in TXVECTOR is allowed.
     * This function is used as a callback for WifiMode operation.
     *
     * @param txVector the TXVECTOR
     * @returns true if this combination is allowed, false otherwise.
     */
    static bool IsAllowed(const WifiTxVector& txVector);

  private:
    PhyFieldRxStatus DoEndReceiveField(WifiPpduField field, Ptr<Event> event) override;
    Ptr<SpectrumValue> GetTxPowerSpectralDensity(Watt_u txPower,
                                                 Ptr<const WifiPpdu> ppdu) const override;
    MHz_u GetRxChannelWidth(const WifiTxVector& txVector) const override;
    MHz_u GetMeasurementChannelWidth(const Ptr<const WifiPpdu> ppdu) const override;

    /**
     * @param txVector the transmission parameters
     * @return the WifiMode used for the PHY header field
     */
    WifiMode GetHeaderMode(const WifiTxVector& txVector) const;

    /**
     * @param txVector the transmission parameters
     * @return the duration of the PHY preamble field
     *
     * @see WIFI_PPDU_FIELD_PREAMBLE
     */
    Time GetPreambleDuration(const WifiTxVector& txVector) const;
    /**
     * @param txVector the transmission parameters
     * @return the duration of the PHY header field
     */
    Time GetHeaderDuration(const WifiTxVector& txVector) const;

    /**
     * End receiving the header, perform DSSS-specific actions, and
     * provide the status of the reception.
     *
     * @param event the event holding incoming PPDU's information
     * @return status of the reception of the header
     */
    PhyFieldRxStatus EndReceiveHeader(Ptr<Event> event);

    /**
     * Create a DSSS or HR/DSSS mode from a unique name, the unique name
     * must already be contained inside ModulationLookupTable.
     * This method binds all the callbacks used by WifiMode.
     *
     * @param uniqueName the unique name of the WifiMode
     * @param modClass the modulation class of the WifiMode, must be either WIFI_MOD_CLASS_DSSS or
     * WIFI_MOD_CLASS_HR_DSSS
     * @return the DSSS or HR/DSSS WifiMode
     */
    static WifiMode CreateDsssMode(std::string uniqueName, WifiModulationClass modClass);

    static const PpduFormats m_dsssPpduFormats; //!< DSSS and HR/DSSS PPDU formats

    static const ModulationLookupTable
        m_dsssModulationLookupTable; //!< lookup table to retrieve code rate and constellation size
                                     //!< corresponding to a unique name of modulation
};

} // namespace ns3

#endif /* DSSS_PHY_H */
