#ifndef UA_CONFIG_H_
#define UA_CONFIG_H_

#ifndef _XOPEN_SOURCE
# define _XOPEN_SOURCE 500
# define _BSD_SOURCE
#endif

#define UA_LOGLEVEL ${UA_LOGLEVEL}
#cmakedefine UA_ENABLE_MULTITHREADING
#cmakedefine UA_ENABLE_METHODCALLS
#cmakedefine UA_ENABLE_SUBSCRIPTIONS
#cmakedefine UA_ENABLE_TYPENAMES
#cmakedefine UA_ENABLE_EMBEDDED_LIBC
#cmakedefine UA_ENABLE_GENERATE_NAMESPACE0
#cmakedefine UA_ENABLE_EXTERNAL_NAMESPACES
#cmakedefine UA_ENABLE_NODEMANAGEMENT

#cmakedefine UA_ENABLE_NONSTANDARD_UDP
#cmakedefine UA_ENABLE_NONSTANDARD_STATELESS

/* Function Export */
#ifdef _WIN32
# ifdef UA_DYNAMIC_LINKING
#  ifdef __GNUC__
#   define UA_EXPORT __attribute__ ((dllexport))
#  else
#   define UA_EXPORT __declspec(dllexport)
#  endif
# else
#  ifdef __GNUC__
#   define UA_EXPORT __attribute__ ((dllexport))
#  else
#   define UA_EXPORT __declspec(dllimport)
#  endif
# endif
#else
# if __GNUC__ || __clang__
#  define UA_EXPORT __attribute__ ((visibility ("default")))
# else
#  define UA_EXPORT
# endif
#endif

/* Endianness */
// UA_NON_LITTLEENDIAN_ARCHITECTURE disables memcpying integer arrays directly
// onto the message buffer. UA_MIXED_ENDIAN enables special encoding for floats
// and doubles. Otherwise, they are endianness-switched similar to integers.
#if defined(__LITTLE_ENDIAN__) || defined(_WIN32) || (!defined(__ANDROID__) && BYTE_ORDER == ORDER_LITTLE_ENDIAN)
# define htole16(x) (x)
# define htole32(x) (x)
# define htole64(x) (x)
# define le16toh(x) (x)
# define le32toh(x) (x)
# define le64toh(x) (x)
#else
# if defined(__ANDROID__)
#  include <endian.h>
#  define le16toh(x) letoh16(x)
#  define le32toh(x) letoh32(x)
#  define le64toh(x) letoh64(x)
# elif defined(__linux__)
#  include <endian.h>
# elif defined(__OpenBSD__)
#  include <sys/endian.h>
# elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
#  include <sys/endian.h>
#  define le16toh(x) letoh16(x)
#  define le32toh(x) letoh32(x)
#  define le64toh(x) letoh64(x)
# elif defined(__APPLE__)
#  include <libkern/OSByteOrder.h>
#  define htole16(x) OSSwapHostToLittleInt16(x)
#  define htole32(x) OSSwapHostToLittleInt32(x)
#  define htole64(x) OSSwapHostToLittleInt64(x)
#  define le16toh(x) OSSwapLittleToHostInt16(x)
#  define le32toh(x) OSSwapLittleToHostInt32(x)
#  define le64toh(x) OSSwapLittleToHostInt64(x)
#  define __BYTE_ORDER BYTE_ORDER
# elif defined(__QNX__) || defined(__QNXNTO__)
#  include <gulliver.h>
#  if defined(__LITTLEENDIAN__)
#   define __BYTE_ORDER __LITTLE_ENDIAN
#  endif
#  define htole16(x) ENDIAN_LE16(x)
#  define htole32(x) ENDIAN_LE32(x)
#  define htole64(x) ENDIAN_LE64(x)
#  define le16toh(x) ENDIAN_LE16(x)
#  define le32toh(x) ENDIAN_LE32(x)
#  define le64toh(x) ENDIAN_LE64(x)
# endif
# if ( __BYTE_ORDER != __LITTLE_ENDIAN ) && (_BYTE_ORDER != _LITTLE_ENDIAN)
#  define UA_NON_LITTLEENDIAN_ARCHITECTURE
# endif
#endif

/* Manually override */
// If required, define UA_NON_LITTLEENDIAN_ARCHITECTURE, UA_MIXED_ENDIAN, and
// the htole / letoh functions here. Even better, post an issue on github or the
// mailing list, so we can include the architecture in the standard release.
#define swap16(u16) ((u16 >> 8) | (u16 << 8))
#define swap32(u32) ((u32 >> 24) | ((u32 << 8) & 0x00FF0000) | ((u32 >> 8) & 0x0000FF00) | (u32 << 24))
#define swap64(u64) ((u64 >> 56) | ((u64 << 40) & 0x00FF000000000000) | ((u64 << 24) & 0x0000FF0000000000) | \
                     ((u64 << 8) & 0x000000FF00000000) | ((u64 >> 8) & 0x00000000FF000000) |                 \
                     ((u64 >> 24) & 0x0000000000FF0000) | ((u64 >> 40) & 0x000000000000FF00) | (u64 << 56))

#ifdef __ARM_ARCH_4T__
# define UA_MIXED_ENDIAN
# define UA_NON_LITTLEENDIAN_ARCHITECTURE
# define htole16(x) swap16(x)
# define htole32(x) swap32(x)
# define htole64(x) swap64(x)
# define le16toh(x) swap16(x)
# define le32toh(x) swap32(x)
# define le64toh(x) swap64(x)
#endif

#ifndef htole16
# error The endianness of the architecture not known
#endif

/* Inline Functions */
#ifdef _MSC_VER
# define UA_INLINE __inline
#else
# define UA_INLINE inline
#endif

/* Define non-aliasing pointers */
#ifdef _MSC_VER
# define UA_RESTRICT __restrict
#elif defined(__GNUC__)
# define UA_RESTRICT __restrict__
#else
# define UA_RESTRICT restrict
#endif

/* Function attributes */
#ifdef __GNUC__
# define UA_FUNC_ATTR_MALLOC __attribute__((malloc))
# define UA_FUNC_ATTR_PURE __attribute__ ((pure))
# define UA_FUNC_ATTR_CONST __attribute__((const))
# define UA_FUNC_ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#else
# define UA_FUNC_ATTR_MALLOC
# define UA_FUNC_ATTR_PURE
# define UA_FUNC_ATTR_CONST
# define UA_FUNC_ATTR_WARN_UNUSED_RESULT
#endif

#include <stddef.h>
#ifdef UA_ENABLE_EMBEDDED_LIBC
  void *memcpy(void *UA_RESTRICT dest, const void *UA_RESTRICT src, size_t n);
  void *memset(void *dest, int c, size_t n);
  size_t strlen(const char *s);
  int memcmp(const void *vl, const void *vr, size_t n);
#else
# include <string.h>
#endif

#endif /* UA_CONFIG_H_ */