#ifndef _calpoint_h__
#define _calpoint_h__

/** calpoint **
 * 
 * Two-dimensional Point representing user-calibration points that can be configured
 * in Dracal's USB-CAL and VCP-CAL products.
 * 
 */

#ifdef __cplusplus
#include <cmath>
#define ISNAN std::isnan
#else
#include <math.h>
#define ISNAN isnan
#endif

#include <stdint.h>

#include "quantity.h"

/**
 * Number of calibration points per channel
 */
#define CAL_POINTS_COUNT 3

/**
 * Size in bytes of calibration points per channel
 */
#define CAL_POINTS_SIZE (CAL_POINTS_COUNT * sizeof(Point))

/**
 * Return true if the given point is invalid.
 */
#define POINT_IS_INVALID(p)     (ISNAN((p).x) || ISNAN((p).y))

/**
 * Return true if the given point is valid.
 */
#define POINT_IS_VALID(p)    (!(POINT_IS_INVALID(p)))


#ifdef __cplusplus
extern "C" {
#endif


/**
 * Pair of double-precision (64-bit) floating point values.
 */
typedef struct Point {

    union {
        double x;
        uint64_t x_bits;
    };

    union {
        double y;
        uint64_t y_bits;
    };

} Point;


/**
 * Count the number of valid points and pack them at the beginning of the array.
 * For example, an array of [p0, INVALID, p1] would become [p0, p1, INVALID].
 * The number of valid points is returned.
 */
uint8_t calpoints_pack(Point *points);


/**
 * Apply n-point calibration to the given quantity using the first n points of the given array.
 */
void calpoints_apply(Quantity *qty, Point *points);


#ifdef __cplusplus
}
#endif

#endif
