
#ifndef ETHERCAT_SLAVE_ESI_H
#define ETHERCAT_SLAVE_ESI_H

#pragma once

#include "../utils/esi.h"
#include "../ethercat_types.h"
#include <stdint.h>
#include <stdbool.h>

struct dll;
#ifndef DLL_T_FWD_DECLARED
#define DLL_T_FWD_DECLARED
typedef struct dll dll_t;
#endif

#ifdef __cplusplus
extern "C" {
#endif

#ifdef DLL_T_DEFINED

static inline bool slave_has_esi(dll_t* dll, uint16_t mi, uint16_t si)
{
    return dll->GetSlaveHasEsi ? (dll->GetSlaveHasEsi(mi, si) != 0) : false;
}

static inline bool slave_set_esi_file(dll_t* dll, uint16_t mi, uint16_t si, const char* path)
{
    return dll->SetSlaveEsiFile ? (dll->SetSlaveEsiFile(mi, si, path) != 0) : false;
}

static inline bool slave_get_esi_version(dll_t* dll, uint16_t mi, uint16_t si,
                                                char* buf, int bufSize)
{
    if (!buf || bufSize <= 0) return false;
    buf[0] = 0;
    return dll->GetSlaveEsiVersion ? (dll->GetSlaveEsiVersion(mi, si, buf, bufSize) != 0) : false;
}

#endif

#define ESI_SM_RXPDO_COUNT(info, sm) \
    esi_count_pdos_for_sm(&(info)->pdoConfig, (sm), true)

#define ESI_SM_TXPDO_COUNT(info, sm) \
    esi_count_pdos_for_sm(&(info)->pdoConfig, (sm), false)

static inline int esi_count_pdos_for_sm(
    const DarraEsiPdoConfiguration* pdoConfig, uint8_t sm, bool isRx)
{
    int count = 0;
    if (isRx) {
        for (int i = 0; i < pdoConfig->rxPdoCount; i++) {
            if (pdoConfig->rxPdos[i].syncManager == sm) count++;
        }
    } else {
        for (int i = 0; i < pdoConfig->txPdoCount; i++) {
            if (pdoConfig->txPdos[i].syncManager == sm) count++;
        }
    }
    return count;
}

static inline int esi_pdo_bit_length(const DarraEsiPdoInfo* pdo)
{
    int bits = 0;
    for (int i = 0; i < pdo->entryCount; i++) {
        bits += pdo->entries[i].bitLength;
    }
    return bits;
}

#ifdef __cplusplus
}
#endif

#endif
