#include "terminal_utils.h"

#include <atomic>
#include <cstring>
#include <endian.h>
#include <QString>
#include <QByteArray>
#include <QDebug>

namespace TU {
    char const *terminalStatus(uint8_t status) {
        switch (status) {
        case TERMINAL_CB2_KEYS_NOT_PRESENT:
            return "CB2 KEYS NOT PRESENT";
        case TERMINAL_NO_BANKING_PARAMETERS_PRESENT:
            return "NO BANKING PARAMETERS PRESENT";
        case TERMINAL_IS_BLOCKED:
            return "TERMINAL IS BLOCKED";
        case TERMINAL_NOT_OPERATIVE:
            return "TERMINAL NOT OPERATIVE";
        case TERMINAL_IS_READY_AND_ACTIVE:
            return "TERMINAL IS READY AND ACTIVE";
        case TERMINAL_IS_READY_AND_NOT_ACTIVE:
            return "TERMINAL IS READY AND *NOT* ACTIVE";
        case TERMINAL_LOG_FULL:
            return "TERMINAL LOG IS FULL";
        default:
            return "";
        }
    }

    QByteArray int2Hex(int i) {
        return QByteArray::fromHex(
                QString().setNum(i, 16).toLocal8Bit().constData()).toHex();
    }

    uint16_t getNextTransactionId() {
        static std::atomic<int> i{0};
        int j = 0;

        while ((j = (++i % 100)) == 0); // 1 <= j <= 99

        return htobe16(((j / 10) + 0x30) << 8) | ((j % 10) + 0x30);
    }

    uint32_t crc32(uint32_t crc, unsigned char* pData, size_t len) {

        qCritical() << "updateCRC" << QByteArray((char *)pData, len).toHex();

        int i = 0;
        int j = 0;
        unsigned char ucCarry = 0x00;

        crc = ~crc;
        while (len > 0) {
            uint32_t const c = pData[i];
            crc ^= c;
            ++i;

            for (j = 0; j < 8; ++j) {
                ucCarry = crc & 1;
                crc >>= 1;

                if (ucCarry) {
                    crc ^= 0xedb88320;
                }
            }
            --len;
        }

        return ~crc;

    }

    uint32_t crc32(QByteArray const &ba) {
        uint32_t crc = 0;
        return crc32(crc, (uint8_t *)ba.data(), ba.size());
    }

    char lrc(QByteArray const &ba) {
        char crc = 0;
        for (int i = 0; i < ba.size(); ++i) {
            crc ^= ba[i];
        }
        return crc;
    }

    bool isBigEndian() {
        union {
            uint32_t i;
            char c[4];
        } bint = {0x01020304};

        return bint.c[0] == 1;
    }
}