#include "config.h"

#ifdef MODBUS_BRIDGE

#ifndef MODBUS_BRIDGE_H
#define MODBUS_BRIDGE_H

#include <Component.h>
#include <Mudbus.h>
#include "enums.h"
#include "config_adv.h"
#include "./PHApp.h"

#define MBB_HAS_PRINT

class Modbus;

class Query
{
public:
    short slave;
    long addr;
    short value;
    short state;
    short fn;
    int id;
    int prio;
    short owner;
    millis_t ts;

    void printNumber(int number)
    {
        Serial.print("   ");
        int spaces = 0;
        if (number < 1000)
        {
            spaces = 1;
        }
        if (number < 100)
        {
            spaces = 2;
        }
        if (number < 10)
        {
            spaces = 3;
        }
        for (int i = 0; i < spaces; i++)
        {
            Serial.print(" ");
        }
        Serial.print(number);
        return 0;
    }

    void print()
    {
        Serial.print("SLAVE: ");
        Serial.print(slave);
        Serial.print(" \t | Address: ");
        // Serial.print(addr, HEX);
        printNumber(addr);
        Serial.print(" \t | VALUE:  ");
        printNumber(value);
        Serial.print(" \t | STATE ");
        if (state == DONE)
        {
            Serial.print("Done       ");
        }
        if (state == PROCESSING)
        {
            Serial.print("Processsing");
        }
        if (state == QUEUED)
        {
            Serial.print("Queued     ");
        }
        Serial.print(" \t | FN: ");
        Serial.print(fn);
        Serial.print(" \t | PRIO: ");
        Serial.print(prio);
        Serial.print(" | ");

        Serial.print(" \t | OWNER: ");
        Serial.print(owner);
        Serial.print(" | ");
        Serial.print(" \t | DT: ");
        Serial.print(millis() - ts);
        Serial.print(" | ");
    }
    Query()
    {
        reset();
    }
    void reset()
    {
        state = DONE;
        fn = 0;
        ts = 0;
        value = 0;
        slave = 0;
        addr = 0;
        prio = 0;
        owner = 0;
    }
};

class ModbusBridge : public Component
{

public:
    enum FLAGS
    {
        DEBUG_RECEIVE = 1,
        DEBUG_SEND = 2,
    };

    ModbusBridge(App *owner) : Component("ModbusBridge", 1000, Component::COMPONENT_DEFAULT, (Component *)owner),
                               mb(new Mudbus()),
                               app(owner)
    {
        setFlag(OBJECT_RUN_FLAGS::E_OF_DEBUG);
        debug_flags = 1 << DEBUG_RECEIVE;
        nextWaitingTime = 100;
        ownerId = -1;
        owner = NULL;
        responseFn = NULL;
        onError = NULL;
        onMessage = NULL;
    }

    uint16_t ModbusSlaveRegisters[8];

    // Component implementation
    short debug();
    short info();
    short setup();
    short loop();
    short loop_test();
    short loopPoll();

    // current query
    short cSlave;
    short cFN;
    short cAddr;
    int cNB;

    long debug_flags;

    short queryState();
    short query(int slave, short function, long start, int coils, Component *_owner, ComponentFnPtr _responseFn);
    short query(int slave, short function, long start, int coils, int _ownerId);
    short qstate();

    PHApp *app;

    // 0x3-6 callback
    ComponentFnPtr responseFn;
    // on Error
    ComponentFnPtr onError;
    // on RawMessage
    ComponentRxFn onMessage;
    // callback owner
    Component *rOwner;
    int ownerId;
    int nextWaitingTime;
    Mudbus *mb;
    Mudbus *getMudbus()
    {
        return mb;
    }

    // Modbus query / commands
    Query *nextQueryByState(uchar state = DONE, int owner = -1);
    Query *nextQueryByOwner(uchar state = DONE, int owner = -1);
    Query *nextByPrio(uchar state, int prio);
    Query *nextSame(uchar state, short slave, int addr, short fn, int value);
    bool skipRead(int slave, int fn, int addr, int num, int prio);
    int numSame(uchar state, short slave, int addr, short fn, int value);
    int numSameOwner(uchar state, short slave, int addr, short fn, int value, int owner);
    int numByState(int state = DONE);
    void print();

    Query *nextQueryByState2(uchar state, int owner);
    void clearQueue();

    Query queries[MAX_QUERY_BUFFER];
    millis_t startTS;
    Modbus *modbus();
    void setDebugSend(bool debug);
};

#endif
#endif
