//
// Created by Ht on 2019/8/12.
//

#ifndef JSONPROTOCOL_BYTEUTILS_H
#define JSONPROTOCOL_BYTEUTILS_H

#include <cstdio>
#include <cstdlib>
#include <memory>
#include <vector>
#include <string>

#include <jebase/config.h>

#ifdef __GNUC__
#include <unordered_map>

#else
#include <unordered_map>
#endif

#define BIT_CNT_OF_BYTE     ((QByte)8)
#define BYTE_CNT_OF_WORD    ((QByte)2)
#define BYTE_CNT_OF_DWORD   ((QByte)4)
#define BYTE_CNT_OF_QWORD   ((QByte)8)

typedef unsigned char       QByte;
typedef unsigned short      QWord;
typedef unsigned int        QDWord;
typedef unsigned long long  QQWord;

typedef std::vector<QByte> QByteList;
typedef std::unordered_map<QByte, bool> QByteMap;
typedef std::shared_ptr<QByte> QRByte;


/**
 *  数据的对齐方式，低位在左，或低位在右
 *      系统默认高位在右
 */
typedef enum {
    bitShiftAlignLeft = 0,
    bitShiftAlignRight
} QBitShiftAlignType;

class JE_API ByteUtils {

public:
    static bool  isPackedHexStr(const std::string& str);

    static QByte  byteFromHexStr(const std::string &value);

    static void  byteToHexStr(QByte orgChar, std::string& str);
    static std::string  byteToHexStr(QByte orgChar);

    static QWord wordFromHexStr(const std::string &value, bool reverse = false);
    static void  wordToHexStr(QWord word,std::string& str);
    static std::string  wordToHexStr(QWord word);

    static QDWord dwordFromHexStr(const std::string &str, bool reverse = false);
    static void  dwordToHexStr(QDWord dword,std::string& str);
    static std::string  dwordToHexStr(QDWord dword);

    static QQWord qwordFromHexStr(const std::string &str, bool reverse = false);
    static void  qwordToHexStr(QQWord qword,std::string& str);
    static std::string  qwordToHexStr(QQWord qword);

    static const QByte* clearOverloadBit(QByte *buff, size_t bufflen, size_t bitlen,
                                         QBitShiftAlignType leftAlign = bitShiftAlignLeft);

    static size_t  byteLenFromBit(size_t len);

    static void  byteToHexStrOfFixBitLen(const QByte *buff, size_t bufflen, size_t bitLen,std::string& str);

    /**
     *     将Buff的高低位字节顺序取反,用于某些串口数据传输顺序与内存数据存放相反的情况
     * @param buff
     * @param bufflen
     */
    static void  reverseBuffOrder(QByte *buff, size_t bufflen);

    static void  intFromBuffer(const QByte *buff,size_t bitlen, bool reversOrder, int& v);
    static size_t  intToBuffer(int& v, bool reversOrder, QByte *buff, size_t bitelen);

    static void  longFromBuffer(const QByte *buff,size_t bitlen, bool reversOrder, long long& v);
    static size_t  longToBuffer(long long& v, bool reversOrder, QByte *buff, size_t bitelen);

    static void  uintFromBuffer(const QByte *buff,size_t bitlen, bool reversOrder, unsigned int& v);
    static size_t  uintToBuffer(unsigned int& v, bool reversOrder, QByte *buff, size_t bitelen);

    static void  ulongFromBuffer(const QByte *buff,size_t bitlen, bool reversOrder, unsigned long long & v);
    static size_t  ulongToBuffer(unsigned long long & v, bool reversOrder, QByte *buff, size_t bitelen);

    static void  wordFromBuffer(const QByte *buff,size_t bitlen,bool reversOrder,  QWord &byte);
    static size_t  wordToBuffer(QWord &v, bool reversOrder, QByte *buff, size_t bitlen);

    static void  dwordFromBuffer(const QByte *buff,size_t bitlen,bool reversOrder,  QDWord &byte);
    static size_t  dwordToBuffer(QDWord &v, bool reversOrder, QByte *buff, size_t bitlen);

    static void  qwordFromBuffer(const QByte *buff,size_t bitlen,bool reversOrder,  QQWord &byte);
    static size_t  qwordToBuffer(QQWord &v, bool reversOrder, QByte *buff, size_t bitlen);

    static void  byteFromBuffer(const QByte *buff,size_t bitlen, QByte &byte);
    static size_t  byteToBuffer(QByte &v, QByte *buff, size_t bitlen);


    /**
     *  确保buffer长度不低于leastLen，高于部分清0
     * @param buffer
     * @param bufflen
     * @param leastLen
     */
    static void recheckBuffSizeGreaderThan(QByte **buffer, size_t bufflen, size_t leastLen);

    /**
     *      按Bit的多字节位移对齐操作
     *      用于处理跨字节的bit位描述字段的预处理
     *      考虑数的情况，对齐按照后对齐
     * @param buff          源缓冲区
     * @param offset        起始偏移
     * @param bitlen        位长
     * @param alignType     对齐方式，默认为右对齐
     * @return
     */
    static void  alignBufferByBit(const QByte *buff, QByte bitOffset, size_t bitlen, QByte** targetBuff, size_t* newlen,
                                   QBitShiftAlignType alignType = bitShiftAlignLeft);

    static void  alignLeftOrderBufferInByte(const QByte *buff, QByte bitOffset, size_t bitlen, QByte** targetBuff, size_t* newlen);
    static void  alignRightOrderBufferInByte(const QByte *buff, QByte bitOffset, size_t bitlen, QByte** targetBuff, size_t* newlen);


    /**
     *      按Bit的多字位移操作,  位移数量不超过7，否则取模
     *
     * @param src               源缓冲区
     * @param srclen            源位长度
     * @param targetBuff        目标缓冲区
     * @param offset            位移量
     */
    static void  shiftBufferByBitHighDirection(const QByte *src, size_t bitlen, QByte *targetBuff, QByte offset,
                                              QBitShiftAlignType leftAlign = bitShiftAlignLeft);

    /**
     *      带有位偏移的位拷贝，不能修改未涉及的Bit
     *
     *             按bit拷贝数据，从src到targetBuff， 长度未bitlen，偏移未bitOffset，偏移不高于7
     *
     * @param targetBuff
     * @param buffLen
     * @param bitOffset
     * @param src
     * @param bitlen
     * @param alignType
     */
    static QByte  copyBitsToBuffer(QByte *targetBuff, size_t buffLen, QByte bitOffset, QByte *src, size_t bitlen, QBitShiftAlignType alignType = bitShiftAlignLeft);

    static QByte  copyRightOrderBitsToBuffer(QByte *targetBuff, size_t buffLen, QByte bitOffset, QByte *src, size_t bitlen);
    static QByte  copyLeftOrderBitsToBuffer(QByte *targetBuff, size_t buffLen, QByte bitOffset, QByte *src, size_t bitlen);

    static void  ShowByteln(const char* prompt, QByte byte);
    static void  ShowByteln(const char* prompt, QByte byte, QByte i);
};

#define B32_ADDR_STR(var) \
    (ByteUtils::dwordToHexStr(reinterpret_cast<QDWord>(&var)).c_str())

#define B64_ADDR_STR(var) \
    (ByteUtils::qwordToHexStr(reinterpret_cast<QQWord>(&var)).c_str())

    //大端在后
#define BYTES_FROM_WORD_BE(bytes, word)\
    *(bytes+1) = word>>8 & 0XFF; *(bytes) = word & 0xFF
    //小端在后
#define BYTES_FROM_WORD_SE(bytes, word)\
    *(bytes) = word>>8 & 0XFF; *(bytes+1) = word & 0xFF

    //大端在后
#define BYTES_TO_WORD_BE(bytes, word)\
    word = *(bytes+1); word<<=8; word+= *(bytes)
    //小端在后
#define BYTES_TO_WORD_SE(bytes, word)\
    word = *(bytes); word<<=8; word+= *(bytes+1)

#endif //JSONPROTOCOL_BYTEUTILS_H
