#ifndef AVIFILE_UTILS_H
#define AVIFILE_UTILS_H

#include "avm_default.h"
#include "formats.h"

/**
 *  Utility functions.
 *    plain C functions are here
 */
AVM_BEGIN_EXTERN_C;

#ifdef AVM_COMPATIBLE
// these are not used anymore
extern uint_t (*localcount)(void) _avm_deprecated;
extern int64_t (*longcount)(void) _avm_deprecated;
#endif

/**
 * retriew current time in microseconds
 * \returns time in microsecond units
 */
int64_t avm_get_time_us(void);
/**
 * callculate diff between 2 times -
 * \returns time difference in seconds
 */
static inline float avm_get_time_diff(int64_t t1, int64_t t2) { return (float)(t1 - t2) * 0.000001f; }


/*
 * function to retrieve/store data in machine independent format
 * - right now dump implementation - as we could check functionality
 */
static inline uint16_t avm_get_le16(const void* p) {
#ifdef WORDS_BIGENDIAN
    const uint8_t* c = (const uint8_t*) p;
    return c[0] | c[1] << 8;
#else
    return *(const uint16_t*)p;
#endif
}

static inline uint8_t* avm_set_le16(void* p, uint16_t v) {
    uint8_t* b = (uint8_t*) p;
#ifdef WORDS_BIGENDIAN
    b[0] = v & 0xff;
    b[1] = (v >> 8) & 0xff;
#else
    *(uint16_t*)p = v;
#endif
    return b;
}

static inline uint32_t avm_get_le32(const void* p) {
#ifdef WORDS_BIGENDIAN
    const uint8_t* c = (const uint8_t*) p;
    return c[0] | c[1] << 8 | c[2] << 16 | c[3] << 24;
#else
    return *(const uint32_t*)p;
#endif
}

static inline uint8_t* avm_set_le32(void* p, uint32_t v) {
    uint8_t* b = (uint8_t*) p;
#ifdef WORDS_BIGENDIAN
    b[0] = v & 0xff;
    b[1] = (v >> 8) & 0xff;
    b[2] = (v >> 16) & 0xff;
    b[3] = (v >> 24) & 0xff;
#else
    *(uint32_t*)p = v;
#endif
    return b;
}

static inline uint64_t avm_get_le64(const void* p) {
#ifdef WORDS_BIGENDIAN
    const uint8_t* c = (const uint8_t*) p;
    return avm_get_le32(c) | (((uint64_t)avm_get_le32(c + 4)) << 32);
#else
    return *(const uint64_t*)p;
#endif
}

static inline uint16_t avm_get_be16(const void* p) {
#ifdef WORDS_BIGENDIAN
    return *(const uint16_t*)p;
#else
    const uint8_t* c = (const uint8_t*) p;
    return c[0] << 8 | c[1];
#endif
}

static inline uint8_t* avm_set_be16(void* p, uint16_t v) {
    uint8_t* b = (uint8_t*) p;
    b[0] = (v >> 8) & 0xff;
    b[1] = v & 0xff;
    return b;
}

static inline uint32_t avm_get_be32(const void* p) {
#ifdef WORDS_BIGENDIAN
    return *(const uint32_t*)p;
#else
    const uint8_t* c = (const uint8_t*) p;
    return c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3];
#endif
}

static inline uint8_t* avm_set_be32(void* p, uint32_t v) {
    uint8_t* b = (uint8_t*) p;
    b[0] = (v >> 24) & 0xff;
    b[1] = (v >> 16) & 0xff;
    b[2] = (v >> 8) & 0xff;
    b[3] = v & 0xff;
    return b;
}

static inline uint64_t avm_get_be64(const void* p) {
#ifdef WORDS_BIGENDIAN
    return *(const uint64_t*)p;
#else
    const uint8_t* c = (const uint8_t*) p;
    return ((uint64_t) avm_get_be32(c)) << 32 | avm_get_le32(c + 4);
#endif
}

static inline int avm_img_is_rgb(fourcc_t fmt)
{
    return ((fmt & 0xffffff00) == IMG_FMT_RGB);
}
static inline int avm_img_is_bgr(fourcc_t fmt)
{
    return ((fmt & 0xffffff00) == IMG_FMT_BGR);
}
static inline int avm_img_get_depth(fourcc_t fmt)
{
    return fmt & 0xff;
}

WAVEFORMATEX* avm_get_leWAVEFORMATEX(WAVEFORMATEX* wf);
BITMAPINFOHEADER* avm_get_leBITMAPINFOHEADER(BITMAPINFOHEADER* bi);

const char* avm_fcc_name(fourcc_t fcc);
const char* avm_wave_format_name(short fmt); /* not sure - might be special type */
const char* avm_img_format_name(fourcc_t fmt);
char* avm_wave_format(char* buf, uint_t s, const WAVEFORMATEX* wf);
char* avm_mp3wave_format(char* buf, uint_t s, const MP3WAVEFORMATEX* wf);

/* wrapping functions */
/* A thread-save usec sleep */
int avm_usleep(unsigned long);

/* some system doesn't have setenv/unsetenv */
int avm_setenv(const char *name, const char *value, int overwrite);
void avm_unsetenv(const char *name);

AVM_END_EXTERN_C;

#endif /* AVIFILE_UTILS_H */
