/***************************************************************************
 *   Copyright (C) 2025 by Santiago González                               *
 *                                                                         *
 ***( see copyright.txt file at root folder )*******************************/

#pragma once

#include <QProcess>

#include "chip.h"

typedef struct qemuArena{
    uint64_t simuTime;    // in ps
    uint64_t qemuTime;    // in ps
    uint64_t regData;
    uint64_t regAddr;
    uint64_t irqNumber;
    uint64_t irqLevel;
    uint64_t simuAction;
    uint64_t qemuAction;
    uint64_t running;
    int64_t  loop_timeout_ns;
    double   ps_per_inst;

} qemuArena_t;

enum simuAction{
    SIM_NONE=0,
    SIM_READ,
    SIM_WRITE,
    SIM_FREQ,
    SIM_INTERRUPT,
    SIM_I2C=10,
    SIM_SPI,
    SIM_USART,
    SIM_TIMER,
    SIM_GPIO_IN,
    SIM_EVENT=1<<7
};

class IoPin;
class QemuModule;
class QemuUsart;
class QemuTimer;
class QemuTwi;
class QemuSpi;
class LibraryItem;

class QemuDevice : public Chip
{
    public:
        QemuDevice( QString type, QString id );
        ~QemuDevice();

        void initialize() override;
        void stamp() override;
        //void updateStep() override;
        void voltChanged() override;
        void runEvent() override;

        QString firmware() { return m_firmware; }
        void setFirmware( QString file );

        QString extraArgs()  { return m_extraArgs; }
        void setExtraArgs( QString a ){ m_extraArgs = a; }

        void setPackageFile( QString package );

        std::vector<uint32_t>* getIoMem() { return &m_ioMem; }
        volatile qemuArena_t* getArena() { return m_arena; }

        void slotLoad();
        void slotReload();
        void slotOpenTerm( int num );

        void addModule( QemuModule* m ) { m_modules.append( m ); }

 static QemuDevice* self() { return m_pSelf; }
 static Component* construct( QString type, QString id );
 static LibraryItem* libraryItem();

    protected:
 static QemuDevice* m_pSelf;

        virtual bool createArgs(){ return false;}

        virtual void doAction();
        virtual void updtFrequency(){;}

        void runModuleEvent();

        void contextMenu( QGraphicsSceneContextMenuEvent* e, QMenu* m ) override;

        QString m_lastFirmDir;  // Last firmware folder used
        QString m_firmware;
        QString m_firmPath;
        QString m_executable;
        QString m_packageFile;

        QString m_extraArgs;

        volatile qemuArena_t* m_arena;

        QemuModule* m_dummyModule;
        QemuModule* m_eventModule;
        uint64_t m_nextEvent;
        uint64_t m_lastEvent;

        uint32_t m_ioMemStart;

        int m_gpioSize;
        std::vector<IoPin*> m_ioPin;
        IoPin* m_rstPin;

        QString m_shMemKey;
        int64_t m_shMemId;

        void* m_wHandle;

        QProcess m_qemuProcess;
        QStringList m_arguments;

        uint8_t m_portN;
        uint8_t m_usartN;
        uint8_t m_timerN;
        uint8_t m_i2cN;
        uint8_t m_spiN;

        std::vector<QemuTwi*>   m_i2cs;
        std::vector<QemuSpi*>   m_spis;
        std::vector<QemuUsart*> m_usarts;
        std::vector<QemuTimer*> m_timers;
        std::vector<uint32_t>   m_ioMem;

        QList<QemuModule*> m_modules;
};
