/*
 * Safe loader/read-only probe for the supplied 32-bit Change.dll.
 *
 * MSVC Win32 build (Developer Command Prompt):
 *   cl /nologo /W4 /TC /D_CRT_SECURE_NO_WARNINGS demo.c change_loader.c
 *
 * MinGW 32-bit build:
 *   i686-w64-mingw32-gcc -std=c11 -Wall -Wextra -o demo.exe demo.c change_loader.c
 *
 * Usage:
 *   demo.exe [path-to-Change.dll]
 *   demo.exe [path-to-Change.dll] --probe-reader
 *
 * The default mode only loads the DLL and resolves all 16 exports.
 * --probe-reader opens the reader, searches for a card and performs a read.
 * This sample never calls CapSetNBCardInfo or CapUpload and cannot debit a card.
 */

#include <stdio.h>
#include <string.h>

#include "Change.h"

static void print_loader_error(int status, const ChangeApi *api)
{
    char system_message[256];
    size_t message_length = 0u;

    fprintf(stderr, "Change_Load failed: %s", Change_LoaderStatusText(status));
    if (api != NULL && api->last_system_error != 0u) {
        message_length = Change_FormatSystemError(
            api->last_system_error, system_message, sizeof(system_message));
        if (message_length > 0u) {
            fprintf(stderr, " (Windows error %lu: %s)",
                    (unsigned long)api->last_system_error, system_message);
        } else {
            fprintf(stderr, " (Windows error %lu)",
                    (unsigned long)api->last_system_error);
        }
    }
    fputc('\n', stderr);
}

static int probe_reader(ChangeApi *api)
{
    CHANGE_LONG result;
    CHANGE_LONG uid = 0;
    CustomerInfo customer;

    result = api->OpenCom();
    if (result != 0) {
        fprintf(stderr, "OpenCom failed: %ld\n", (long)result);
        return 1;
    }

    puts("Reader connection opened.");
    result = api->CapNBQueryCard(&uid);
    if (result != 0) {
        printf("No card detected or query failed: %ld\n", (long)result);
        api->CloseCom();
        return 0;
    }

    memset(&customer, 0, sizeof(customer));
    result = api->CapGetNBCardInfo(&customer);
    if (result == 0) {
        puts("Card read succeeded. Account and card identifiers are intentionally not printed.");
    } else {
        fprintf(stderr, "CapGetNBCardInfo failed: %ld\n", (long)result);
    }

    api->CloseCom();
    puts("Reader connection closed.");
    return result == 0 ? 0 : 1;
}

int main(int argc, char **argv)
{
    const char *dll_path = "Change.dll";
    int should_probe_reader = 0;
    int status;
    int exit_code = 0;
    ChangeApi api;

    if (argc >= 2 && strcmp(argv[1], "--probe-reader") != 0) {
        dll_path = argv[1];
    }
    if ((argc >= 2 && strcmp(argv[1], "--probe-reader") == 0) ||
        (argc >= 3 && strcmp(argv[2], "--probe-reader") == 0)) {
        should_probe_reader = 1;
    }

    printf("ABI: Win32/x86, %s, UPLOADINFO=%lu bytes, psamID offset=%lu\n",
#if defined(CHANGE_USE_STDCALL)
           "__stdcall",
#else
           "__cdecl",
#endif
           (unsigned long)sizeof(UPLOADINFO),
           (unsigned long)offsetof(UPLOADINFO, psamID));

    status = Change_Load(&api, dll_path);
    if (status != CHANGE_LOADER_OK) {
        print_loader_error(status, &api);
        return 1;
    }

    puts("Change.dll loaded; all 16 required exports resolved.");
    if (should_probe_reader) {
        exit_code = probe_reader(&api);
    } else {
        puts("Safe mode complete. No reader, card, WebService or debit operation was invoked.");
    }

    Change_Unload(&api);
    return exit_code;
}
