
#ifndef ETHERCAT_SUGAR_INLINE_GETTERS_H
#define ETHERCAT_SUGAR_INLINE_GETTERS_H

#include "../ethercat_types.h"
#include "../master/core.h"
#include "../slave/core.h"
#include "../master/diagnostics.h"
#include <stdint.h>
#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

#ifndef EC_SUGAR_INLINE
#  if defined(_MSC_VER)
#    define EC_SUGAR_INLINE static __inline
#  else
#    define EC_SUGAR_INLINE static inline
#  endif
#endif

EC_SUGAR_INLINE uint16_t ec_slave_count(uint16_t mi) {
    const void* st = GetMasterState(mi);
    if (st == NULL) return 0;

    return (uint16_t)(*(const int32_t*)((const uint8_t*)st + 4));
}

EC_SUGAR_INLINE ec_link_state_t ec_link(uint16_t mi) {
    return (ec_link_state_t)GetLinkStatus(mi);
}

EC_SUGAR_INLINE uint32_t ec_vendor(uint16_t mi, uint16_t si) {
    return GetSlaveVendorId(mi, si);
}

EC_SUGAR_INLINE uint32_t ec_product(uint16_t mi, uint16_t si) {
    return GetSlaveProductCode(mi, si);
}

EC_SUGAR_INLINE uint32_t ec_revision(uint16_t mi, uint16_t si) {
    return GetSlaveRevision(mi, si);
}

EC_SUGAR_INLINE uint32_t ec_serial(uint16_t mi, uint16_t si) {
    return GetSlaveSerialNumber(mi, si);
}

EC_SUGAR_INLINE uint16_t ec_addr(uint16_t mi, uint16_t si) {
    return GetSlaveConfigAddr(mi, si);
}

EC_SUGAR_INLINE uint16_t ec_alias(uint16_t mi, uint16_t si) {
    return GetSlaveAliasAddr(mi, si);
}

EC_SUGAR_INLINE ec_state_t ec_state(uint16_t mi, uint16_t si) {
    return (ec_state_t)GetSlaveState(mi, si);
}

EC_SUGAR_INLINE uint16_t ec_alstatus(uint16_t mi, uint16_t si) {
    return GetSlaveALStatusCode(mi, si);
}

EC_SUGAR_INLINE int ec_is_op(uint16_t mi, uint16_t si) {
    return ec_state(mi, si) == EC_STATE_OPERATIONAL ? 1 : 0;
}

EC_SUGAR_INLINE int ec_has_error(uint16_t mi, uint16_t si) {
    return (GetSlaveState(mi, si) & EC_STATE_ERROR) ? 1 : 0;
}

EC_SUGAR_INLINE uint32_t ec_out_bytes(uint16_t mi, uint16_t si) {
    return GetSlaveOutputBytes(mi, si);
}

EC_SUGAR_INLINE uint32_t ec_in_bytes(uint16_t mi, uint16_t si) {
    return GetSlaveInputBytes(mi, si);
}

EC_SUGAR_INLINE uint16_t ec_parent(uint16_t mi, uint16_t si) {
    return GetSlaveParent(mi, si);
}

EC_SUGAR_INLINE const char* ec_state_name(ec_state_t s) {
    switch (s & 0x0F) {
        case EC_STATE_NONE:        return "NONE";
        case EC_STATE_INIT:        return "INIT";
        case EC_STATE_PRE_OP:      return "PRE_OP";
        case EC_STATE_BOOT:        return "BOOT";
        case EC_STATE_SAFE_OP:     return "SAFE_OP";
        case EC_STATE_OPERATIONAL: return "OP";
        default:                   return "UNKNOWN";
    }
}

EC_SUGAR_INLINE uint8_t ec_slave_wc_state(uint16_t mi, uint16_t si) {
    return GetSlaveWcState(mi, si);
}

EC_SUGAR_INLINE int ec_slave_wc_known(uint16_t mi, uint16_t si) {
    return GetSlaveWcState(mi, si) == 0xFF ? 0 : 1;
}

EC_SUGAR_INLINE uint16_t ec_slave_al_mirror(uint16_t mi, uint16_t si) {
    return GetSlaveAlStatusMirror(mi, si);
}

EC_SUGAR_INLINE uint16_t ec_wc_deficit(uint16_t mi) {
    return GetWcDeficit(mi);
}

EC_SUGAR_INLINE uint64_t ec_wc_seq(uint16_t mi) {
    return GetWcStateSeq(mi);
}

EC_SUGAR_INLINE uint16_t ec_mapped_slaves(uint16_t mi) {
    return GetMappedSlaveCount(mi);
}

EC_SUGAR_INLINE uint16_t ec_wkc_actual_mirror(uint16_t mi) {
    return GetWkcActualMirror(mi);
}

EC_SUGAR_INLINE uint16_t ec_wkc_expected_mirror(uint16_t mi) {
    return GetWkcExpectedMirror(mi);
}

EC_SUGAR_INLINE ec_mailbox_health_t ec_slave_mailbox_health(uint16_t mi, uint16_t si) {
    return (ec_mailbox_health_t)GetSlaveMailboxHealth(mi, si);
}

EC_SUGAR_INLINE int ec_slave_freerun_demoted(uint16_t mi, uint16_t si) {
    return GetSlaveFreeRunDemoted(mi, si) != 0 ? 1 : 0;
}

EC_SUGAR_INLINE uint32_t ec_slave_health_degraded_count(uint16_t mi, uint16_t si) {
    return GetSlaveHealthDegradedCount(mi, si);
}

EC_SUGAR_INLINE ec_state_t ec_al_mirror_state(uint16_t mirror) {
    return (ec_state_t)(mirror & 0x00FF);
}

EC_SUGAR_INLINE int ec_al_mirror_has_error(uint16_t mirror) {
    return (mirror & EC_STATE_ERROR) ? 1 : 0;
}

EC_SUGAR_INLINE uint8_t ec_al_mirror_status_code(uint16_t mirror) {
    return (mirror & EC_STATE_ERROR) ? (uint8_t)((mirror >> 8) & 0xFF) : (uint8_t)0;
}

EC_SUGAR_INLINE const char* ec_al_mirror_state_name(uint16_t mirror) {
    return ec_state_name(ec_al_mirror_state(mirror));
}

EC_SUGAR_INLINE int ec_slave_contributed(uint16_t mi, uint16_t si) {
    return GetSlaveWcState(mi, si) == 1 ? 1 : 0;
}

EC_SUGAR_INLINE const char* ec_link_name(ec_link_state_t l) {
    switch (l) {
        case EC_LINK_DOWN:           return "DOWN";
        case EC_LINK_UP:             return "UP";
        case EC_LINK_PRIMARY_ONLY:   return "PRIMARY_ONLY";
        case EC_LINK_SECONDARY_ONLY: return "SECONDARY_ONLY";
        default:                     return "UNKNOWN";
    }
}

#ifdef __cplusplus
}
#endif

#endif
