///////////////////////////////////////////////////////////////////////////////
/// @file deByteOrder.hpp
///
/// @brief utilities for handling byte ordering on different CPU architectures
///
/// @author Assassin
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date June 2003
/// @author Assassin
/// @remarks Creation
///
///////////////////////////////////////////////////////////////////////////////

#ifndef DEBYTEORDER_HPP
#define DEBYTEORDER_HPP

#include "deGlobalTypes.hpp"

/// reverse the byte ordering in a 16-bit value.
/// used via macros: deByteOrderLE16 and deByteOrderBE16
static inline u16 deSwap16(u16 x)
{
#ifdef DE3D_CPU_I386
	__asm
	{
		mov ax, x
		xchg ah, al
		mov x, ax
	}

	return x;
#else
	return (u16)((x>>8)|(x<<8));
#endif
}

/// reverse the byte ordering in a 32-bit value.
/// used via macros: deByteOrderLE32 and deByteOrderBE32
static inline u32 deSwap32(u32 x)
{
#ifdef DE3D_CPU_I386
	__asm
	{
		mov eax, x
		bswap eax
		mov x, eax
	}

	return x;
#else
	return (x<<24) | ((x&0x0000ff00)<<8) | ((x&0x00ff0000)>>8) | (x>>24);
#endif
}

/// reverse the byte ordering in a 64-bit value.
/// used via macros: deByteOrderLE64 and deByteOrderBE64
static inline u64 deSwap64(u64 x)
{
#ifdef DE3D_CPU_I386
	__asm
	{
		lea edx, x
		mov eax, [edx]
		mov ebx, [edx+4]
		bswap eax
		bswap ebx
		mov [edx+4], eax
		mov [edx], ebx
	}

	return x;
#else
	return (deSwap32((u32)x)<<32)|(deSwap32((u32)(x>>32)));
#endif
}

#if 0 // temporarily disable these to see if they're needed instead of the more specific ones below
template <typename T>
static inline T deSwap16(T val)
{
    u16 retval = deSwap16(*(u16*)(&val));
    return *(T*)(&retval);
}

template <typename T>
static inline T deSwap32(T val)
{
    u32 retval = deSwap32(*(u32*)(&val));
    return *(T*)(&retval);
}

template <typename T>
static inline T deSwap64(T val)
{
    u64 retval = deSwap64(*(u64*)(&val));
    return *(T*)(&retval);
}

#else

static inline s16 deSwap16(s16 val)
{
    u16 retval = deSwap16(*(u16*)(&val));
    return *(s16*)(&retval);
}
static inline s32 deSwap32(s32 val)
{
    u32 retval = deSwap32(*(u32*)(&val));
    return *(s32*)(&retval);
}
static inline s64 deSwap64(s64 val)
{
    u64 retval = deSwap64(*(u64*)(&val));
    return *(s64*)(&retval);
}
static inline float deSwap32(float val)
{
    u32 retval = deSwap32(*(u32*)(&val));
    return *(float*)(&retval);
}
static inline double deSwap64(double val)
{
    u64 retval = deSwap64(*(u64*)(&val));
    return *(double*)(&retval);
}
#endif

#if DE3D_CPU_LITTLE_ENDIAN
#	define deByteOrderLE16(x) (x)
#	define deByteOrderLE32(x) (x)
#	define deByteOrderLE64(x) (x)
#	define deByteOrderBE16(x) deSwap16(x)
#	define deByteOrderBE32(x) deSwap32(x)
#	define deByteOrderBE64(x) deSwap64(x)
#elif DE3D_CPU_BIG_ENDIAN
#	define deByteOrderLE16(x) deSwap16(x)
#	define deByteOrderLE32(x) deSwap32(x)
#	define deByteOrderLE64(x) deSwap64(x)
#	define deByteOrderBE16(x) (x)
#	define deByteOrderBE32(x) (x)
#	define deByteOrderBE64(x) (x)
#endif //DE3D_CPU_LITTLE_ENDIAN


#endif //DEBYTEORDER_HPP

