// SPDX-License-Identifier: GPL-2.0-only
/*
 * Digital Voice Modem - Common Library
 * GPLv2 Open Source. Use is subject to license terms.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 *  Copyright (C) 2016 Jonathan Naylor, G4KLX
 *  Copyright (C) 2017-2026 Bryan Biedenkapp, N2PLL
 *
 */
/**
 * @defgroup p25_lc Link Control
 * @brief Implementation for the data handling of the TIA-102.BAAA Project 25 standard.
 * @ingroup p25
 * 
 * @file LC.h
 * @ingroup p25_lc
 * @file LC.cpp
 * @ingroup p25_lc
 */
#if !defined(__P25_LC__LC_H__)
#define  __P25_LC__LC_H__

#include "common/Defines.h"
#include "common/p25/lc/TSBK.h"
#include "common/p25/lc/TDULC.h"
#include "common/p25/SiteData.h"
#include "common/edac/RS634717.h"

#include <string>

namespace p25
{
    namespace lc
    {
        // ---------------------------------------------------------------------------
        //  Class Prototypes
        // ---------------------------------------------------------------------------

        class HOST_SW_API TSBK;
        class HOST_SW_API TDULC;

        // ---------------------------------------------------------------------------
        //  Class Declaration
        // ---------------------------------------------------------------------------

        /**
         * @brief Represents link control data for HDU, LDU1 and 2 packets.
         * @ingroup p25_lc
         */
        class HOST_SW_API LC {
        public:
            /**
             * @brief Initializes a copy instance of the LC class.
             * @param data Instance of LC class to copy from.
             */
            LC(const LC& data);
            /**
             * @brief Initializes a new instance of the LC class.
             */
            LC();
            /**
             * @brief Finalizes a instance of the LC class.
             */
            ~LC();

            /**
             * @brief Equals operator.
             * @param data Instance of LC class to copy from.
             */
            LC& operator=(const LC& data);

            /** Project 25 Phase I CAI (TIA-102.BAAA-B Section 4.2, 4.5) */

            /**
             * @brief Decode a header data unit.
             * @param[in] data Buffer containing the HDU to decode.
             * @param rawOnly Flag indicating only the raw bytes of the LC should be decoded.
             * @returns True, if HDU decoded, otherwise false.
             */
            bool decodeHDU(const uint8_t* data, bool rawOnly = false);
            /**
             * @brief Encode a header data unit.
             * @param[out] data Buffer to encode an HDU.
             * @param rawOnly Flag indicating only the raw bytes of the LC should be encoded.
             */
            void encodeHDU(uint8_t* data, bool rawOnly = false);

            /**
             * @brief Decode a logical link data unit 1.
             * @param[in] data Buffer containing an LDU1 to decode.
             * @param rawOnly Flag indicating only the raw bytes of the LC should be decoded.
             * @returns bool True, if LDU1 decoded, otherwise false.
             */
            bool decodeLDU1(const uint8_t* data, bool rawOnly = false);
            /**
             * @brief Encode a logical link data unit 1.
             * @param[out] data Buffer to encode an LDU1.
             */
            void encodeLDU1(uint8_t* data);

            /**
             * @brief Decode a logical link data unit 2.
             * @param[in] data Buffer containing an LDU2 to decode.
             * @returns bool  True, if LDU2 decoded, otherwise false.
             */
            bool decodeLDU2(const uint8_t* data);
            /**
             * @brief Encode a logical link data unit 2.
             * @param[out] data Buffer to encode an LDU2.
             */
            void encodeLDU2(uint8_t* data);

            /** Project 25 Phase II (TIA-102.BBAD-D Section 2) */

            /**
             * @brief Decode a IEMI VCH MAC PDU.
             * @param data Buffer containing the MAC PDU to decode.
             * @param sync Flag indicating if sync is included (true=276 bits with RS, false=312 bits no RS).
             * @return bool True, if MAC PDU decoded, otherwise false.
             */
            bool decodeVCH_MACPDU_IEMI(const uint8_t* data, bool sync);
            /**
             * @brief Decode a xOEMI VCH MAC PDU.
             * @param data Buffer containing the MAC PDU to decode.
             * @param sync Flag indicating if sync is included.
             * @return bool True, if MAC PDU decoded, otherwise false.
             */
            bool decodeVCH_MACPDU_OEMI(const uint8_t* data, bool sync);
            /**
             * @brief Encode a VCH MAC PDU.
             * @param[out] data Buffer to encode a MAC PDU.
             * @param sync Flag indicating if sync is to be included.
             */
            void encodeVCH_MACPDU(uint8_t* data, bool sync);

            /**
             * @brief Set the Phase 2 scrambler superframe bit offset for the current burst.
             * @param offset Superframe bit offset in the 4320-bit lane sequence.
             */
            void setP2ScrambleOffset(uint16_t offset);
            /**
             * @brief Clear the Phase 2 scrambler superframe bit offset override.
             */
            void clearP2ScrambleOffset();


            /**
             * @brief Helper to determine if the MFId is a standard MFId.
             * @returns bool True, if the MFId contained for this LC is standard, otherwise false.
             */
            bool isStandardMFId() const;

            /**
             * @brief Decode link control.
             * @param[in] rs Buffer containing the decoded Reed-Solomon LC data.
             * @param rawOnly Flag indicating only the raw bytes of the LC should be decoded.
             * @returns bool True, if LC is decoded, otherwise false.
             */
            bool decodeLC(const uint8_t* rs, bool rawOnly = false);
            /**
             * @brief Encode link control.
             * @param[out] rs Buffer to encode LC data.
             */
            void encodeLC(uint8_t* rs);

            /**
             * @brief Decode MAC PDU.
             * @param[in] raw Buffer containing the decoded Reed-Solomon MAC PDU data.
             * @param macLength MAC PDU length in bits (156 for IEMI/S-OEMI, 180 for I-OEMI).
             * @returns bool True, if MAC PDU is decoded, otherwise false.
             */
            bool decodeMACPDU(const uint8_t* raw, uint32_t macLength = defines::P25_P2_IOEMI_MAC_LENGTH_BITS);
            /**
             * @brief Encode MAC PDU.
             * @param[out] raw Buffer to encode MAC PDU data.
             * @param macLength MAC PDU length in bits (156 for IEMI/S-OEMI, 180 for I-OEMI).
             */
            void encodeMACPDU(uint8_t* raw, uint32_t macLength = defines::P25_P2_IOEMI_MAC_LENGTH_BITS);

            /** @name Encryption data */
            /**
             * @brief Sets the encryption message indicator.
             * @param[in] mi Buffer containing the 9-byte Message Indicator.
             */
            void setMI(const uint8_t* mi);
            /**
             * @brief Gets the encryption message indicator.
             * @param[out] mi Buffer containing the 9-byte Message Indicator.
             */
            void getMI(uint8_t* mi) const;
            /** @} */

            /** @name User Alias data */
            /**
             * @brief Gets the user alias.
             * @returns std::string User Alias.
             */
            std::string getUserAlias() const;
            /**
             * @brief Sets the user alias.
             * @param alias User alias.
             */
            void setUserAlias(std::string alias);

            /** @name Local Site data */
            /**
             * @brief Gets the local site data.
             * @returns SiteData Currently set site data for the LC class.
             */
            static SiteData getSiteData() { return s_siteData; }
            /**
             * @brief Sets the local site data.
             * @param siteData Site data to set for the LC class.
             */
            static void setSiteData(SiteData siteData) { s_siteData = siteData; }
            /** @} */

            /**
             * @brief Sets the flag indicating CRC-errors should be warnings and not errors.
             * @param warnCRC Flag indicating CRC-errors should be treated as warnings.
             */
            static void setWarnCRC(bool warnCRC) { s_warnCRC = warnCRC; }

        public:
            /** @name Common Data */
            /**
             * @brief Flag indicating the link control data is protected.
             */
            DECLARE_PROPERTY(bool, protect, Protect);
            /**
             * @brief Link control opcode.
             */
            DECLARE_PROPERTY(uint8_t, lco, LCO);
            /**
             * @brief Manufacturer ID.
             */
            DECLARE_PROPERTY(uint8_t, mfId, MFId);

            /**
             * @brief Source ID.
             */
            DECLARE_PROPERTY(uint32_t, srcId, SrcId);
            /**
             * @brief Destination ID.
             */
            DECLARE_PROPERTY(uint32_t, dstId, DstId);

            /**
             * @brief Voice channel number.
             */
            DECLARE_PROPERTY(uint32_t, grpVchNo, GrpVchNo);

            /**
             * @brief Voice channel number.
             */
            DECLARE_PROPERTY(uint32_t, grpVchNoB, GrpVchNoB);
            /**
             * @brief Destination ID.
             */
            DECLARE_PROPERTY(uint32_t, dstIdB, DstIdB);

            /**
             * @brief Flag indicating explicit addressing.
             */
            DECLARE_PROPERTY(bool, explicitId, ExplicitId);

            /**
             * @brief Network ID.
             */
            DECLARE_PROPERTY(uint32_t, netId, NetId);
            /**
             * @brief System ID.
             */
            DECLARE_PROPERTY(uint32_t, sysId, SysId);
            /** @} */

            /** @name Service Options */
            /**
             * @brief Flag indicating the emergency bits are set.
             */
            DECLARE_PROPERTY(bool, emergency, Emergency);
            /**
             * @brief Flag indicating that encryption is enabled.
             */
            DECLARE_PROPERTY(bool, encrypted, Encrypted);
            /**
             * @brief Priority level for the traffic.
             */
            DECLARE_PROPERTY(uint8_t, priority, Priority);
            /**
             * @brief Flag indicating a group/talkgroup operation.
             */
            DECLARE_PROPERTY(bool, group, Group);
            /** @} */

            /** @name Encryption data */
            /**
             * @brief Encryption algorithm ID.
             */
            DECLARE_PROPERTY(uint8_t, algId, AlgId);
            /**
             * @brief Encryption key ID.
             */
            DECLARE_PROPERTY(uint32_t, kId, KId);
            /** @} */

            /** @name Phase 2 Data */
            /**
             * @brief Slot Number.
             */
            DECLARE_PROPERTY(uint8_t, slotNo, SlotNo);

            /**
             * @brief Phase 2 DUID.
             */
            DECLARE_PROPERTY(uint8_t, p2DUID, P2DUID);
            /**
             * @brief Color Code.
             */
            DECLARE_PROPERTY(uint16_t, colorCode, ColorCode);
            /**
             * @brief MAC PDU Opcode.
             */
            DECLARE_PROPERTY(uint8_t, macPduOpcode, MACPDUOpcode);
            /**
             * @brief MAC PDU SACCH Offset.
             */
            DECLARE_PROPERTY(uint8_t, macPduOffset, MACPDUOffset);
            /**
             * @brief MAC Partition.
             */
            DECLARE_PROPERTY(uint8_t, macPartition, MACPartition);
            /** @} */

            /** @name Packed RS Data */
            /**
             * @brief Packed RS Data.
             */
            DECLARE_PROPERTY(ulong64_t, rsValue, RS);
            /** @} */

            /** @name Phase 2 Raw MCO Data */
            uint8_t* p2MCOData; // ?? - this should probably be private with getters/setters
            /** @} */

        private:
            friend class TSBK;
            friend class TDULC;
            edac::RS634717 m_rs;
            bool m_encryptOverride;
            bool m_tsbkVendorSkip;

            uint16_t m_p2ScrambleOffset;
            bool m_p2ScrambleOffsetValid;

            uint32_t m_callTimer;

            // Encryption data
            uint8_t* m_mi;

            // User Alias data
            uint8_t* m_userAlias;

            bool m_gotUserAliasPartA;
            bool m_gotUserAlias;

            static bool s_warnCRC;

            // Local Site data
            static SiteData s_siteData;

            /**
             * @brief Internal helper to copy the class.
             */
            void copy(const LC& data);

            /**
             * @brief Decode LDU hamming FEC.
             * @param[in] raw 
             * @param[out] data 
             */
            void decodeLDUHamming(const uint8_t* raw, uint8_t* data);
            /**
             * @brief Encode LDU hamming FEC.
             * @param[out] data 
             * @param[in] raw 
             */
            void encodeLDUHamming(uint8_t* data, const uint8_t* raw);

            /**
             * @brief Decode HDU Golay FEC.
             * @param[in] raw 
             * @param[out] data 
             */
            void decodeHDUGolay(const uint8_t* raw, uint8_t* data);
            /**
             * @brief Encode HDU Golay FEC.
             * @param[out] data 
             * @param[in] raw 
             */
            void encodeHDUGolay(uint8_t* data, const uint8_t* raw);

            /**
             * @brief Decode Phase 2 DUID hamming FEC.
             * @param[in] raw 
             * @param[out] data 
             */
            void decodeP2_DUIDHamming(const uint8_t* raw, uint8_t* data);
            /**
             * @brief Encode Phase 2 DUID hamming FEC.
             * @param[out] data 
             * @param[in] raw 
             */
            void encodeP2_DUIDHamming(uint8_t* data, const uint8_t* raw);

            /**
             * @brief Apply the Phase 2 TDMA MAC burst scrambler.
             * @param data Buffer containing the over-the-air burst bits.
             * @param inbound True for inbound/IEMI, false for outbound/OEMI.
             * @param sync True when the burst includes sync symbols.
             */
            void applyP2Scrambler(uint8_t* data, bool inbound, bool sync);

        };
    } // namespace lc
} // namespace p25

#endif // __P25_LC__LC_H__
