#ifndef QGREXSOCKET_H
#define QGREXSOCKET_H

#include <QObject>
#include <QHostAddress>

class IidNodeId
{
public :

    //## type nodeid_t
    enum nodeid_t
    {
        NONE,
        EIF,
        DFE,
        DSP0,
        DSP1,
        DSP2,
        DSP3,
        DSP4,
        TIMER
    };
};

class IRexNetListener
{
public:
    enum release_policy_t { release_now=0, no_release};

    struct packet_descriptor_t
    {
        unsigned int srcId;
        unsigned int dstId;

        unsigned errors;

        packet_descriptor_t(unsigned int src, unsigned int dst, unsigned int err):
            srcId(src),
            dstId(dst),
            errors(err)
        {
        }
        packet_descriptor_t():
            srcId(0),
            dstId(0),
            errors(0)
        {
        }
    };

    struct msg_descriptor_t: public packet_descriptor_t
    {
        unsigned int mailbox;
        unsigned int letter;
        const void* payload;
        unsigned int size;
        QByteArray ba;

        msg_descriptor_t(const packet_descriptor_t& p, unsigned int mb=0, unsigned int lt=0, const void* data=0, unsigned int size_bytes=0):
            packet_descriptor_t(p),
            mailbox(mb),
            letter(lt),
            payload(data),
            size(size_bytes)
        {
        }
        msg_descriptor_t():
            mailbox(0),
            letter(0),
            payload(0),
            size(0)
        {
        }
    };

    struct mem_descriptor_t: public packet_descriptor_t
    {
        unsigned int address;
        unsigned int size;

        mem_descriptor_t(const packet_descriptor_t& p, unsigned int ab=0, unsigned int size_bytes=0):
            packet_descriptor_t(p),
            address(ab),
            size(size_bytes)
        {
        }
        //mem_descriptor_t() {}
    };

    struct doorbell_descriptor_t: public packet_descriptor_t
    {
        unsigned int code;

        doorbell_descriptor_t(const packet_descriptor_t& p, unsigned int c):
            packet_descriptor_t(p),
            code(c)
        {
        }
        doorbell_descriptor_t(unsigned int c=0):
            code(c)
        {
        }
    };

    //virtual release_policy_t onMessageReceived(const msg_descriptor_t&); //default = release_now
    //virtual release_policy_t onDirectIO(mem_descriptor_t&); //default = release_now
    //virtual release_policy_t onDoorbell(const doorbell_descriptor_t&); //default = release_now

    //virtual ~IRexNetListener();
};

class QgRexSocket: public QObject
{
    Q_OBJECT

public:
    QgRexSocket(const char* name=0, QObject* parent=0);

    static void setDefaultWindow(unsigned int num_msg);

    void setId(unsigned int id, const char* name);

    bool localBind(unsigned int port=0);
    bool remoteBind(const QHostAddress& ha, unsigned int port=51000);

public Q_SLOTS:
    void sendMessage(unsigned int dst, unsigned int mailbox, const void* data, unsigned int len_bytes);
    void sendDoorBell(unsigned int dst, unsigned int code);
    void memoryWrite(unsigned int dst, unsigned int destination_address, const void* data, unsigned int len_bytes,unsigned int event_code);

    void mapMemory(void* physical_address, uintptr_t logical_address, unsigned int size_bytes);

Q_SIGNALS:
    void messageReady();

    void messageCompleted();

    void doorbellReceived(unsigned int dst, unsigned int code);

    void messageReceived(const IRexNetListener::msg_descriptor_t d);

private:    
    class Implementation;
    Implementation& p_;
};


class QgRexConnectedSocket: public QObject
{
    Q_OBJECT

public:
    QgRexConnectedSocket(unsigned int dstid, QgRexSocket* rexSocket_):
        QObject(rexSocket_),
        rexSocket(rexSocket_),
        dst(dstid)
    {
    }

public Q_SLOTS:
    void sendMessage(unsigned int mailbox, const void* data, unsigned int len_bytes)
    {
       rexSocket->sendMessage(dst, mailbox, data, len_bytes);
    }

    void sendDoorBell(unsigned int code)
    {
        rexSocket->sendDoorBell(dst, code);
    }

    void memoryWrite(unsigned int destination_address, const void* data, unsigned int len_bytes,unsigned int event_code)
    {
        rexSocket->memoryWrite(dst, destination_address, data, len_bytes, event_code);
    }

private:
    QgRexSocket* rexSocket;
    unsigned int dst;
};


#endif // QGREXSOCKET_H
