#include <wizHelper.h>

#include <stdint.h>
#include <main2.h>
#include <spi.h>
#include <stdbool.h>
#include <logger.h>
#include <PontCoopScheduler.h>
#include <utils.h>
#include <wizchip_conf.h>
#include <string.h>
#include <dhcp.h>


wiz_NetInfo netInfo = {
    .mac = { 0xa0, 0x57, 0x62, 0x01, 0x02, 0x03 },
    .dhcp = NETINFO_DHCP
};

#define DHCP_BUFFER_SIZE 2048
static uint8_t dhcpBuffer[DHCP_BUFFER_SIZE];

const uint8_t DHCP_SOCK = 6;


void wiz_cs_select(void) {
    HAL_GPIO_WritePin(ETHER_CS_GPIO_Port, ETHER_CS_Pin, GPIO_PIN_RESET);
}

void wiz_cs_deselect(void) {
    HAL_GPIO_WritePin(ETHER_CS_GPIO_Port, ETHER_CS_Pin, GPIO_PIN_SET);
}

uint8_t wiz_spi_readbyte(void) {
    uint8_t rbuf;
    HAL_SPI_Receive(&etherSpi, &rbuf, 1, HAL_MAX_DELAY);
    // coloredMsg(LOG_YELLOW, "R: %02x", rbuf);
    return rbuf;
}

void wiz_spi_writebyte(uint8_t wb) {
    // coloredMsg(LOG_YELLOW, "W: %02x", wb);
    HAL_SPI_Transmit(&etherSpi, &wb, 1, HAL_MAX_DELAY);
}

void wiz_spi_readburst(uint8_t* pBuf, uint16_t len) {
    HAL_SPI_Receive(&etherSpi, pBuf, len, HAL_MAX_DELAY);
    // coloredMsg(LOG_YELLOW, "RB: %d %02x %02x %02x", len, pBuf[0], pBuf[1], pBuf[2]);
}

void wiz_spi_writeburst(uint8_t* pBuf, uint16_t len) {
    HAL_SPI_Transmit(&etherSpi, pBuf, len, HAL_MAX_DELAY);
    // coloredMsg(LOG_YELLOW, "WB: %d %02x %02x %02x", len, pBuf[0], pBuf[1], pBuf[2]);
}

static void wizReset(bool b) {
    HAL_GPIO_WritePin(ETHER_RES_GPIO_Port, ETHER_RES_Pin, b ? GPIO_PIN_RESET : GPIO_PIN_SET);
}


static void wizDHCPAssign() {
    coloredMsg(LOG_RED, "wizda");
}

static void wizDHCPUpdate() {
    coloredMsg(LOG_RED, "wizdu");
}

static void wizDHCPHandler(void *handle) {
    static uint8_t lastStablePhyLink = 255;
    static uint8_t lastDhcpRes = 255;
    static bool dhcpInitialized = false;

    uint8_t phyLink = 0;
    int8_t res = ctlwizchip(CW_GET_PHYLINK, (void*) &phyLink);
    if (lastStablePhyLink != phyLink) {
        coloredMsg(LOG_RED, "wizdh, ctlwizchip returns %d, phy link changed to %d", res, phyLink);
        lastStablePhyLink = phyLink;
    }
    if (phyLink == PHY_LINK_ON) {

        if (! dhcpInitialized) {
            memset(dhcpBuffer, 0, DHCP_BUFFER_SIZE);
            reg_dhcp_cbfunc(wizDHCPAssign, wizDHCPUpdate, NULL);
            DHCP_init(DHCP_SOCK, dhcpBuffer);
            coloredMsg(LOG_RED, "wizI, DHCP initialized");
            dhcpInitialized = true;
        }

        uint8_t res = DHCP_run();

        if (lastDhcpRes != res) {
            coloredMsg(LOG_RED, "wizdh, dhcp state has changed: %d", res);
            lastDhcpRes = res;
        }
    }
}


int wizInit() {
    coloredMsg(LOG_RED, "wizI, resetting Ethernet module");
    wizReset(true);
    activeDelay(2);
    wizReset(false);
    activeDelay(2);

    coloredMsg(LOG_RED, "wizI, registering callbacks");
    reg_wizchip_cs_cbfunc(wiz_cs_select, wiz_cs_deselect);
    coloredMsg(LOG_GREEN, "wizI, cs funcs registed");
    reg_wizchip_spi_cbfunc(wiz_spi_readbyte, wiz_spi_writebyte);
    coloredMsg(LOG_GREEN, "wizI, spi funcs registed");
    reg_wizchip_spiburst_cbfunc(wiz_spi_readburst, wiz_spi_writeburst);
    coloredMsg(LOG_GREEN, "wizI, spi burst funcs registed");


    coloredMsg(LOG_RED, "wizI, initializing Ethernet module");
    int8_t res = wizchip_init(NULL, NULL);
    coloredMsg(LOG_RED, "wizI, module driver returned %d", res);

    wizchip_setnetinfo(&netInfo);
    coloredMsg(LOG_RED, "wizI, netinfo set to Ethernet module");

    uint8_t buf[6];
    res = ctlwizchip(CW_GET_ID, (void*) buf);
    coloredMsg(LOG_RED, "wizI, CW_GET_ID: %d %02x %02x %02x %02x %02x %02x", res, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);


    //schAdd(wizDHCPHandler, NULL, 0, 100);
    //coloredMsg(LOG_RED, "wizI, DHCP handler scheduled");

    return 0;
}