#!/usr/bin/env fun

/*
 * This file is part of the Fun programming language.
 * https://fun-lang.xyz/
 *
 * Copyright 2025 Johannes Findeisen <you@hanez.org>
 * Licensed under the terms of the Apache-2.0 license.
 * https://opensource.org/license/apache-2-0
 *
 * Added: 2025-10-04
 */

// PCSC2 stdlib abstraction class wrapping VM PC/SC opcodes.
// Goal: Provide clean, object-oriented access to PC/SC with safe fallbacks
// when the VM is built without PCSC support. All methods avoid throwing and
// return neutral values (0, [], or a default map).

include <hex.fun>

class PCSC2()
  // Establish a new PC/SC context. Returns ctx id (>0) or 0 if unavailable.
  fun establish(this)
    res = pcsc_establish()
    if res == nil
      return 0
    return res

  // Release a PC/SC context. Returns 1 on success, 0 otherwise.
  fun release(this, ctx)
    res = pcsc_release(ctx)
    if res == nil
      return 0
    return res

  // List available reader names for a context. Returns [] on failure.
  fun list_readers(this, ctx)
    readers = pcsc_list_readers(ctx)
    if readers == nil
      return []
    return readers

  // Connect to a given reader name for a context. Returns handle id (>0) or 0.
  fun connect(this, ctx, reader_name)
    res = pcsc_connect(ctx, to_string(reader_name))
    if res == nil
      return 0
    return res

  // Disconnect a card handle. Returns 1 on success or 0.
  fun disconnect(this, handle)
    res = pcsc_disconnect(handle)
    if res == nil
      return 0
    return res

  // Transmit raw APDU bytes (array of numbers 0..255).
  // Returns map {"data":[], "sw1":n, "sw2":n, "code":n}
  fun transmit_bytes(this, handle, bytes)
    res = pcsc_transmit(handle, bytes)
    // Normalize to map regardless of VM build
    if res == nil
      m = {}
      m["data"] = []
      m["sw1"] = -1
      m["sw2"] = -1
      m["code"] = -2
      return m
    t = typeof(res)
    if t != "Map"
      m = {}
      m["data"] = []
      m["sw1"] = -1
      m["sw2"] = -1
      m["code"] = -2
      return m
    if res["data"] == nil
      res["data"] = []
    return res

  // Transmit hex APDU string. Returns a convenience map with hex payload too:
  // {"data_hex":string, "sw1":n, "sw2":n, "code":n}
  fun transmit_hex(this, handle, hex)
    arr = hex_to_bytes(hex)
    res = pcsc_transmit(handle, arr)
    // Normalize result to a map first
    number sw1 = -1
    number sw2 = -1
    number code = -2
    data_arr = []
    if res != nil && typeof(res) == "Map"
      if res["sw1"] != nil
        sw1 = res["sw1"]
      if res["sw2"] != nil
        sw2 = res["sw2"]
      if res["code"] != nil
        code = res["code"]
      if res["data"] != nil
        data_arr = res["data"]
    dh = bytes_to_hex(data_arr)
    m = {}
    m["data_hex"] = dh
    m["sw1"] = sw1
    m["sw2"] = sw2
    m["code"] = code
    return m
