#ifndef _virtual_h__
#define _virtual_h__

/** virtual **
 *
 * Virtual Channels derived from regular Device Channels.
 * 
 * Virtual Channels are configured using a struct VirtualOptions, and computed using the
 * data from one or more underlying quantities, obtained from regular Device Channels.
 * 
 * For example, Humidex is computed from temperature and relative humidity.
 * 
 * Besides the struct VirtualOptions, this module is not intended to be used directly.
 * Rather, use the Source module to manage the creation and computation of Virtual Channels
 * automatically for each Device.
 * 
 * The Source module will, for example, automatically create a Humidex virtual channel for
 * any Device that has a temperature channel and a relative humidity channel.
 * 
 */

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

#ifdef __cplusplus
extern "C" {
#endif

/**
 * Options that affect the computation of virtual channel quantities.
 */
typedef struct VirtualOptions {

    uint32_t flags;
    double standard_sea_level_pressure;  // in pascals

} VirtualOptions;

/**
 * Virtual channel flag to disable the humidex input range check
 */
#define VIRTUAL_FLAG_NO_HUMIDEX_RANGE 0x01

/**
 * Virtual channel flag to disable the heat index input range check
 */
#define VIRTUAL_FLAG_NO_HEAT_INDEX_RANGE 0x02

/**
 * Default standard Sea Level Pressure (SLP) in pascals
 */
#define VIRTUAL_DEFAULT_SLP 101325.0

#define VIRTUAL_OPTIONS_DEFAULT { \
    0, \
    VIRTUAL_DEFAULT_SLP \
}

typedef struct VirtualChannel VirtualChannel;

/**
 * Function to refresh a VirtualChannel. For internal use by this module.
 */
typedef void (*virtual_channel_fn_t)(VirtualChannel *vc);

/**
 * Struct of a Virtual Channel used by this module and the Source module.
 * Normally you shouldn't be using this directly outside of those two modules.
 */
struct VirtualChannel {

    Channel channel;

    VirtualOptions *opt;
    Quantity **parents;
    virtual_channel_fn_t fn;

};

/**
 * Macro to refresh a VirtualChannel using its refresh function.
 */
#define virtual_channel_refresh(vc) ((vc)->fn)(vc)

/**
 * Create VirtualChannel structs and add them to a List.
 * 
 * The number of Virtual Channels created varies based on the List of input Channels.
 * For example, if input Channels include temperature and relative humidity, then a Humidex
 * Virtual Channel will be created and added.
 * 
 * Each created VirtualChannel must be freed later with virtual_channel_free().
 * 
 * This function is used by this module and the Source module.
 * Normally you shouldn't be using this directly outside of those two modules.
 * 
 * Return: how many virtual channels were added
 */
size_t virtual_channels_add(List *virtual_channels, List *channels, VirtualOptions *opt);

/**
 * Safely free a VirtualChannel created by virtual_channels_add().
 * 
 * This function is used by this module and the Source module.
 * Normally you shouldn't be using this directly outside of those two modules.
 */
void virtual_channel_free(VirtualChannel *vc);

/*
 * Declarations of various virtual channel functions
 */

#define _VIRTUAL_CHANNEL_FUNCTION(name) \
    void virtual_ ## name (VirtualChannel *vc)

_VIRTUAL_CHANNEL_FUNCTION(tsl2568_lux);
_VIRTUAL_CHANNEL_FUNCTION(tsl2561_lux);
_VIRTUAL_CHANNEL_FUNCTION(dew_point);
_VIRTUAL_CHANNEL_FUNCTION(humidex);
_VIRTUAL_CHANNEL_FUNCTION(heat_index);
_VIRTUAL_CHANNEL_FUNCTION(altitude);
_VIRTUAL_CHANNEL_FUNCTION(hexcolor);


#ifdef __cplusplus
}
#endif

#endif
