#ifndef _unit_h__
#define _unit_h__

/** unit **
 * 
 * Various measurement units and functions to convert between them.
 * 
 */

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif


#ifdef _WIN32
#define strcasecmp(x,y) _stricmp(x,y)
#endif

/**
 * Measurement unit type.
 */
typedef uint8_t unit_t;

/**
 * Categories of measurement units, indexed from 0.
 */
typedef uint8_t unit_category_t;

enum {
    UNIT_CATEGORY_UNKNOWN = 0,
    UNIT_CATEGORY_TEMPERATURE,
    UNIT_CATEGORY_PRESSURE,
    UNIT_CATEGORY_FREQUENCY,
    UNIT_CATEGORY_VOLTAGE,
    UNIT_CATEGORY_CURRENT,
    UNIT_CATEGORY_POWER,
    UNIT_CATEGORY_LENGTH,
    UNIT_CATEGORY_CONCENTRATION,
    UNIT_CATEGORY_RELATIVE_HUMIDITY
};

/**
 * Number of unit categories, indexed from 0 to (UNIT_CATEGORIES - 1) inclusively.
 */
#define UNIT_CATEGORIES (UNIT_CATEGORY_RELATIVE_HUMIDITY + 1)

/**
 * Return the category to which the given unit belongs.
 */
unit_category_t unit_category(unit_t unit);

/**
 * Return a string symbol for the given unit.
 * The string may contain special characters (UTF-8 encoded) unless 'ascii' is true.
 */
const char *unit_to_string(unit_t unit, uint8_t ascii);

/**
 * Return the unit corresponding to the given category and string.
 * If the category is UNIT_CATEGORY_UNKNOWN, all categories are checked.
 */
unit_t unit_parse(unit_category_t cat, const char *s);

/**
 * Function that converts a value from one unit to another.
 */
typedef double (*unit_conversion_fn_t)(double value, unit_t src_unit, unit_t dst_unit);

/**
 * Unit conversion functions indexed by category.
 */
extern const unit_conversion_fn_t UNIT_CONVERSION_FUNCTIONS[UNIT_CATEGORIES];

/**
 * Convert a value from one unit to another.
 * If the conversion isn't possible (e.g. from mass to length), the value is left unmodified,
 * and a non-zero value is returned to indicate that an error occurred.
 */
int unit_convert(double *value, unit_t src_unit, unit_t dst_unit);


/*
 * Unit constants
 */

#define UNIT_RAW            0x00

#define UNIT_CELSIUS        0x01
#define UNIT_FAHRENHEIT     0x02
#define UNIT_KELVIN         0x03
#define UNIT_RH             0x04

#define UNIT_PA             0x09
#define UNIT_KPA            0x10
#define UNIT_HPA            0x11
#define UNIT_BAR            0x12
#define UNIT_AT             0x13
#define UNIT_ATM            0x14
#define UNIT_TORR           0x15
#define UNIT_PSI            0x16
#define UNIT_INHG           0x17 // 3386.389 pascals
#define UNIT_IS_PRESSURE(p)    (((p)>=0x09) && ((p)<=0x17))

#define UNIT_PERCENT        0x19
#define UNIT_PPM            0x1A
#define UNIT_PPB            0x1B

#define UNIT_uG_PER_M3      0x1C    // micro grams per cubic meter
#define UNIT_COUNT_PER_CM3  0x1D    // count per cubic centimeter

#define UNIT_VOLT           0x20
#define UNIT_MILLIVOLT      0x23
#define UNIT_AMP            0x25
#define UNIT_MILLIAMP       0x28

#define UNIT_KILOWATT       0x29
#define UNIT_WATT           0x2A
#define UNIT_MILLIWATT      0x2D

#define UNIT_LUX            0x30
#define UNIT_uW_PER_CM2     0x31    // micro watt per square centimeter

#define UNIT_METER_SEC      0x40

#define UNIT_MILLIHZ        0x50
#define UNIT_HZ             0x51
#define UNIT_KHZ            0x52
#define UNIT_MHZ            0x53

#define UNIT_RPM            0x55

#define UNIT_METER          0x60
#define UNIT_DECIMETER      0x61
#define UNIT_CENTIMETER     0x62
#define UNIT_MILLIMETER     0x63
#define UNIT_MICROMETER     0x64

#define UNIT_MIL            0x69
#define UNIT_INCH           0x6A
#define UNIT_FEET           0x6B
#define UNIT_YARD           0x6C

#define UNIT_ARBITRARY      0x70

#define UNIT_HEXCOLOR       0x90

#define UNIT_UNKNOWN        0xFE

#define UNIT_SENSOR_DEFAULT 0xFF


#ifdef __cplusplus
}
#endif

#endif
