#include "config.h"

#ifdef MODBUS_BRIDGE

#include <Streaming.h>
#include "./Addon.h"
#include "ModbusBridge.h"
#include "config.h"
#include <SPI.h>
#include <Ethernet.h>

#define RS485Serial 3

#define MasterModbusAdd 0
#define SlaveModbusAdd 1

// Modbus master(MasterModbusAdd, RS485Serial);

uint16_t ModbusSlaveRegisters[8];
millis_t WaitingTime;

int _state = IDLE;

bool debugQuery = true;

void ModbusBridge::setDebugSend(bool debug)
{
    // master.debugSend = debug;
}

// Modbus TCP
short ModbusBridge::setup()
{
    WaitingTime = millis() + nextWaitingTime;
    _state = IDLE;

    // Ethernet.begin(MB_MAC, MB_IP, MB_DNS, MB_GATEWAY, MB_SUBNET);
    // Ethernet.begin(MB_MAC, MB_IP, MB_GATEWAY, MB_SUBNET);    
    
    ///Ethernet.begin(mac, ip, gateway, subnet);
    uint8_t mac[] = {0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02};

  uint8_t ip[] = {192, 168, 1, 177}; // CHANGE this to the IP address of your CONTROLLINO

  uint8_t gateway[] = {192, 168, 1, 1};

  uint8_t subnet[] = {255, 255, 255, 0};

  Ethernet.begin(mac, ip, gateway, subnet);
    for (uchar i = 0; i < MAX_QUERY_BUFFER; i++)
    {
        // queries[i].reset();
        // queries[i].id = i;
    }
/*
    for (uchar i = 0; i < 50; i++)
    {
        mb->R[i] = MODBUS_TCP_DEFAULT_REGISTER_VALUE;
        mb->C[i] = 0;
    }
*/
    startTS = millis();
    Serial.println("ModbusBridge setup done");

    // Check for Ethernet hardware present
    if (Ethernet.hardwareStatus() == EthernetNoHardware)
    {
        Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
        while (true)
        {
            delay(1); // do nothing, no point running without Ethernet hardware
        }
    }
    if (Ethernet.linkStatus() == LinkOFF)
    {
        Serial.println("Ethernet cable is not connected.");
    }

    //mb->server->begin();

    Serial.print("server is at ");
    Serial.println(Ethernet.localIP());
    Log.verboseln("s:%d",Ethernet.linkStatus());
    Log.verboseln("hw:%d",Ethernet.hardwareStatus());

    /*
    Serial.println(Ethernet.status());
    Serial.println(Ethernet.hardwareStatus());*/
    return E_OK;
}

Query *ModbusBridge::nextByPrio(uchar state, int prio)
{

    Query *oldest;
    for (int i = 0; i < MAX_QUERY_BUFFER; i++)
    {
        if (!oldest)
        {
            oldest = &queries[i];
        }

        if (queries[i].state == state && queries[i].prio == prio)
        {
            oldest = &queries[i];
        }
    }
    return oldest;
}

bool didm = false;

Query *ModbusBridge::nextSame(uchar state, short slave, int addr, short fn, int value)
{
    return NULL;
}
int ModbusBridge::numSame(uchar state, short slave, int addr, short fn, int value)
{
    return E_OK;
}
int ModbusBridge::numByState(int state = DONE)
{
    int num = 0;
    for (int i = 0; i < MAX_QUERY_BUFFER; i++)
    {
        if (queries[i].state == state)
        {
            num++;
        }
    }
    return num;
}
void ModbusBridge::print()
{
    Serial.print("----- Queries : --- ");
    Serial.print("Proccessing : ");
    Serial.print(numByState(PROCESSING));
    Serial.print(" | QUEUED : ");
    Serial.print(numByState(QUEUED));
    Serial.print(" | DONE: ");
    Serial.print(numByState(DONE));

    Serial.print(" | ADDR: ");
    Serial.print(addr);
    Serial.print(" | FN: ");
    Serial.print(fn);
    Serial.print(" | NOW : ");
    Serial.print(millis());

    Serial.print("-----\n");

    for (int i = 0; i < MAX_QUERY_BUFFER; i++)
    {
        Serial.print(" - ");
        Serial.print(queries[i].id);
        Serial.print(". \t ");
        queries[i].print();
        Serial.print("\n");
    }
}
short ModbusBridge::qstate()
{
    return _state;
}
short ModbusBridge::loop()
{
    // mb->Run();
    return E_OK;
}

short ModbusBridge::query(int slave, short function, long start, int coils, Addon *_addon, ComponentFnPtr _mPtr)
{
    return E_OK;
}

short ModbusBridge::loop_test()
{
    return E_OK;
}

short ModbusBridge::debug()
{
    Log.verboseln("ModbusBridge::debug()");
    return E_OK;
}

short ModbusBridge::info()
{
    // *stream << this->name << "\n\t";
    return E_OK;
}

#endif