// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include "iobox_api.h"
#include <cstdint>
#include <memory>
#include <unordered_map>
#include <condition_variable>
#include <mutex>

// Handle registry with refcount — prevents use-after-free when
// ReleaseANSIOHandle is called while an operation is still running.
static std::unordered_map<ANSCENTER::iobox_api*, int>& IOHandleRegistry() {
	static std::unordered_map<ANSCENTER::iobox_api*, int> s;
	return s;
}
static std::mutex& IOHandleRegistryMutex() {
	static std::mutex m;
	return m;
}
static std::condition_variable& IOHandleRegistryCV() {
	static std::condition_variable cv;
	return cv;
}

static void RegisterIOHandle(ANSCENTER::iobox_api* h) {
	std::lock_guard<std::mutex> lk(IOHandleRegistryMutex());
	IOHandleRegistry()[h] = 1;
}

static ANSCENTER::iobox_api* AcquireIOHandle(ANSCENTER::iobox_api* h) {
	std::lock_guard<std::mutex> lk(IOHandleRegistryMutex());
	auto it = IOHandleRegistry().find(h);
	if (it == IOHandleRegistry().end()) return nullptr;
	it->second++;
	return h;
}

static bool ReleaseIOHandleRef(ANSCENTER::iobox_api* h) {
	std::lock_guard<std::mutex> lk(IOHandleRegistryMutex());
	auto it = IOHandleRegistry().find(h);
	if (it == IOHandleRegistry().end()) return false;
	it->second--;
	if (it->second <= 0) {
		IOHandleRegistry().erase(it);
		IOHandleRegistryCV().notify_all();
		return true;
	}
	return false;
}

static bool UnregisterIOHandle(ANSCENTER::iobox_api* h) {
	std::unique_lock<std::mutex> lk(IOHandleRegistryMutex());
	auto it = IOHandleRegistry().find(h);
	if (it == IOHandleRegistry().end()) return false;
	it->second--;
	bool ok = IOHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
		auto it2 = IOHandleRegistry().find(h);
		return it2 == IOHandleRegistry().end() || it2->second <= 0;
	});
	if (!ok) {
		OutputDebugStringA("WARNING: UnregisterIOHandle timed out waiting for in-flight operations\n");
	}
	IOHandleRegistry().erase(h);
	return true;
}

// RAII guard — ensures ReleaseIOHandleRef is always called
class IOHandleGuard {
	ANSCENTER::iobox_api* engine;
public:
	explicit IOHandleGuard(ANSCENTER::iobox_api* e) : engine(e) {}
	~IOHandleGuard() { if (engine) ReleaseIOHandleRef(engine); }
	ANSCENTER::iobox_api* get() const { return engine; }
	explicit operator bool() const { return engine != nullptr; }
	IOHandleGuard(const IOHandleGuard&) = delete;
	IOHandleGuard& operator=(const IOHandleGuard&) = delete;
};

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     ) noexcept
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

// Helper: safely copy a std::string into a LabVIEW LStrHandle.
// Returns 1 on success, 0 on failure (empty string or allocation error).
static int CopyToLStrHandle(LStrHandle handle, const std::string& str) noexcept {
    if (str.empty() || handle == nullptr) return 0;
    const auto size = static_cast<int32>(str.length());
    MgErr error = DSSetHandleSize(handle, sizeof(int32) + size * sizeof(uChar));
    if (error != noErr) return 0;
    (*handle)->cnt = size;
    memcpy((*handle)->str, str.c_str(), static_cast<size_t>(size));
    return 1;
}

// Helper: join a vector of strings with semicolon separator.
static std::string JoinStrings(const std::vector<std::string>& items) {
    std::string result;
    for (size_t i = 0; i < items.size(); ++i) {
        if (i > 0) result += ";";
        result += items[i];
    }
    return result;
}

extern "C" ANSIO_API int  CreateANSIOHandle(ANSCENTER::iobox_api** Handle, const char* multicastIPAddress, int multicastPort) {
    if (Handle == nullptr || multicastIPAddress == nullptr) return 0;
    try {
        // Release existing handle if called twice (prevents leak from LabVIEW)
        if (*Handle) {
            if (UnregisterIOHandle(*Handle)) {
                delete *Handle;
            }
            *Handle = nullptr;
        }

        // std::unique_ptr ensures automatic cleanup on any failure path
        auto ptr = std::make_unique<ANSCENTER::iobox_api>(multicastIPAddress, multicastPort);
        // Transfer ownership to caller on success
        *Handle = ptr.release();
        RegisterIOHandle(*Handle);
        return 1;
    }
    catch (const std::exception&) {
        if (Handle) *Handle = nullptr;
        return 0;
    }
    catch (...) {
        if (Handle) *Handle = nullptr;
        return 0;
    }
}
extern "C" ANSIO_API int  ConnectANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int ioBoxPort, const char* userName, const char* passWord, LStrHandle deviceStr) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || userName == nullptr || passWord == nullptr) return 0;
    try {
        return CopyToLStrHandle(deviceStr, guard.get()->connectToIobox(ioBoxIP, ioBoxPort, userName, passWord));
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}

extern "C" ANSIO_API int  AdvancedConnectANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int ioBoxPort, const char* ioBoxSN, const char* userName, const char* passWord, LStrHandle deviceStr) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || ioBoxSN == nullptr || userName == nullptr || passWord == nullptr) return 0;
    try {
        std::vector<std::string> st = guard.get()->advancedConnectToIobox(ioBoxIP, ioBoxPort, ioBoxSN, userName, passWord);
        if (st.empty()) return 0;
        return CopyToLStrHandle(deviceStr, JoinStrings(st));
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}

extern "C" ANSIO_API int  DisconnectANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP) {
    if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->disconnectToIoboxWithResetOutputs(ioBoxIP) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
static int ReleaseANSIOHandle_Impl(ANSCENTER::iobox_api** Handle) {
    try {
        if (!Handle || !*Handle) return 1;
        if (!UnregisterIOHandle(*Handle)) {
            *Handle = nullptr;
            return 1;
        }
        delete *Handle;
        *Handle = nullptr;
        return 1;
    }
    catch (...) {
        if (Handle) *Handle = nullptr;
        return 0;
    }
}

extern "C" ANSIO_API int  ReleaseANSIOHandle(ANSCENTER::iobox_api** Handle)
{
    __try {
        return ReleaseANSIOHandle_Impl(Handle);
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        if (Handle) *Handle = nullptr;
        return 0;
    }
}

extern "C" ANSIO_API int  SetValueANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, const char* value) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || channelName == nullptr || value == nullptr) return 0;
    try {
        return guard.get()->setValue(ioBoxIP, channelName, value) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}

extern "C" ANSIO_API int  GetValueANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, LStrHandle lStrValue) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || channelName == nullptr) return 0;
    try {
        std::string st = "fail";
        bool success = guard.get()->getValue(ioBoxIP, channelName, st);
        if (!success || st.empty() || st == "fail") return 0;
        return CopyToLStrHandle(lStrValue, st);
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}

extern "C" ANSIO_API int  SetAuthenticationANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* userName, const char* passWord) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || userName == nullptr || passWord == nullptr) return 0;
    try {
        return guard.get()->setAuthenticationIobox(ioBoxIP, userName, passWord) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSIO_API int  ScanANSIOHandle(ANSCENTER::iobox_api** Handle, int timeout, LStrHandle ipAddresses) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    try {
        std::vector<std::string> st = guard.get()->scanNetworkDevicesMulticast(timeout);
        if (st.empty()) return 0;
        return CopyToLStrHandle(ipAddresses, JoinStrings(st));
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSIO_API int  ScanANSIOUnicastHandle(ANSCENTER::iobox_api** Handle, int timeout, LStrHandle ipAddresses) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    try {
        std::vector<std::string> st = guard.get()->scanNetworkDevicesManually(timeout);
        if (st.empty()) return 0;
        return CopyToLStrHandle(ipAddresses, JoinStrings(st));
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSIO_API int  AdvancedScanANSIOHandle(ANSCENTER::iobox_api** Handle, int timeout, LStrHandle deviceInfos) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    try {
        std::vector<std::string> st = guard.get()->advancedScan(timeout);
        if (st.empty()) return 0;
        return CopyToLStrHandle(deviceInfos, JoinStrings(st));
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSIO_API int  AdvancedStaticScanANSIOHandle(int timeout, LStrHandle deviceInfos) {
    try {
        ANSCENTER::iobox_api iobox_api("239.255.255.250", 12345);
        std::vector<std::string> st = iobox_api.advancedScan(timeout);
        if (st.empty()) return 0;
        return CopyToLStrHandle(deviceInfos, JoinStrings(st));
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSIO_API int  ScanANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, int timeout, std::string& ipAddresses) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    try {
        std::vector<std::string> st = guard.get()->scanNetworkDevicesMulticast(timeout);
        if (st.empty()) return 0;
        ipAddresses = JoinStrings(st);
        return 1;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSIO_API int  ScanANSIOUnicastHandle_CPP(ANSCENTER::iobox_api** Handle, int timeout, std::string& ipAddresses) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    try {
        std::vector<std::string> st = guard.get()->scanNetworkDevicesManually(timeout);
        if (st.empty()) return 0;
        ipAddresses = JoinStrings(st);
        return 1;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSIO_API int  AdvancedScanANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, int timeout, std::string& deviceInfos) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    try {
        std::vector<std::string> st = guard.get()->advancedScan(timeout);
        if (st.empty()) return 0;
        deviceInfos = JoinStrings(st);
        return 1;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSIO_API int  AdvancedStaticScanANSIOHandle_CPP(int timeout, std::string& deviceInfos)
{
    try {
        ANSCENTER::iobox_api iobox_api("239.255.255.250", 12345);
        std::vector<std::string> st = iobox_api.advancedScan(timeout);
        if (st.empty()) return 0;
        deviceInfos = JoinStrings(st);
        if (deviceInfos.empty()) return 0;
        return 1;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSIO_API int  GetChannelNamesANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int timeout, LStrHandle channelNames) {
    if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    try {
        std::vector<std::string> st = guard.get()->getDeviceChannelNames(ioBoxIP);
        if (st.empty()) return 0;
        return CopyToLStrHandle(channelNames, JoinStrings(st));
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSIO_API int  GetValueANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, std::string& lStrValue) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || channelName == nullptr) return 0;
    try {
        std::string st = "fail";
        bool success = guard.get()->getValue(ioBoxIP, channelName, st);
        if (!success || st.empty() || st == "fail") return 0;
        lStrValue = st;
        return 1;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}

extern "C" ANSIO_API int  GetChannelNamesANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int timeout, std::string& channelNames) {
    if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    try {
        std::vector<std::string> st = guard.get()->getDeviceChannelNames(ioBoxIP);
        if (st.empty()) return 0;
        channelNames = JoinStrings(st);
        return 1;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}

extern "C" ANSIO_API int  ResetAuthenticationANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* token) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || token == nullptr) return 0;
    try {
        return guard.get()->resetAuthenticationIobox(ioBoxIP, token) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSIO_API int  ResetANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* token) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || token == nullptr) return 0;
    try {
        return guard.get()->resetIobox(ioBoxIP, token) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSIO_API int  GenerateANSIOTokenHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, LStrHandle tokenStr) {
    if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    try {
        return CopyToLStrHandle(tokenStr, guard.get()->generateToken(ioBoxIP));
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}

extern "C" ANSIO_API int  GenerateANSIOTokenHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, std::string& tokenStr) {
    if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    try {
        std::string st = guard.get()->generateToken(ioBoxIP);
        if (st.empty()) return 0;
        tokenStr = st;
        return 1;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSIO_API int  ConnectANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int ioBoxPort, const char* userName, const char* passWord, std::string& deviceStr) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || userName == nullptr || passWord == nullptr) return 0;
    try {
        std::string st = guard.get()->connectToIobox(ioBoxIP, ioBoxPort, userName, passWord);
        if (st.empty()) return 0;
        deviceStr = st;
        return 1;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}

extern "C" ANSIO_API int  AdvancedConnectANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int ioBoxPort, const char* ioBoxSN, const char* userName, const char* passWord, std::string& deviceStr) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || ioBoxSN == nullptr || userName == nullptr || passWord == nullptr) return 0;
    try {
        std::vector<std::string> st = guard.get()->advancedConnectToIobox(ioBoxIP, ioBoxPort, ioBoxSN, userName, passWord);
        if (st.empty()) return 0;
        deviceStr = JoinStrings(st);
        return 1;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}


extern "C" ANSIO_API int  CheckANSIOStatusHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP) {
    if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->checkTcpConnectStatus(ioBoxIP) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}

extern "C" ANSIO_API int  OpenANSAIRS232Port(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int baudrate, int DataBits, int stopBits, int parityBits) {
    if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->openRs232Port(ioBoxIP, baudrate, DataBits, stopBits, parityBits) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSIO_API int  CloseANSAIRS232Port(ANSCENTER::iobox_api** Handle, const char* ioBoxIP) {
    if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    try {
        return guard.get()->closeRs232Port(ioBoxIP) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSIO_API int  WriteANSAIRS232Port(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* data, int timeout_ms) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || data == nullptr) return 0;
    try {
        return guard.get()->writeRs232Port(ioBoxIP, data, timeout_ms) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSIO_API int  ReadANSAIRS232Port(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* terminatorString, int lenExpect, int timeout_ms, LStrHandle receivedData) {
    if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    try {
        const char* safeTerminator = (terminatorString != nullptr) ? terminatorString : "";
        return CopyToLStrHandle(receivedData, guard.get()->readRs232Port(ioBoxIP, safeTerminator, lenExpect, timeout_ms));
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}

// OTA
extern "C" ANSIO_API int  OTAANSIOFirmwareDevice(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* filename, const char* type) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || filename == nullptr || type == nullptr) return 0;
    try {
        return guard.get()->otaFirmwareDevice(ioBoxIP, filename, type) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}

// Synchronous version (existing behavior)
extern "C" ANSIO_API int ToggleIoboxHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, int timeOut, int revertFlag, int resetFlag) {
    try {
        // Input validation
        if (Handle == nullptr || *Handle == nullptr) {
            return -1; // Invalid handle
        }
        IOHandleGuard guard(AcquireIOHandle(*Handle));
        if (!guard) return -1;

        if (ioBoxIP == nullptr || channelName == nullptr) {
            return -2; // Invalid parameters
        }

        if (timeOut < 0) {
            return -3; // Invalid timeout
        }

        // Convert C parameters to C++ types
        std::string remote(ioBoxIP);
        std::string channel(channelName);
        bool revert = (revertFlag != 0);
        bool reset = (resetFlag != 0);

        // Call synchronous version (asyncMode = false)
        bool result = guard.get()->toggleIobox(remote, channel, timeOut, revert, reset, false);

        return result ? 1 : 0;

    }
    catch (const std::exception&) {
        return -4; // Exception occurred
    }
    catch (...) {
        return -5; // Unknown exception
    }
}

// Asynchronous version (new function)
extern "C" ANSIO_API int ToggleIoboxHandleAsync(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, int timeOut, int revertFlag, int resetFlag) {
    try {
        // Input validation
        if (Handle == nullptr || *Handle == nullptr) {
            return -1; // Invalid handle
        }
        IOHandleGuard guard(AcquireIOHandle(*Handle));
        if (!guard) return -1;

        if (ioBoxIP == nullptr || channelName == nullptr) {
            return -2; // Invalid parameters
        }

        if (timeOut < 0) {
            return -3; // Invalid timeout
        }

        // Convert C parameters to C++ types
        std::string remote(ioBoxIP);
        std::string channel(channelName);
        bool revert = (revertFlag != 0);
        bool reset = (resetFlag != 0);

        // Call asynchronous version (asyncMode = true)
        bool result = guard.get()->toggleIobox(remote, channel, timeOut, revert, reset, true);

        return result ? 1 : 0; // Returns immediately

    }
    catch (const std::exception&) {
        return -4; // Exception occurred
    }
    catch (...) {
        return -5; // Unknown exception
    }
}


extern "C" ANSIO_API int  GetStaticIpConfigANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, LStrHandle staticIpConfigInfo) {
    if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    try {
        std::vector<std::string> configs = guard.get()->getStaticIpConfig(ioBoxIP);
        if (configs.empty()) return 0;
        return CopyToLStrHandle(staticIpConfigInfo, JoinStrings(configs));
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSIO_API int  SetStaticIpConfigANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int enable, const char* ip, const char* gw, const char* nm) {
    if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    if (ip == nullptr || gw == nullptr || nm == nullptr) return 0;
    try {
        return guard.get()->setStaticIpConfig(ioBoxIP, enable != 0, ip, gw, nm) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSIO_API int  GetValueDataStringIoboxFromChannelNameANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, LStrHandle dataValue) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || channelName == nullptr) return 0;
    try {
        return CopyToLStrHandle(dataValue, guard.get()->getValueDataStringIoboxFromChannelName(ioBoxIP, channelName));
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSIO_API int  ToggleDigitalOutputANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, int  milliseconds, int invertFlag, int resetFlag) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || channelName == nullptr) return 0;
    try {
        return guard.get()->toggleDigitalOutput(ioBoxIP, channelName, std::to_string(milliseconds), invertFlag != 0, resetFlag != 0) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}
extern "C" ANSIO_API int  SetAIBValueDataStringIoboxFromChannelNameANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, const char* value) {
    if (Handle == nullptr || *Handle == nullptr) return 0;
    IOHandleGuard guard(AcquireIOHandle(*Handle));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || channelName == nullptr || value == nullptr) return 0;
    try {
        return guard.get()->setAIBValueDataStringIoboxFromChannelName(ioBoxIP, channelName, value) ? 1 : 0;
    }
    catch (const std::exception&) {
        return 0;
    }
    catch (...) {
        return 0;
    }
}

// ============================================================================
// V2 API — handle passed by value (uint64_t) to avoid LabVIEW buffer reuse bug
// ============================================================================

extern "C" ANSIO_API int ConnectANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, int ioBoxPort, const char* userName, const char* passWord, LStrHandle deviceStr) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || userName == nullptr || passWord == nullptr) return 0;
    try {
        return CopyToLStrHandle(deviceStr, guard.get()->connectToIobox(ioBoxIP, ioBoxPort, userName, passWord));
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int AdvancedConnectANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, int ioBoxPort, const char* ioBoxSN, const char* userName, const char* passWord, LStrHandle deviceStr) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || ioBoxSN == nullptr || userName == nullptr || passWord == nullptr) return 0;
    try {
        std::vector<std::string> st = guard.get()->advancedConnectToIobox(ioBoxIP, ioBoxPort, ioBoxSN, userName, passWord);
        if (st.empty()) return 0;
        return CopyToLStrHandle(deviceStr, JoinStrings(st));
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int DisconnectANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr) return 0;
    try {
        return guard.get()->disconnectToIoboxWithResetOutputs(ioBoxIP) ? 1 : 0;
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int CheckANSIOStatusHandle_V2(uint64_t handleVal, const char* ioBoxIP) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr) return 0;
    try {
        return guard.get()->checkTcpConnectStatus(ioBoxIP) ? 1 : 0;
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int SetValueANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, const char* channelName, const char* value) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || channelName == nullptr || value == nullptr) return 0;
    try {
        return guard.get()->setValue(ioBoxIP, channelName, value) ? 1 : 0;
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int GetValueANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, const char* channelName, LStrHandle lStrValue) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || channelName == nullptr) return 0;
    try {
        std::string st = "fail";
        bool success = guard.get()->getValue(ioBoxIP, channelName, st);
        if (!success || st.empty() || st == "fail") return 0;
        return CopyToLStrHandle(lStrValue, st);
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int GetValueDataStringIoboxFromChannelNameANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, const char* channelName, LStrHandle dataValue) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || channelName == nullptr) return 0;
    try {
        return CopyToLStrHandle(dataValue, guard.get()->getValueDataStringIoboxFromChannelName(ioBoxIP, channelName));
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int SetAIBValueDataStringIoboxFromChannelNameANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, const char* channelName, const char* value) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || channelName == nullptr || value == nullptr) return 0;
    try {
        return guard.get()->setAIBValueDataStringIoboxFromChannelName(ioBoxIP, channelName, value) ? 1 : 0;
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int SetAuthenticationANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, const char* userName, const char* passWord) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || userName == nullptr || passWord == nullptr) return 0;
    try {
        return guard.get()->setAuthenticationIobox(ioBoxIP, userName, passWord) ? 1 : 0;
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int ResetAuthenticationANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, const char* token) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || token == nullptr) return 0;
    try {
        return guard.get()->resetAuthenticationIobox(ioBoxIP, token) ? 1 : 0;
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int GenerateANSIOTokenHandle_V2(uint64_t handleVal, const char* ioBoxIP, LStrHandle tokenStr) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr) return 0;
    try {
        return CopyToLStrHandle(tokenStr, guard.get()->generateToken(ioBoxIP));
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int ScanANSIOHandle_V2(uint64_t handleVal, int timeout, LStrHandle ipAddresses) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    try {
        std::vector<std::string> st = guard.get()->scanNetworkDevicesMulticast(timeout);
        if (st.empty()) return 0;
        return CopyToLStrHandle(ipAddresses, JoinStrings(st));
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int ScanANSIOUnicastHandle_V2(uint64_t handleVal, int timeout, LStrHandle ipAddresses) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    try {
        std::vector<std::string> st = guard.get()->scanNetworkDevicesManually(timeout);
        if (st.empty()) return 0;
        return CopyToLStrHandle(ipAddresses, JoinStrings(st));
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int AdvancedScanANSIOHandle_V2(uint64_t handleVal, int timeout, LStrHandle deviceInfos) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    try {
        std::vector<std::string> st = guard.get()->advancedScan(timeout);
        if (st.empty()) return 0;
        return CopyToLStrHandle(deviceInfos, JoinStrings(st));
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int GetChannelNamesANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, int timeout, LStrHandle channelNames) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr) return 0;
    try {
        std::vector<std::string> st = guard.get()->getDeviceChannelNames(ioBoxIP);
        if (st.empty()) return 0;
        return CopyToLStrHandle(channelNames, JoinStrings(st));
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int ResetANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, const char* token) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || token == nullptr) return 0;
    try {
        return guard.get()->resetIobox(ioBoxIP, token) ? 1 : 0;
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int ToggleIoboxHandle_V2(uint64_t handleVal, const char* ioBoxIP, const char* channelName, int timeOut, int revertFlag, int resetFlag) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return -1;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return -1;
    if (ioBoxIP == nullptr || channelName == nullptr) return -2;
    if (timeOut < 0) return -3;
    try {
        std::string remote(ioBoxIP);
        std::string channel(channelName);
        bool revert = (revertFlag != 0);
        bool reset = (resetFlag != 0);
        bool result = guard.get()->toggleIobox(remote, channel, timeOut, revert, reset, false);
        return result ? 1 : 0;
    }
    catch (const std::exception&) { return -4; }
    catch (...) { return -5; }
}

extern "C" ANSIO_API int ToggleIoboxHandleAsync_V2(uint64_t handleVal, const char* ioBoxIP, const char* channelName, int timeOut, int revertFlag, int resetFlag) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return -1;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return -1;
    if (ioBoxIP == nullptr || channelName == nullptr) return -2;
    if (timeOut < 0) return -3;
    try {
        std::string remote(ioBoxIP);
        std::string channel(channelName);
        bool revert = (revertFlag != 0);
        bool reset = (resetFlag != 0);
        bool result = guard.get()->toggleIobox(remote, channel, timeOut, revert, reset, true);
        return result ? 1 : 0;
    }
    catch (const std::exception&) { return -4; }
    catch (...) { return -5; }
}

extern "C" ANSIO_API int ToggleDigitalOutputANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, const char* channelName, int milliseconds, int invertFlag, int resetFlag) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || channelName == nullptr) return 0;
    try {
        return guard.get()->toggleDigitalOutput(ioBoxIP, channelName, std::to_string(milliseconds), invertFlag != 0, resetFlag != 0) ? 1 : 0;
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int OpenANSAIRS232Port_V2(uint64_t handleVal, const char* ioBoxIP, int baudrate, int DataBits, int stopBits, int parityBits) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr) return 0;
    try {
        return guard.get()->openRs232Port(ioBoxIP, baudrate, DataBits, stopBits, parityBits) ? 1 : 0;
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int CloseANSAIRS232Port_V2(uint64_t handleVal, const char* ioBoxIP) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr) return 0;
    try {
        return guard.get()->closeRs232Port(ioBoxIP) ? 1 : 0;
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int WriteANSAIRS232Port_V2(uint64_t handleVal, const char* ioBoxIP, const char* data, int timeout_ms) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || data == nullptr) return 0;
    try {
        return guard.get()->writeRs232Port(ioBoxIP, data, timeout_ms) ? 1 : 0;
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int ReadANSAIRS232Port_V2(uint64_t handleVal, const char* ioBoxIP, const char* terminatorString, int lenExpect, int timeout_ms, LStrHandle receivedData) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr) return 0;
    try {
        const char* safeTerminator = (terminatorString != nullptr) ? terminatorString : "";
        return CopyToLStrHandle(receivedData, guard.get()->readRs232Port(ioBoxIP, safeTerminator, lenExpect, timeout_ms));
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int GetStaticIpConfigANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, LStrHandle staticIpConfigInfo) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr) return 0;
    try {
        std::vector<std::string> configs = guard.get()->getStaticIpConfig(ioBoxIP);
        if (configs.empty()) return 0;
        return CopyToLStrHandle(staticIpConfigInfo, JoinStrings(configs));
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int SetStaticIpConfigANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, int enable, const char* ip, const char* gw, const char* nm) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || ip == nullptr || gw == nullptr || nm == nullptr) return 0;
    try {
        return guard.get()->setStaticIpConfig(ioBoxIP, enable != 0, ip, gw, nm) ? 1 : 0;
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

extern "C" ANSIO_API int OTAANSIOFirmwareDevice_V2(uint64_t handleVal, const char* ioBoxIP, const char* filename, const char* type) {
    auto* _v2h = reinterpret_cast<ANSCENTER::iobox_api*>(handleVal); if (!_v2h) return 0;
    IOHandleGuard guard(AcquireIOHandle(_v2h));
    if (!guard) return 0;
    if (ioBoxIP == nullptr || filename == nullptr || type == nullptr) return 0;
    try {
        return guard.get()->otaFirmwareDevice(ioBoxIP, filename, type) ? 1 : 0;
    }
    catch (const std::exception&) { return 0; }
    catch (...) { return 0; }
}

// End of ANSIO/dllmain.cpp
