#ifndef _source_h__
#define _source_h__

/** Source **
 *
 * Extension over a Device that augments it with more data:
 * 
 *   - distinction between regular channels and user-calibrated channels
 *   - enable/disable user-calibration for individual channels
 *   - virtual channels
 *   - timestamp of last update
 */

#include <stdint.h>

#include "device.h"
#include "virtual.h"
#include "list.h"

#ifdef __cplusplus
extern "C" {
#endif


/**
 * Extension over a Device that augments it with more data:
 * 
 *   - distinction between regular channels and user-calibrated channels
 *   - extra virtual channels
 *   - timestamp of last update
 */
typedef struct Source {

    Device *device;

    // One-to-one mapping with device channels
    List calibrated_channels;

    // 1 bit per channel, indicating whether user calibration is enabled
    uint32_t user_calibration_enabled[((DEVICE_MAX_CHANNELS - 1) / 32) + 1];

    // Virtual channels, based off calibrated channels
    List virtual_channels;

    // Timestamp of last refresh in microseconds (us) since Epoch
    int64_t timestamp;

} Source;

/**
 * Create a new Source on the heap. It must be deleted later with source_delete().
 * 
 * The Source is initialized according to the details of the given Device and VirtualOptions.
 * 
 * Return: pointer to the newly allocated Source
 */
Source *source_new(Device *device, VirtualOptions *opt);

/**
 * Delete a Source previously created with source_new().
 * 
 * The underlying Device is not deleted.
 */
void source_delete(Source *source);

/**
 * Initialize a Source declared on the stack. It must be cleared later with source_clear().
 * 
 * The Source is initialized according to the details of the given Device and VirtualOptions.
 */
void source_init(Source *source, Device *device, VirtualOptions *opt);

/**
 * Clear a Source, i.e. free underlying data structures.
 * 
 * This function is intended to be called when the Source is no longer needed.
 * 
 * The underlying Device is not cleared.
 * 
 * It is not necessary to call source_clear() before source_delete().
 */
void source_clear(Source *source);

/**
 * Return whether user-calibration is enabled on a channel
 */
int source_is_user_calibration_enabled(Source *source, uint8_t channel_index);

/**
 * Enable or disable user-calibration on a channel. Argument `enabled` is boolean.
 */
void source_set_user_calibration(Source *source, uint8_t channel_index, char enabled);

/**
 * Refresh the Source channels, i.e. user-calibrated channels and virtual channels.
 * 
 * Since these channels are derived from the underlying Device's channels, this function
 * must be called whenever the underlying Device has changed.
 *
 * The timestamp is not updated. You may update it manually as needed.
 */
void source_refresh(Source *source);


#ifdef __cplusplus
}
#endif

#endif
