#include "QLbootError.h"
#include "QLbootOutRecord.h"
#include "lboot_proto/lboot_proto.h"

typedef enum {
    /** опция заданная в командной строке не поддерживается */
    LBOOT_ERR_INVALID_OPTION       = -1,
    /** недостаточное количество аргументов */
    LBOOT_ERR_INSUFFICIENT_ARGUMENTS  = -2,
    /** указан неверный интерфейс для передачи прошивки устройству */
    LBOOT_ERR_INVALID_INTERFACE       = -3,
    LBOOT_ERR_FIRMWARE_FILE_OPEN      = -4,
    LBOOT_ERR_SIGNATURE_FILE_OPEN     = -5,
    LBOOT_ERR_HASH_FILE_OPEN          = -6,
    LBOOT_ERR_MEMORY_ALLOC            = -7,
    LBOOT_ERR_ALLOC_RESOURCE          = -8,
    LBOOT_ERR_DEVICE_NOT_FOUND        = -9,
    LBOOT_ERR_IOCTRL_FAILED           = -10,
    LBOOT_ERR_INVALID_DEVICE          = -11,
    LBOOT_ERR_INVALID_SERIAL          = -12,
    LBOOT_ERR_INVALID_DEVMODE         = -13,
    /** загрузчик не поддерживает возможность загрузки, без запуска основной программы */
    LBOOT_ERR_UNSUP_FLAG_DONT_START   = -14,
    /** загрузчик не поддерживает возможность восстановления основной прошивки по команде */
    LBOOT_ERR_UNSUP_FLAG_RECOVERY     = -15,
    /** указан неверный фармат вывода в опции --output-fmt */
    LBOOT_ERR_INVALID_OUTPUT_FMT      = -16,
    /** загрузчик не поддерживает запись защищенного блока данных */
    LBOOT_ERR_UNSUP_WR_PROT_DATA      = -17,
    /** ошибка открытия файла с даннымы для записи в защищенный блок */
    LBOOT_ERR_PROT_DATA_FILE_OPEN     = -18,
    LBOOT_ERR_INVALID_APP_IFACE       = -19,
    LBOOT_ERR_APP_IFACE_NOT_SPECIFIED = -20,
    /** неверно задана скорость RS */
    LBOOT_ERR_MBRTU_INVALID_BAUDRATE = -100,
    /** неверно задана четность для порта RS */
    LBOOT_ERR_MBRTU_INVALID_PARITY   = -101,
    /** неверно задан адрес устройства на шине Modbus */
    LBOOT_ERR_MBRTU_INVALID_ADDRESS  = -102,
    /** ошибка создания контекста Modbus */
    LBOOT_ERR_MBRTU_CREATE_CONTEXT   = -103,
    /** ошибка функции modbus_set_slave() */
    LBOOT_ERR_MBRTU_SET_ADDR         = -104,
    /** ошибка открытия указанного порта */
    LBOOT_ERR_MBRTU_PORT_OPEN        = -105,
    /** ошибка чтения регистров modbus */
    LBOOT_ERR_READ_REGISTERS         = -106,
    LBOOT_ERR_WRITE_REGISTERS        = -107,

    /** Ошибка создания сокета */
    LBOOT_ERR_TFTP_SOCK_CREATE   = -200,
    /** Ошибка передачи данных */
    LBOOT_ERR_TFTP_SEND          = -201,
    /** Ошибка передачи данных */
    LBOOT_ERR_TFTP_RECV          = -202,
    /** Неверный формат принятого пакета */
    LBOOT_ERR_TFTP_RECV_PKT_FMT  = -203,
    /** Ошибка передачи данных */
    LBOOT_ERR_TFTP_TIMEOUT       = -204,
    /** Неверный формат адреса */
    LBOOT_ERR_TFTP_IP_ADDR       = -205,
    /** Неверный номер порта */
    LBOOT_ERR_TFTP_UDP_PORT      = -206,
    LBOOT_ERR_TFTP_BLOCK_SIZE    = -207,
    /** Принят пакет ERR по TFTP */
    LBOOT_ERR_TFTP_ERR_PACKET    = -208,
    LBOOT_ERR_TFTP_RX_OVERFLOW   = -209,
    LBOOT_ERR_TFTP_RX_INSUF_SIZE = -210,
    LBOOT_ERR_TFTP_PACKET_SKIP   = -211,
    LBOOT_ERR_TFTP_WSA_INIT      = -212,
    LBOOT_ERR_TFTP_CON_RESET     = -213,

    LBOOT_ERR_HTTP_CURL             = -300,
    LBOOT_ERR_HTTP_RESPONSE         = -301,
    LBOOT_ERR_HTTP_RX_INSUF_SIZE    = -302,
    LBOOT_ERR_HTTP_TRANSFER_TOUT    = -303,

    LBOOT_ERR_UDP_IP_ADDR       = -400,
    LBOOT_ERR_UDP_PORT          = -401,
    LBOOT_ERR_UDP_WSA_INIT      = -402,
    LBOOT_ERR_UDP_SEND          = -403,
    LBOOT_ERR_UDP_NO_APP_MSG    = -404,

    LBOOT_ERR_MBTCP_NOTSET_IPADDR   = -450,
    LBOOT_ERR_MBTCP_NOTSET_REGADDR  = -451,
    LBOOT_ERR_MBTCP_NOTSET_REGVALS  = -452,
    LBOOT_ERR_MBTCP_INVALID_PORT    = -453,
    LBOOT_ERR_MBTCP_INVALID_REGADDR = -454,
    LBOOT_ERR_MBTCP_INVALID_REGVALS = -455,
    LBOOT_ERR_MBTCP_INVALID_REGCNT  = -456,
    LBOOT_ERR_MBTCP_CREATE_CONTEXT  = -457,
    LBOOT_ERR_MBTCP_CONNECT         = -458,
    LBOOT_ERR_MBTCP_WRITE_REGS      = -459,

} t_lboot_util_errs;

typedef enum {
    LCRYPT_ERR_PGP_UNSUF_DATA                    = -10000,
    LCRYPT_ERR_PGP_SIGN_FORMAT                   = -10001,  /**< неверный формат PGP файла */
    LCRYPT_ERR_PGP_SIGN_UNSUPPORT_CRYPT_ALG      = -10002,  /**< неподдерживаемый алгоритм шифрования для подписи */
    LCRYPT_ERR_PGP_SIGN_UNSUPPORT_HASH_ALG       = -10003  /**< неподдерживаемый алгоритм вычисления hash-функции */
} t_lcrypt_pgp_errs;


LQError QLbootError::error(const QLbootOutRecord &errRecord) {
    int errCode = errRecord.errorCode();
    if (errCode == 0) {
        return LQError::Success();
    }
    QString errMsg {errorStr(errCode)};
    if (errMsg.isEmpty()) {
        errMsg = errRecord.errorMsg();
    }
    return error(errCode, QString{"%1 (%2): %3"}
                 .arg(errRecord.errorTypeDescr()).arg(errCode).arg(errMsg));
}

LQError QLbootError::lbootExec() {
    return error(1, tr("Cannot execute lboot process"));
}

QString QLbootError::errorStr(int errCode) {
    switch (errCode) {
    case LBOOT_ERR_INVALID_OPTION:
        return tr("Invalid input parameter");
    case LBOOT_ERR_INSUFFICIENT_ARGUMENTS:
        return tr("Insufficient input arguments");
    case LBOOT_ERR_INVALID_INTERFACE:
        return tr("Specified invalid interface");
    case LBOOT_ERR_FIRMWARE_FILE_OPEN:
        return tr("Cannot open firmware file");
    case LBOOT_ERR_SIGNATURE_FILE_OPEN:
        return tr("Cannot open signature file");
    case LBOOT_ERR_HASH_FILE_OPEN:
        return tr("Cannot open hash file");
    case LBOOT_ERR_MEMORY_ALLOC:
        return tr("Memory allocation error");
    case LBOOT_ERR_ALLOC_RESOURCE:
        return tr("Resource allocation error");
    case LBOOT_ERR_DEVICE_NOT_FOUND:
        return tr("Bootloader device not found");
    case LBOOT_ERR_IOCTRL_FAILED:
        return tr("IO request failed");
    case LBOOT_ERR_INVALID_DEVICE:
        return tr("Invalid device name");
    case LBOOT_ERR_INVALID_SERIAL:
        return tr("Invalid serial number");
    case LBOOT_ERR_INVALID_DEVMODE:
        return tr("Device not in bootloader mode");
    case LBOOT_ERR_UNSUP_FLAG_DONT_START:
        return tr("Bootloader doesn't support burn withot start application");
    case LBOOT_ERR_UNSUP_FLAG_RECOVERY:
        return tr("Bootloader doesn't support recovery operation");
    case LBOOT_ERR_INVALID_OUTPUT_FMT:
        return tr("Invalid output format specified");
    case LBOOT_ERR_UNSUP_WR_PROT_DATA:
        return tr("Bootloader doesn't support protection data");
    case LBOOT_ERR_PROT_DATA_FILE_OPEN:
        return tr("Cannot open file with protected data");
    case LBOOT_ERR_INVALID_APP_IFACE:
        return tr("Invalid application to bootloader switch interface specified");
    case LBOOT_ERR_APP_IFACE_NOT_SPECIFIED:
        return tr("Application to bootloader switch interface is not specified");

    case LBOOT_ERR_MBRTU_INVALID_BAUDRATE:
        return tr("Invalid rs baudrate specified");
    case LBOOT_ERR_MBRTU_INVALID_PARITY:
        return tr("Invalid rs parity specified");
    case LBOOT_ERR_MBRTU_INVALID_ADDRESS:
        return tr("Invalid modbus address specified");
    case LBOOT_ERR_MBRTU_CREATE_CONTEXT:
        return tr("Cannot create modbus context");
    case LBOOT_ERR_MBRTU_SET_ADDR:
        return tr("Cannot set modbus address");
    case LBOOT_ERR_MBRTU_PORT_OPEN:
        return tr("Cannot open modbus port");
    case LBOOT_ERR_READ_REGISTERS:
        return tr("Cannot read modbus registers");
    case LBOOT_ERR_WRITE_REGISTERS:
        return tr("Cannot write modbus registers");

    case LBOOT_ERR_TFTP_SOCK_CREATE:
        return tr("Cannot create socket for TFTP operations");
    case LBOOT_ERR_TFTP_SEND:
        return tr("Send TFTP packet error");
    case LBOOT_ERR_TFTP_RECV:
        return tr("Receive TFTP packet error");
    case LBOOT_ERR_TFTP_RECV_PKT_FMT:
        return tr("Invalid format of received TFTP packet");
    case LBOOT_ERR_TFTP_TIMEOUT:
        return tr("TFTP packet response timeout");
    case LBOOT_ERR_TFTP_IP_ADDR:
        return tr("Invalid TFTP host address specified");
    case LBOOT_ERR_TFTP_UDP_PORT:
        return tr("Invalid UDP port for TFTP interface specified");
    case LBOOT_ERR_TFTP_BLOCK_SIZE:
        return tr("Invalid TFTP block size specified");
    case LBOOT_ERR_TFTP_ERR_PACKET:
        return tr("Receive TFTP error packet");
    case LBOOT_ERR_TFTP_RX_OVERFLOW:
        return tr("Received TFTP packets overflow");
    case LBOOT_ERR_TFTP_RX_INSUF_SIZE:
        return tr("Receive insufficient data over TFTP");
    case LBOOT_ERR_TFTP_PACKET_SKIP:
        return tr("Received not expected TFTP packet");
    case LBOOT_ERR_TFTP_WSA_INIT:
        return tr("Socket system initialization error");
    case LBOOT_ERR_TFTP_CON_RESET:
        return tr("Connection was reset by another side (port unreachable?)");

    case LBOOT_ERR_HTTP_RESPONSE:
        return tr("HTTP Server response error");
    case LBOOT_ERR_HTTP_RX_INSUF_SIZE:
        return tr("Receive insufficient data size");
    case LBOOT_ERR_HTTP_TRANSFER_TOUT:
        return tr("HTTP transfer timeout");

    case LBOOT_ERR_UDP_IP_ADDR:
        return tr("Invalid IP-address for UDP connection specified");
    case LBOOT_ERR_UDP_PORT:
        return tr("Invalid UDP port specifeid");
    case LBOOT_ERR_UDP_WSA_INIT:
        return tr("Socket system initialization error");
    case LBOOT_ERR_UDP_SEND:
        return tr("UDP packet send error");
    case LBOOT_ERR_UDP_NO_APP_MSG:
        return tr("UDP message is not specified");

    case LBOOT_ERR_MBTCP_NOTSET_IPADDR:
        return tr("Device IP-address is not specified");
    case LBOOT_ERR_MBTCP_NOTSET_REGADDR:
        return tr("Modbus registers start address is not specified");
    case LBOOT_ERR_MBTCP_NOTSET_REGVALS:
        return tr("Modbus registers write values are not specified");
    case LBOOT_ERR_MBTCP_INVALID_PORT:
        return tr("Invalid Modbus TCP port specified");
    case LBOOT_ERR_MBTCP_INVALID_REGADDR:
        return tr("Invalid Modbus registers start address specified");
    case LBOOT_ERR_MBTCP_INVALID_REGVALS:
        return tr("Invalid modbus register values format");
    case LBOOT_ERR_MBTCP_INVALID_REGCNT:
        return tr("Invalid modbus register values count");
    case LBOOT_ERR_MBTCP_CREATE_CONTEXT:
        return tr("Modbus context creation error");
    case LBOOT_ERR_MBTCP_CONNECT:
        return tr("Modbus connection error");
    case LBOOT_ERR_MBTCP_WRITE_REGS:
        return tr("Modbus registers write error");

    case LBOOT_ERR_UNCORRECT_SIGN:
        return tr("Signature check failed");
    case LBOOT_ERR_UNSTABLE_RECOV_WR:
        return tr("Cannot write unstable firmware as reserve copy");
    case LBOOT_ERR_FIRMWARE_FOR_INVALID_DEVICE:
        return tr("Firmware file is invalid or for another device type");
    case LBOOT_ERR_UNCORRECT_START_SIGN:
        return tr("Incorrect sign for start write firmware");
    case LBOOT_ERR_WR_DISABLED:
        return tr("Write this type of firmware is disabled");
    case LBOOT_ERR_FLASH_WRITE:
        return tr("Flash memory write error");
    case LBOOT_ERR_UNCORRECT_FIRM_RESET_ADDR:
        return tr("Invalid start address in firmware");
    case LBOOT_ERR_INVALID_REQ_DATA_LENGTH:
        return tr("Invalid request data length");
    case LBOOT_ERR_INVALID_OPERATION:
        return tr("Invalid command");
    case LBOOT_ERR_UNSUP_UNPACK:
        return tr("Unpack operation is not supported");
    case LBOOT_ERR_UNPACK_NOT_COMPLETE:
        return tr("Unpack operation is not complete");
    case LBOOT_ERR_FW_INTEGRITY_CHECK:
        return tr("Firmware integrity check error");
    case LBOOT_ERR_INVALID_SECTOR:
        return tr("Invalid flash write sector");
    case LBOOT_ERR_FIRM_WITHOUT_SIGN_DISABLED:
        return tr("Write firmware without signature is disabled");
    case LBOOT_ERR_INVALID_HASH:
        return tr("Invalid firmware hash");
    case LBOOT_ERR_DEVELOP_FIRM_DISABLE:
        return tr("Write development firmware is disabled");
    case LBOOT_ERR_INVALID_CMD_CODE:
        return tr("Unsupported special command code");
    case LBOOT_ERR_INVALID_CMD_PARAMS:
        return tr("Invalid special command parameters");
    case LBOOT_ERR_INVALID_CMD_SIGN:
        return tr("Invalid special command sign");
    case LBOOT_ERR_RESERV_COPY_NOT_PRESENT:
        return tr("Reserve copy is't present");
    case LBOOT_ERR_APPLICATION_NOT_PRESENT:
        return tr("Main application is't present");
    case LBOOT_ERR_INVALID_APPL_SIZE:
        return tr("Invalid firmware size");
    case LBOOT_ERR_PROT_DATA_INVALID_SIZE:
        return tr("invalid protection block size");
    case LBOOT_ERR_PROT_DATA_WR_DISABLED:
        return tr("Write protected block is disabled");
    case LBOOT_ERR_PROT_DATA_CHECK:
        return tr("Protected block integrity check error");
    case LBOOT_ERR_INVALID_REG_ADDR:
        return tr("Invalid register address");
    case LBOOT_ERR_ABORTED_BY_ANOTHER_REQ:
        return tr("Operation aborted by another request");
    case LBOOT_ERR_INVALID_XZ_FORMAT:
        return tr("Invalid xz archive format");
    case LBOOT_ERR_INVALID_SIGN_FORMAT:
        return tr("Invalid signature format");
    case LBOOT_ERR_FLASH_COMPARE:
        return tr("Flash compare operation failed");
    case LBOOT_ERR_FLASH_ERASE:
        return tr("Flash erase error");
    case LBOOT_ERR_CUR_FIRMWARE_NOT_SELECTED:
        return tr("Current firmware is not selected");
    case LBOOT_ERR_UNKNOWN_FIRMWARE_TYPE:
        return tr("Unsupported firmware type");
    case LBOOT_ERR_FLASH_WRITE_ENABLE:
        return tr("Flash write enable error");
    case LBOOT_ERR_FLASH_WRITE_DISABLE:
        return tr("Flash write disable error");
    case LBOOT_ERR_FLASH_WRITE_RDP_LVL:
        return tr("Flash read protection code write error");
    case LBOOT_ERR_INVALID_FILE_FORMAT:
        return tr("Invalid firmware file format");
    case LBOOT_ERR_HASH_NOT_PRESENT:
        return tr("No firmware hash present in file");
    case LBOOT_ERR_INVALID_DATA_BLOCK_CNT:
        return tr("File contains unsupported firmware block count");
    case LBOOT_ERR_INVALID_REGION_NUM:
        return tr("Invalid firmware region number");
    case LBOOT_ERR_NO_MAIN_REGION:
        return tr("Main region data was not found in file");
    case LBOOT_ERR_FILE_NOT_ALLOWED_FWTYPE:
        return tr("File is not allowed to be used as specified firmware type");
    case LBOOT_ERR_FILE_NOT_FOR_CUR_CHIPTYPE:
        return tr("Firmware is for invalid chip type");
    case LBOOT_ERR_FILE_SIGN_NOT_PRESENT:
        return tr("Signature is not present in file");
    case LBOOT_ERR_FILE_METAFILE_FMT_NOT_SUPPORTED:
        return tr("Metafile format is not supported by device");
    case LBOOT_ERR_FILE_METAFILE_FMT_REQUIRED:
        return tr("Metafile format is required for this device");
    case LBOOT_ERR_CANT_DECRYPT_DATA:
        return tr("Cannot decrypt data in file");
    case LBOOT_ERR_ENCRYPTION_REQUIRED:
        return tr("Firmware data must be encrypted");
    case LBOOT_ERR_FIRMWARE_DATA_NOT_PRESENT:
        return tr("Firmware data is not present in file");
    case LBOOT_ERR_INVALID_ENCRYPTION_KEY:
        return tr("Invalid encryption key");
    case LBOOT_ERR_END_OF_FILE_NOT_DETECTED:
        return tr("Valid file ending is not detected");

    case LCRYPT_ERR_PGP_UNSUF_DATA:
        return tr("Received not complete signature packet");
    case LCRYPT_ERR_PGP_SIGN_FORMAT:
        return tr("Invalid signature packet format");
    case LCRYPT_ERR_PGP_SIGN_UNSUPPORT_CRYPT_ALG:
        return tr("Unsupported signature cryptographic algorithm");
    case LCRYPT_ERR_PGP_SIGN_UNSUPPORT_HASH_ALG:
        return tr("Unsupported signature hash algorithm");
    }
    return QString{};
}

LQError QLbootError::error(int code, const QString &msg) {
    static const QString err_type {QStringLiteral("lboot")};
    return LQError{code, msg, err_type};
}
