//
// NixUniversalSDK.Wrapper.h
// NixUniversalSDK.Wrapper
// 
// Exported functions that can be called from C/C++
//
// Created by James Strack on 2024-12-09.
// Copyright © 2023-2024 Nix Sensor Ltd. All rights reserved.
//

#ifndef NixUniversalSDK_Wrapper_h
#define NixUniversalSDK_Wrapper_h

/// CommandStatus enum values
/// Refer to https://nixsensor.github.io/nix-universal-sdk-windows-doc/api/NixUniversalSDK.CommandStatus.html
#define CommandStatus_Success                           0
#define CommandStatus_ErrorNotReady                     1
#define CommandStatus_ErrorNotSupported                 2
#define CommandStatus_ErrorInvalidArgument              3
#define CommandStatus_ErrorLowPower                     4
#define CommandStatus_ErrorTimeout                      5
#define CommandStatus_ErrorAmbientLight                 6
#define CommandStatus_ErrorScanDelta                    7
#define CommandStatus_ErrorInternal                     8
#define CommandStatus_WarningTemperature                9
#define CommandStatus_ErrorLicense                      10

/// DeviceScannerState enum values
/// Refer to https://nixsensor.github.io/nix-universal-sdk-windows-doc/api/NixUniversalSDK.DeviceScannerState.html
#define DeviceScannerState_Cold                         -1
#define DeviceScannerState_Idle                         0
#define DeviceScannerState_Scanning                     1
#define DeviceScannerState_ErrorBluetoothPermissions    2
#define DeviceScannerState_ErrorBluetoothDisabled       3
#define DeviceScannerState_ErrorBluetoothUnavailable    4
#define DeviceScannerState_ErrorInvalidHardwareId       5
#define DeviceScannerState_ErrorInternal                6
#define DeviceScannerState_ErrorLicense                 7

/// DeviceState enum values
/// Refer to https://nixsensor.github.io/nix-universal-sdk-windows-doc/api/NixUniversalSDK.DeviceState.html
#define DeviceState_Disconnected                        0
#define DeviceState_BusyConnnecting                     1
#define DeviceState_BusyDiscovering                     2
#define DeviceState_BusySubscribing                     3
#define DeviceState_BusyDataTransfer                    4
#define DeviceState_BusyRunningCommand                  5
#define DeviceState_Idle                                6

/// DeviceStatus enum values
/// Refer to https://nixsensor.github.io/nix-universal-sdk-windows-doc/api/NixUniversalSDK.DeviceStatus.html
#define DeviceStatus_Success                            0
#define DeviceStatus_ErrorMaxAttempts                   1
#define DeviceStatus_ErrorTimeout                       2
#define DeviceStatus_ErrorUnsupportedDevice             3
#define DeviceStatus_ErrorDroppedConnection             4
#define DeviceStatus_ErrorUnauthorized                  5
#define DeviceStatus_ErrorInternal                      6
#define DeviceStatus_ErrorLicense                       7

/// DeviceType enum values
/// Refer to https://nixsensor.github.io/nix-universal-sdk-windows-doc/api/NixUniversalSDK.DeviceType.html
#define DeviceType_Mini                                 0
#define DeviceType_Mini2                                1
#define DeviceType_Pro                                  2
#define DeviceType_Pro2                                 3
#define DeviceType_QC                                   4
#define DeviceType_Spectro2                             5
#define DeviceType_Mini3                                6
#define DeviceType_SpectroL                             7
#define DeviceType_Unknown                              255

/// InterfaceType enum values
/// Refer to https://nixsensor.github.io/nix-universal-sdk-windows-doc/api/NixUniversalSDK.InterfaceType.html
#define InterfaceType_Undefined                         0
#define InterfaceType_Ble                               1
#define InterfaceType_UsbCdc                            2

/// LicenseFeature enum values
/// Refer to https://nixsensor.github.io/nix-universal-sdk-windows-doc/api/NixUniversalSDK.LicenseFeature.html
#define LicenseFeature_BasicData                        0
#define LicenseFeature_DensityData                      1
#define LicenseFeature_SpectralData                     2

/// LicenseManagerState enum values
/// Refer to https://nixsensor.github.io/nix-universal-sdk-windows-doc/api/NixUniversalSDK.LicenseManagerState.html
#define LicenseManagerState_Inactive                    0
#define LicenseManagerState_Active                      1
#define LicenseManagerState_ErrorLicenseBadSignature    2
#define LicenseManagerState_ErrorLicenseInvalidOptions  3
#define LicenseManagerState_ErrorLicenseExpired         4
#define LicenseManagerState_ErrorInternal               -1

#ifdef __cplusplus
extern "C" {
#endif // !__cplusplus

#include <stdbool.h>
#include <stdint.h>

/// <summary>
/// Gets the vendor identifier for the current license. This function is deprecated and has been replaced by License_GetUuid().
/// </summary>
extern const char* GetSdkId(void);

/// <summary>
/// Gets the current `LicenseManager` state as a 32-bit signed integer.
/// </summary>
extern int32_t License_GetState(void);

/// <summary>
/// Gets a list of Nix device allocation codes associated with the current license formatted as a JSON array.
/// </summary>
extern const char* License_GetAllocations(void);

/// <summary>
/// Gets a list of device types supported by the current license, formatted as a JSON array of integer values.
/// </summary>
extern const char* License_GetAllowedDeviceTypes(void);

/// <summary>
/// Gets the expiry time for the current license represented as an unsigned 64-bit integer. This corresponds to the milliseconds since the Unix epoch (January 1, 1970 00:00 UTC).
/// </summary>
extern uint64_t License_GetExpiryJavaTicks(void);

/// <summary>
/// Gets a list of supported features for the current license, formatted as a JSON array of integer values.
/// </summary>
extern const char* License_GetFeatures(void);

/// <summary>
/// Gets the vendor identifier for the current license.
/// </summary>
extern const char* License_GetUuid(void);

/// <summary>
/// Gets the current version of the `NixUniversalSDK`.
/// </summary>
extern const char* License_GetLibraryVersion(void);

/// <summary>
/// Gets the current version of the wrapper library for the `NixUniversalSDK`.
/// </summary>
extern const char* License_GetLibraryWrapperVersion(void);

/// <summary>
/// Checks if the current license supports the specified device type (signed 32-bit integer value).
/// </summary>
/// <param name="type>Device type to query (see `DeviceType` enum values defined above)</param>
extern bool License_IsDeviceTypeSupported(int32_t type);

/// <summary>
/// Checks if the current license supports the specified feature (signed 32-bit integer value).
/// </summary>
/// <param name="feature">Feature type to query (see `LicenseFeature` enum values defined above)</param>
extern bool License_IsFeatureEnabled(int32_t feature);

/// <summary>
/// Activates a license. The options and signature parameters must exactly match the values provided in the SDK license. Calling this function invalidates any currently active license. Any connected device will be disconnected.
/// </summary>
/// <param name="options">License options string.</param>
/// <param name="signature">License signature string, used to validate the license options.</param>
/// <returns>License manager state after activation as a 32-bit signed integer.</returns>
extern int32_t License_Activate(
    const char* options, 
    const char* signature);

/// <summary>
/// Deactivates the current license. Any connected device will be disconnected.
/// </summary>
extern void License_Deactivate(void);

/// <summary>
/// Gets the current `IDeviceScanner` state as an integer
/// </summary>
extern int32_t Scanner_GetState(void); 

/// <summary>
/// Checks if the specified device ID has been found by the `IDeviceScanner`
/// </summary>
/// <param name="id">ID value to query, corresponding to `IDeviceCompat.Id`</param>
/// <returns>True if the device has been found</returns>
extern bool Scanner_HasFoundDevice(const char* id);

/// <summary>
///  Gets a snapshot of the nearby devices list, sorted by signal strength and serialized as a JSON string. This command only provides a snapshot of the list, but does not update it. The list is updated while the `IDeviceScanner` is running; to update the list, call `Scanner_Start()` or `Scanner_SearchForId()`
/// </summary>
/// <param name="maxCount">Maximum number of devices to report. Set to -1 to report all devices</param>
/// <returns>List of nearby devices serialized as JSON string</returns>
/// <example>
/// An example of calling this function from C is shown below:
/// <code>
/// const char* list = Scanner_GetSortedResults(5);
/// </code>
/// Example JSON output:
/// <code>
/// [
///     {
///         "id": "COM3",
///         "interfaceType": 2,
///         "name": "Nix Spectro 2",
///         "rssi": 0,
///         "type": 5
///     },
///     {
///         "id": "D2:4F:5C:5C:54:40",
///         "interfaceType": 1,
///         "name": "Nix Mini 3",
///         "rssi": -50,
///         "type": 6
///     },
///     {
///         "id": "F8:CA:CF:4A:3C:03",
///         "interfaceType": 1,
///         "name": "Nix Spectro 2",
///         "rssi": -53,
///         "type": 5
///     },
///     {
///         "id": "D0:92:BA:D3:13:3A",
///         "interfaceType": 1,
///         "name": "Nix Spectro 2",
///         "rssi": -54,
///         "type": 5
///     },
///     {
///         "id": "CB:80:63:06:CD:9F",
///         "interfaceType": 1,
///         "name": "Nix Spectro 2",
///         "rssi": -55,
///         "type": 5
///     }
/// ]
/// </code>
/// </example>
extern const char* Scanner_GetSortedResults(int32_t maxCount);

/// <summary>
/// Checks the Bluetooth adapter state again and resets the `IDeviceScanner` instance. This will invoke the `ScannerCreated` callback upon completion.
/// </summary>
extern void Scanner_Reset(void);

/// <summary>
/// Starts a device search for the specified length of time, maximum callback interval, and report length. This will invoke the `ScannerStarted` callback on start, `ScannerStopped` callback on stop, and `ScanResult` callback when the device list updates.
/// </summary>
/// <param name="scanPeriodMs">Length of time in milliseconds to run the device search, as an integer</param>
/// <param name="maxReportIntervalMs"> Maximum interval in milliseconds to invoke the `ScanResult` callback, as an integer</param>
/// <param name="maxReportCount">Maximum number of devices to report in the `ScanResult` callback, as an integer</param>
extern void Scanner_Start(
    int32_t scanPeriodMs,
    int32_t maxReportIntervalMs,
    int32_t maxReportCount);

/// <summary>
/// Stops a device search if one is currently running. This will invoke the `ScannerStopped` callback once the scanner changes from a running state to a stopped state.
/// </summary>
extern void Scanner_Stop(void);

/// <summary>
/// Searches for a specific Nix device via USB and Bluetooth. The search will run until the specified device is found, or until the specified time interval elapses, whichever is shorter. This will invoke the `ScanResult` callback when the device is found.
/// </summary>
/// <param name="deviceId">Specific device ID to find</param>
/// <param name="scanPeriodMs">Maximum time period in milliseconds to run the search, as an integer</param>
extern void Scanner_SearchForId(
    const char* deviceId,
    int32_t scanPeriodMs);

/// <summary>
///  Runs a listing for all available Nix devices attached via USB. This will invoke the `ScanResult` callback when the listing is complete.
/// </summary>
extern void Scanner_ListUsbDevices(void);

/// <summary>
/// Registers a callback function for the `ScannerCreated` callback. The callback takes two arguments: a string (name of the calling event) and an integer corresponding to the `DeviceScannerState` after initialization.
/// </summary>
extern void Scanner_RegisterCreated(
    void (*callback)(const char*, int32_t));

/// <summary>
/// Registers a callback function for the `ScannerStarted` callback. The callback takes one string argument (name of the calling event).
/// </summary>
extern void Scanner_RegisterStarted(
    void (*callback)(const char*));

/// <summary>
/// Registers a callback function for the `ScannerStopped` callback. The callback takes one string argument (name of the calling event).
/// </summary>
extern void Scanner_RegisterStopped(
    void (*callback)(const char*));

/// <summary>
/// Registers a callback function for the `ScanResult` callback. The callback takes two arguments: a string (name of the calling event), and a string containing JSON formatted list scan results.
/// </summary>
extern void Scanner_RegisterScanResult(
    void (*callback)(const char*, const char*));

/// <summary>
/// Gets `Id` for the current device as a UTF8 string, or empty if no device is selected.
/// </summary>
extern const char* Device_GetId(void);

/// <summary>
/// Gets `State` for the current device as an integer. See `DeviceState` enum for the possible values.
/// </summary>
extern int32_t Device_GetState(void);

/// <summary>
/// Gets `Type` for the current device as an integer. See `DeviceType` enum for the possible values.
/// </summary>
extern int32_t Device_GetType(void);

/// <summary>
/// Gets `InterfaceType` for the current device as an integer. See the `InterfaceType` enum for the possible values.
/// </summary>
extern int32_t Device_GetInterfaceType(void);

/// <summary>
/// Gets `Name` for the current device as a UTF8 string, or empty if no device is selected.
/// </summary>
extern const char* Device_GetName(void);

/// <summary>
/// Gets `Note` for the current device as a UTF8 string. This value is valid only after a connection been opened.
/// </summary>
extern const char* Device_GetNote(void);

/// <summary>
/// Gets `SerialNumber` for the current device as a UTF8 string. This value is valid only after a connection been opened.
/// </summary>
extern const char* Device_GetSerialNumber(void);

/// <summary>
/// Gets `FirmwareVersion` for the current device as a UTF8 string. This value is valid only after a connection been opened.
/// </summary>
extern const char* Device_GetFirmwareVersion(void);

/// <summary>
/// Gets `HardwareVersion` for the current device as a UTF8 string. This value is valid only after a connection been opened.
/// </summary>
extern const char* Device_GetHardwareVersion(void);

/// <summary>
/// Gets `SoftwareVersion` for the current device as a UTF8 string. This value is valid only after a connection been opened.
/// </summary>
extern const char* Device_GetSoftwareVersion(void);

/// <summary>
/// Gets `BatteryLevel` for the current device as an integer. Range is 0 - 100, or -1 if not available. This value is valid only after a connection been opened.
/// </summary>
extern int32_t Device_GetBatteryLevel(void);

/// <summary>
/// Gets `PowerState` for the current device; `true` if sufficient power is available to complete a measurement, `false` if a measurement will be aborted. This value is valid only after a connection been opened.
/// </summary>
extern bool Device_GetPowerState(void);

/// <summary>
/// Gets `ExtPowerState` for the current device. This value is valid only after a connection been opened.
/// </summary>
extern bool Device_GetExtPowerState(void);

/// <summary>
/// Gets `ScanTemperature` for the current device as a 32-bit float, or -2048 if not available. This value is valid only if a device is connected and a measurement has completed.
/// </summary>
extern float Device_GetScanTemperature(void);

/// <summary>
/// Gets `ReferenceTemperature` for the current device as a 32-bit float, or -2048 if not available. This value is valid only if a device is connected.
/// </summary>
extern float Device_GetReferenceTemperature(void);

/// <summary>
/// Gets `ReferenceDate` for the current device, represented as a 64-bit unsigned integer, or 0 if not supported. This corresponds to the milliseconds since the Unix epoch (January 1, 1970 00:00 UTC).
/// </summary>
extern uint64_t Device_GetReferenceJavaTicks(void);

/// <summary>
/// Gets `ScanCount` for the current device as an unsigned 32-bit integer, or 0 if not supported. This value is valid only if a device is connected.
/// </summary>
extern uint32_t Device_GetScanCount(void);

/// <summary>
/// Gets `SupportedModes` for the current device, formatted as a JSON array of string values (scan mode names). This value is valid only after a connection been opened.
/// </summary>
extern const char* Device_GetSupportedModes(void);

/// <summary>
/// Gets `ProvidesSpectral` for the current device. This value is valid only after a connection been opened.
/// </summary>
extern bool Device_GetProvidesSpectral(void);

/// <summary>
/// Gets `ProvidesDensity` for the current device. This value is valid only after a connection been opened.
/// </summary>
extern bool Device_GetProvidesDensity(void);

/// <summary>
/// Gets `SupportedReferences` for the current device, formatted as a JSON array of string values (reference names). This value is valid only after a connection been opened.
/// </summary>
extern const char* Device_GetSupportedReferences(void);

/// <summary>
/// Flag to indicate if any on-device options are available. Value is `true` if any one of `SupportsFieldCalibration`, `SupportsTemperatureCompensation`, `SupportsHapticFeedback`,  or `SupportsRgbFeedback` is true.
/// </summary>
extern bool Device_HasOptions(void);

/// <summary>
/// Flag to indicate if this device supports in-field calibration using the provided reference tile.
/// </summary>
extern bool Device_GetSupportsFieldCalibration(void);

/// <summary>
/// Flag to indicate if in-field calibration is recommended for this device at this time (if supported). This value is only valid after opening a connection and is a function of both time and ambient temperature. This value also updates each time a measurement is completed.
/// </summary>
extern bool Device_GetFieldCalibrationDue(void);

/// <summary>
/// Flag to indicate if in-field calibration results are applied (`true`) or bypassed (`false`) when evaluating the final calibrated measurement result. Value is `true` by default if supported by the device. It is recommended to leave this set to `true` if supported.
/// </summary>
extern bool Device_GetFieldCalibrationEnabled(void);

/// <summary>
/// Flag to indicate if this device supports automatic temperature compensation to correct for small changes in ambient temperature.
/// </summary>
extern bool Device_GetSupportsTemperatureCompensation(void);

/// <summary>
/// Flag to indicate if ambient temperature compensation / correction is applied (`true`) or bypassed (`false`) when evaluating the final calibrated measurement. Value is `true` by default if supported by the device. It is recommended to leave this set to `true` if supported.
/// </summary>
extern bool Device_GetTemperatureCompensationEnabled(void);

/// <summary>
/// Flag to indicate if the device supports built-in haptic feedback.
/// </summary>
extern bool Device_GetSupportsHapticFeedback(void);

/// <summary>
/// Flag to indicate if device haptic feedback is enabled.
/// </summary>
extern bool Device_GetHapticFeedbackEnabled(void);

/// <summary>
/// Flag to indicate if the device supports built-in RGB feedback.
/// </summary>
extern bool Device_GetSupportsRgbFeedback(void);

/// <summary>
/// Flag to indicate if device RGB feedback is enabled.
/// </summary>
extern bool Device_GetRgbFeedbackEnabled(void);

/// <summary>
/// Opens a connection to the device with the specified ID. Only a single device can be connected at one time; opening a connection to a second device will disconnect the first. Connecting is an async process; either the `Connected` callback will be invoked on success, or the `Disconnected` callback will be invoked on failure. To cancel a connection in progress, call `Device_Disconnect()`.
/// </summary>
/// <param name="deviceId">Identifier for the target device. This should match the `Id` of a device found by the `DeviceScanner` in this app session. If this device has not already been found, a search will automatically be started before starting the connection process.</param>
extern void Device_Connect(const char* deviceId);

/// <summary>
/// Closes the current device connection or cancels a connection operation in progress.
/// </summary>
extern void Device_Disconnect(void);

/// <summary>
/// Calls `LedTestAsync()` on the current device. This is an async operation; it will invoke the `CommandCompleted` callback on completion, with sender name "LedTestAsync" and the `CommandStatus` of the result passed as an integer.
/// </summary>
extern void Device_LedTest(void);

/// <summary>
/// Calls `MeasureAsync()` on the current device. This is an async operation; it will invoke the `CommandCompleted` callback  on completion, with sender name "MeasureAsync" and the  `CommandStatus` of the result passed as an integer.
/// </summary>
/// <param name="modesJson">Scan mode(s) to select, formatted as a JSON array, or empty string to select all supported modes. Scan mode names must match the names in the `ScanMode` enum (e.g.  `["M1"]` for M1 measurement mode)</param>
extern void Device_Measure(const char* modesJson);

/// <summary>
/// Calls `RunFieldCalibrationAsync()` on the current device. This is an async operation; it will invoke the `CommandCompleted` callback  on completion, with sender name "RunFieldCalibrationAsync" and the  `CommandStatus` of the result passed as an integer.
/// </summary>
/// <param name="tileString">String value decoded from the reference tile QR code. For `Spectro2` devices, the 5 digit code printed on the reference tile case is also accepted.</param>
extern void Device_RunFieldCalibration(const char* tileString);

/// Calls `InvalidateFieldCalibrationAsync()` on the current device. This is an async operation; it will invoke the `CommandCompleted` callback on completion, with sender name "InvalidateFieldCalibrationAsync" and the `CommandStatus` of the result passed as an integer.
extern void Device_InvalidateFieldCalibration(void);

/// <summary>
/// Used to check if a decoded string from the reference tile is valid.
/// </summary>
/// <param name="tileString">String value decoded from the reference tile QR code</param>
/// <returns>True if the `tileString` is valid for the current device</returns>
extern bool Device_IsTileStringValid(const char* tileString);

/// <summary>
/// Gets the `CommandStatus` for the last field calibration performed in this application session, represented as an integer.
/// </summary>
extern int32_t Device_GetLastCalibrationStatus(void);

/// <summary>
/// Gets debug information for the last field calibration performed in this application session, formatted as a JSON string.
/// </summary>
extern const char* Device_GetLastCalibrationDebug(void);

/// <summary>
/// Checks if a specific scan mode is supported. This value is valid only after a connection been opened.
/// </summary>
/// <param name="scanModeName">Scan mode name to query. Must match names defined in the `ScanMode` enum (e.g. - "M0", "M1", or "M2").</param>
/// <returns>True if mode is supported, false if not supported or invalid</returns>
extern bool Device_IsModeSupported(const char* scanModeName);

/// <summary>
/// Helper to check if a particular reference white point is supported by the colorimetry data from this device.
/// </summary>
/// <param name="referenceName">Reference white, by its name defined in the `ReferenceWhite` enum (e.g. - "D50_2") to query to query D50 illuminant, 2 degree observer.</param>
/// <returns>True if reference is supported, false if not supported or invalid</returns>
extern bool Device_ProvidesColor(const char* referenceName);


/// <summary>
/// Gets the current threshold/maximum Delta E threshold used when performing in-field calibration. Value is NaN if the device does not support field calibration.
/// </summary>
extern double Device_GetFieldCalibrationMaxDelta(void);

/// <summary>
/// Updates the maximum Delta E threshold used when performing in-field calibration. This is ignored if the device does not support field calibration.
/// </summary>
extern void Device_SetFieldCalibrationMaxDelta(double newValue);

/// <summary>
/// Calls `SetFieldCalibrationEnabledAsync()` on the current device. This is an async operation; it will invoke the `CommandCompleted` callback  on completion, with sender name "SetFieldCalibrationEnabledAsync" and the `CommandStatus` of the result passed as an integer.
/// </summary>
/// <param name="enabled">New state for this option</param>
extern void Device_SetFieldCalibrationEnabled(bool enabled);

/// <summary>
/// Calls `SetTemperatureCompensationEnabledAsync()` on the current device. This is an async operation; it will invoke the `CommandCompleted` callback  on completion, with sender name "SetTemperatureCompensationEnabledAsync" and the `CommandStatus` of the result passed as an integer.
/// </summary>
/// <param name="enabled">New state for this option</param>
extern void Device_SetTemperatureCompensationEnabled(bool enabled);

/// <summary>
/// Calls `SetHapticFeedbackEnabledAsync()` on the current device. This is an async operation; it will invoke the `CommandCompleted` callback  on completion, with sender name "SetHapticFeedbackEnabledAsync" and the `CommandStatus` of the result passed as an integer.
/// </summary>
/// <param name="enabled">New state for this option</param>
extern void Device_SetHapticFeedbackEnabled(bool enabled);

/// <summary>
/// Calls `SetRgbFeedbackEnabledAsync()` on the current device. This is an async operation; it will invoke the `CommandCompleted` callback  on completion, with sender name "SetRgbFeedbackEnabledAsync" and the `CommandStatus` of the result passed as an integer.
/// </summary>
/// <param name="enabled">New state for this option</param>
extern void Device_SetRgbFeedbackEnabled(bool enabled);

/// <summary>
/// Registers a callback for the `Connected` callback. The callback takes one string argument (name of the calling event).
/// </summary>
extern void Device_RegisterConnected(
    void (*callback)(const char*));

/// <summary>
/// Registers a callback for the `Disconnected` callback. The callback takes two arguments: a string (name of the calling event) and an integer corresponding to the `DeviceStatus` reason for disconnection.
/// </summary>
extern void Device_RegisterDisconnected(
	void (*callback)(const char*, int32_t));

/// <summary>
/// Registers a callback for the `BatteryStateChanged` callback. The callback takes two arguments: a string (name of the calling event) and an integer corresponding to the new battery level (0 - 100).
/// </summary>
extern void Device_RegisterBatteryStateChanged(
    void (*callback)(const char*, int32_t));

/// <summary>
/// Registers a callback for the `ExtPowerStateChanged` callback. The callback takes two arguments: a string (name of the calling event) and a boolean corresponding to the external power state.
/// </summary>
extern void Device_RegisterExtPowerStateChanged(
    void (*callback)(const char*, bool));

/// <summary>
/// Registers a callback for the `CommandCompleted` callback, which is invoked on completion of any async operations on the internal `IDeviceCompat` instance. The handler takes two arguments: a string (name of the internal calling function), and an integer corresponding to the `CommandStatus` of the operation.
/// </summary>
extern void Device_RegisterCommandCompleted(
    void (*callback)(const char*, int32_t));

/// <summary>
/// Gets the time stamp for the last measurement, represented as a unsigned 64-bit integer, or 0 if not available. This corresponds to the milliseconds since the Unix epoch (January 1, 1970 00:00 UTC).
/// </summary>
extern uint64_t Measurement_GetLastJavaTicks(void);

/// <summary>
/// Gets the `CommandStatus` of the last measurement, represented as an integer.
/// </summary>
extern int32_t Measurement_GetLastStatus(void);

/// <summary>
/// Gets a list of `ScanMode` modes available for the last measurement, formatted as JSON.
/// </summary>
/// <example>
/// Example JSON output:
/// <code>
/// ["M0","M1","M2"]
/// </code>
/// </example>
extern const char* Measurement_GetLastModesJson(void);

/// <summary>
/// Gets metadata (device type, device settings, temperature) for the last measurement, formatted as JSON.
/// </summary>
/// <param name="scanModeName">Name of the scan mode to select (e.g. - "M0", "M1", or "M2")</param>
/// <returns>Measurement metadata formatted as JSON</returns>
/// <example>
/// An example of calling this function from C is shown below:
/// <code>
/// const char* metadata = Measurement_GetLastMetadataJson("M2");
/// </code>
/// Example JSON output:
/// <code>
/// {
///     "dateMs": 1682005505841,
///     "status": 1,
///     "deviceName": "Nix Spectro 2",
///     "deviceType": 5,
///     "mode": "M2",
///     "tRef": 24.25,
///     "tScan": 24.5625,
///     "tReal": true,
///     "tCompEnabled": true,
///     "tileEnabled": true
/// }
/// </code>
/// </example>
extern const char* Measurement_GetLastMetadataJson(const char* scanModeName);

/// <summary>
/// Gets spectral data for the last measurement in the selected scan mode, formatted as JSON. Result is empty ("{}") if spectral data is not available.
/// </summary>
/// <param name="scanModeName">Name of the scan mode to select (e.g. - "M0", "M1", or "M2")</param>
/// <returns>Spectral data formatted as JSON</returns>
/// <example>
/// An example of calling this function from C is shown below:
/// <code>
/// const char* spectral = Measurement_GetLastSpectralJson("M2");
/// </code>
/// Example JSON output:
/// <code>
/// {
///     "mode": "M2",
///     "lambdaMin": 400,
///     "lambdaInterval": 10,
///     "value": [
///         0.09571632,
///         0.143246919,
///         0.201270252,
///         0.233701661,
///         0.229667112,
///         0.219201699,
///         0.197433069,
///         0.171539515,
///         0.14366518,
///         0.118656777,
///         0.102365054,
///         0.0851489082,
///         0.066573441,
///         0.0530253462,
///         0.0496698469,
///         0.0497059524,
///         0.0470496677,
///         0.0388559736,
///         0.0423551463,
///         0.123382688,
///         0.342879653,
///         0.608318865,
///         0.770111382,
///         0.84290266,
///         0.88257581,
///         0.898779333,
///         0.898909926,
///         0.902816713,
///         0.904295564,
///         0.906794488,
///         0.906649113
///     ]
/// }
/// </code>
/// </example>
extern const char* Measurement_GetLastSpectralJson(const char* scanModeName);

/// <summary>
/// Gets ISO density data for the last measurement in the selected scan mode and density status setting, formatted as JSON. Result is empty ("{}") if density data is not available.
/// </summary>
/// <param name="scanModeName">Name of the scan mode to select (e.g. - "M0", "M1", or "M2")</param>
/// <param name="densityStatusName">Name of the ISO density setting to select (e.g. - "A", "E", "I", "T")</param>
/// <returns>Density data formatted as JSON</returns>
/// <example>
/// An example of calling this function from C is shown below:
/// <code>
/// const char* density = Measurement_GetLastDensityJson("M2", "T");
/// </code>
/// Example JSON output:
/// <code>
/// {
///     "mode": "M2",
///     "isoStatus": "T",
///     "autoIndex": 1,
///     "value": [
///         0.2709233297197278,
///         1.2105773026488242,
///         0.7482882315988111,
///         0.6266073723704548
///     ]
/// }
/// </code>
/// </example>
extern const char* Measurement_GetLastDensityJson(
    const char* scanModeName,
    const char* densityStatusName);

/// <summary>
/// Gets a list of reference white names available for the last measurement, formatted as JSON.
/// </summary>
/// <param name="scanModeName">Name of the scan mode to select (e.g. - "M0", "M1", or "M2")</param>
/// <example>
/// An example of calling this function is shown below:
/// <code>
/// string references = Measurement_GetLastReferencesJson("M2");
/// </code>
/// Example JSON output:
/// <code>
/// ["D50_2","D65_10"]
/// </code>
/// </example>
extern const char* Measurement_GetLastReferencesJson(
    const char* scanModeName);

/// <summary>
/// Gets tristimulus colorimetry data for the last measurement in the selected scan mode, reference white, and color type, formatted as JSON. Result is empty ("{}") if the measurement mode or reference white is not available for the last measurement.
/// </summary>
/// <param name="scanModeName">Name of the scan mode to select (e.g. - "M0", "M1", or "M2")</param>
/// <param name="referenceName">Reference white to select (e.g. - "D50_2")</param>
/// <param name="typeName">Color type to select (e.g. - "CIEXYZ", "CIELAB", "CIELCH", "CIELUV")</param>
/// <returns>Colorimetry data formatted as JSON</returns>
/// <example>
/// An example of calling this function from C is shown below:
/// <code>
/// const char* color = Measurement_GetLastColorJson("M2", "D50_2", "CIEXYZ");
/// </code>
/// Example JSON output:
/// <code>
/// {
///     "mode": "M2",
///     "reference": "D50_2",
///     "type": "CIEXYZ",
///     "value": [
///         0.3444101768980547,
///         0.18339852869976314,
///         0.15600230435248466
///     ]
/// }
/// </code>
/// </example>
extern const char* Measurement_GetLastColorJson(
    const char* scanModeName,
    const char* referenceName,
    const char* typeName);

/// <summary>
/// Gets sRGB value for the last measurement in the selected scan mode and reference white, as a HEX triplet. Result is empty ("") if the measurement mode or reference white is not available for the last measurement.
/// </summary>
/// <param name="scanModeName">Name of the scan mode to select (e.g. - "M0", "M1", or "M2")</param>
/// <param name="referenceName">Reference white to select (e.g. - "D50_2")</param>
/// <returns>sRGB value as a HEX triplet (e.g. "#RRGGBB"), or empty string ("") on error</returns>
/// <example>
/// An example of calling this function from C is shown below:
/// <code>
/// const char* hexCode = Measurement_GetLastHexCode("M2", "D50_2");
/// </code>
/// Example output:
/// <code>
/// #DB267C
/// </code>
/// </example>
extern const char* Measurement_GetLastHexCode(
    const char* scanModeName, 
    const char* referenceName);

#ifdef __cplusplus
}
#endif // !__cplusplus

#endif // !NixUniversalSDK_Wrapper_h
