#ifndef PICUPLOADER_H
#define PICUPLOADER_H

#include <QObject>
#include "PICUploaderGui.h"
#include "HexFile.h"
#include <QTcpSocket>
#include "BootloaderProtocol.h"

enum eBootloaderUploadSMEvents
{
    BOOTLOADER_UPLOAD_SM_TICK_EVENT,
    BOOTLOADER_UPLOAD_SM_NEW_CMD_EVENT,

    BOOTLOADER_UPLOAD_SM_MAX_EVENT
};

enum eBootloaderSMCmdEvents
{
    BOOTLOADER_UPLOAD_ERASE_FLASH_GUI_CMD,
    BOOTLOADER_UPLOAD_START_UPLOAD_GUI_CMD,
    BOOTLOADER_UPLOAD_START_FULL_UPDATE_GUI_CMD,
    BOOTLOADER_UPLOAD_ABORT_GUI_CMD,
    BOOTLOADER_UPLOAD_BOOTLOADER_CONNECTED_CMD,
    BOOTLOADER_UPLOAD_BOOTLOADER_DISCONNECTED_CMD,

    BOOTLOADER_UPLOAD_HEARTBEAT_HOST_CMD,
    BOOTLOADER_UPLOAD_ERASE_BOOTLOADER_FLASH_ACK_HOST_CMD,
    BOOTLOADER_UPLOAD_ERASE_BOOTLOADER_FLASH_RESULT_HOST_CMD,
    BOOTLOADER_UPLOAD_INIT_UPLOAD_HOST_CMD,
    BOOTLOADER_UPLOAD_GET_STATE_HOST_CMD,
    BOOTLOADER_UPLOAD_READY_FOR_DATA_HOST_CMD,
    BOOTLOADER_UPLOAD_SEND_DATA_CHUNK_HOST_CMD,
    BOOTLOADER_UPLOAD_UPLOAD_FINISHED_HOST_CMD,
    BOOTLOADER_UPLOAD_EXECUTE_UPGRADE_HOST_CMD,
    BOOTLOADER_UPLOAD_ABORT_OPERATION_HOST_CMD,

    BOOTLOADER_UPLOAD_MAX_CMD
};

typedef enum eBootloaderInterfaceSMStates
{
    BOOTLOADER_INTERFACE_SM_STANDBY_STATE,
    BOOTLOADER_INTERFACE_SM_BOOTLDR_CONNECTED_STATE,
    BOOTLOADER_INTERFACE_SM_ERASE_FLASH_STATE,
    BOOTLOADER_INTERFACE_SM_WAIT_READY_FOR_DATA_FROM_HOST_STATE,
    BOOTLOADER_INTERFACE_SM_INIT_UPLOAD_STATE,
    BOOTLOADER_INTERFACE_SM_SEND_DATA_STATE,
    BOOTLOADER_INTERFACE_SM_DATA_FINISHED_STATE,

    BOOTLOADER_UPLOAD_MAX_STATE
}BootloaderInterfaceSMStates;

typedef enum eBootloaderFirmwareUploadSMStates
{
    BOOTLOADER_FIRM_UPLD_STANDBY_STATE,
 //   BOOTLOADER_FIRM_UPLD_WAIT_FOR_HOST_READY_STATE,
    BOOTLOADER_FIRM_UPLD_SEND_CHUNK_STATE,
    BOOTLOADER_FIRM_UPLD_FINISHED_STATE,

    BOOTLOADER_FIRM_UPLD_MAX_STATE
}BootloaderFirmwareUpldState;

enum eBootloaderFirmwareUploadEvents
{
    BOOTLOADER_FIRM_UPLD_TICK_EVENT,
    BOOTLOADER_FIRM_UPLD_CMD_EVENT,

    BOOTLOADER_FIRM_UPLD_MAX_EVENT
};

enum eBootloaderFirmwareUploadSMCmd
{
    BOOTLOADER_FIRM_UPLD_INIT_UPLOAD_CMD,
    BOOTLOADER_FIRM_UPLD_CHUNK_RX_RESPONSE_CMD,
    BOOTLOADER_FIRM_UPLD_ABORT_UPLOAD_CMD,

    BOOTLOADER_FIRM_UPLD_MAX_CMD
};

enum eBootloaderProtocolDataTransferError
{
    BOOTLOADER_CHUNK_TRANSFER_SUCCESS = 1,
    BOOTLOADER_CHUNK_TRANSFER_ERROR_RESEND = 2,
    BOOTLOADER_CHUNK_TRANSFER_ERROR_FLASH_FAILURE = 3,
    BOOTLOADER_CHUNK_TRANSFER_ERROR_INVALID_CHUNK_INDEX = 4,
    BOOTLOADER_CHUNK_TRANSFER_ERROR_FLASH_ERROR = 5,

    BOOTLOADER_CHUNK_TRANSFER_MAX_ERROR
};

enum eBootloaderProtocolInitUploadError
{
    BOOTLOADER_INIT_UPLOAD_FAILED = 0,
    BOOTLOADER_INIT_UPLOAD_SUCCESS = 1,
    BOOTLOADER_INIT_UPLOAD_ERROR_FLASH_NOT_ERASED = 2,

    BOOTLOADER_INIT_UPLOAD_MAX_ERROR
};

enum eBootloaderFirmwareUploadRes
{

    BOOTLOADER_FIRM_UPLD_STANDBY_RES,
    BOOTLOADER_FIRM_UPLD_SENDING_RES,
    BOOTLOADER_FIRM_UPLD_FINISHED_RES,
    BOOTLOADER_FIRM_UPLD_ERROR_RES,
    BOOTLOADER_FIRM_UPLD_TIMEOUT_RES,
    BOOTLOADER_FIRM_UPLD_ABORT_RES,
    BOOTLOADER_FIRM_UPLD_OK_RES,

    BOOTLOADER_FIRM_UPLD_MAX_RES
};

//Used for both ACK and erase operation result
enum eBootloaderFlashEraseResult
{
    BOOTLOADER_FLASH_ERASE_ERROR = 0,
    BOOTLOADER_FLASH_ERASE_OK = 1,

    BOOTLOADER_FLASH_ERASE_MAX_RESULT
};


class CPICUploader : public QObject
{
    Q_OBJECT
public:
    explicit CPICUploader(CPICUploaderGui *Gui);
    int OpenHexFileRequest(QString FilePath);

    int Start();

    CPICUploaderGui *mPICUploaderGui;

    CHexFile mHexFile;

    QTcpSocket mBootloaderSocket;
    CBootloaderProtocol mBootloaderProtocol;

    int ConnectToBootloader(QString IP);
    int DisconnectFromBootloader();
    int SendSingleCmdRequest(int CmdID);
    int SendCmdRequest(int CmdID, QByteArray Data);
    int GuiEvent(int EventID, void* Data=0);
    int ShowHexFileInfoRequest();

    int BootloaderRxCmd(int CmdID, QByteArray Data);

    int BootloaderFirmwareUploadStateMachine(int Event, int Cmd, int CmdResult = 1, int CmdParam = 0xBAADCAFE);
    int BootloaderInterfaceStateMachine(int Event, int Cmd, int CmdParam = 0, void *Data = 0);


private:
    BootloaderInterfaceSMStates mBootloaderInterfaceSMState;
    int ResetBooloaderInterfaceStateMachine();
    BootloaderFirmwareUpldState mBootloaderFirmwareUpldState;
    int ResetFirmwareUploadStateMachine();
    unsigned int mFirmwareUploadBufferSize;
    unsigned int mFirmwareUploadCurFrame;
    QByteArray mFirmwareData;
    QByteArray GetCurDataChunk(bool &IsLastChunk);
    QByteArray IntToByteArray(int);



signals:

public slots:
    void BootloaderSocketConnected();
    void BootloaderSocketDisconnected();
    void BootloaderDataAvailable();
    void BootloaderSocketError(QAbstractSocket::SocketError);
};

#endif // PICUPLOADER_H
