#pragma once

typedef unsigned int uint;

template <typename T>
inline T WordSwapC(T w)
{
  uint16 temp;

  temp = ((*((uint16 *)&w) & 0xff00) >> 8);
  temp |= ((*((uint16 *)&w) & 0x00ff) << 8);

  return *((T*)&temp);
}

template <typename T>
inline T DWordSwapC(T dw)
{
  uint32 temp;

  temp = *((uint32 *)&dw) >> 24;
  temp |= ((*((uint32 *)&dw) & 0x00FF0000) >> 8);
  temp |= ((*((uint32 *)&dw) & 0x0000FF00) << 8);
  temp |= ((*((uint32 *)&dw) & 0x000000FF) << 24);

  return *((T*)&temp);
}

//-------------------------------------
// Fast swaps
//-------------------------------------

#if defined( _X360 )

#define WordSwap  WordSwap360Intr
#define DWordSwap DWordSwap360Intr

template <typename T>
inline T WordSwap360Intr(T w)
{
  T output;
  __storeshortbytereverse(w, 0, &output);
  return output;
}

template <typename T>
inline T DWordSwap360Intr(T dw)
{
  T output;
  __storewordbytereverse(dw, 0, &output);
  return output;
}

#elif defined( _MSC_VER )

#define WordSwap  WordSwapAsm
#define DWordSwap DWordSwapAsm

#pragma warning(push)
#pragma warning (disable:4035) // no return value

template <typename T>
inline T WordSwapAsm(T w)
{
  __asm
  {
    mov ax, w
    xchg al, ah
  }
}

template <typename T>
inline T DWordSwapAsm(T dw)
{
  __asm
  {
    mov eax, dw
    bswap eax
  }
}

#pragma warning(pop)

#else

#define WordSwap  WordSwapC
#define DWordSwap DWordSwapC

#endif

//-------------------------------------
// The typically used methods.
//-------------------------------------

#if defined(__i386__)
#define LITTLE_ENDIAN 1
#endif

#if defined( _SGI_SOURCE ) || defined( _X360 )
#define BIG_ENDIAN 1
#endif

// If a swapped float passes through the fpu, the bytes may get changed.
// Prevent this by swapping floats as DWORDs.
#define SafeSwapFloat( pOut, pIn ) (*((uint*)pOut) = DWordSwap( *((uint*)pIn) ))

#if defined(LITTLE_ENDIAN)

#define BigShort( val ) WordSwap( val )
#define BigWord( val ) WordSwap( val )
#define BigLong( val ) DWordSwap( val )
#define BigDWord( val ) DWordSwap( val )
#define LittleShort( val ) ( val )
#define LittleWord( val ) ( val )
#define LittleLong( val ) ( val )
#define LittleDWord( val ) ( val )
#define SwapShort( val ) BigShort( val )
#define SwapWord( val ) BigWord( val )
#define SwapLong( val ) BigLong( val )
#define SwapDWord( val ) BigDWord( val )

// Pass floats by pointer for swapping to avoid truncation in the fpu
#define BigFloat( pOut, pIn ) SafeSwapFloat( pOut, pIn )
#define LittleFloat( pOut, pIn ) ( *pOut = *pIn )
#define SwapFloat( pOut, pIn ) BigFloat( pOut, pIn )

#elif defined(BIG_ENDIAN)

#define BigShort( val ) ( val )
#define BigWord( val ) ( val )
#define BigLong( val ) ( val )
#define BigDWord( val ) ( val )
#define LittleShort( val ) WordSwap( val )
#define LittleWord( val ) WordSwap( val )
#define LittleLong( val ) DWordSwap( val )
#define LittleDWord( val ) DWordSwap( val )
#define SwapShort( val ) LittleShort( val )
#define SwapWord( val ) LittleWord( val )
#define SwapLong( val ) LittleLong( val )
#define SwapDWord( val ) LittleDWord( val )

// Pass floats by pointer for swapping to avoid truncation in the fpu
#define BigFloat( pOut, pIn ) ( *pOut = *pIn )
#define LittleFloat( pOut, pIn ) SafeSwapFloat( pOut, pIn )
#define SwapFloat( pOut, pIn ) LittleFloat( pOut, pIn )

#else

// @Note (toml 05-02-02): this technique expects the compiler to
// optimize the expression and eliminate the other path. On any new
// platform/compiler this should be tested.
inline short BigShort(short val) { int test = 1; return (*(char *)&test == 1) ? WordSwap(val) : val; }
inline uint16 BigWord(uint16 val) { int test = 1; return (*(char *)&test == 1) ? WordSwap(val) : val; }
inline long BigLong(long val) { int test = 1; return (*(char *)&test == 1) ? DWordSwap(val) : val; }
inline uint32 BigDWord(uint32 val) { int test = 1; return (*(char *)&test == 1) ? DWordSwap(val) : val; }
inline short LittleShort(short val) { int test = 1; return (*(char *)&test == 1) ? val : WordSwap(val); }
inline uint16 LittleWord(uint16 val) { int test = 1; return (*(char *)&test == 1) ? val : WordSwap(val); }
inline long LittleLong(long val) { int test = 1; return (*(char *)&test == 1) ? val : DWordSwap(val); }
inline uint32 LittleDWord(uint32 val) { int test = 1; return (*(char *)&test == 1) ? val : DWordSwap(val); }
inline short SwapShort(short val) { return WordSwap(val); }
inline uint16 SwapWord(uint16 val) { return WordSwap(val); }
inline long SwapLong(long val) { return DWordSwap(val); }
inline uint32 SwapDWord(uint32 val) { return DWordSwap(val); }

// Pass floats by pointer for swapping to avoid truncation in the fpu
inline void BigFloat(float *pOut, const float *pIn) { int test = 1; (*(char *)&test == 1) ? SafeSwapFloat(pOut, pIn) : (*pOut = *pIn); }
inline void LittleFloat(float *pOut, const float *pIn) { int test = 1; (*(char *)&test == 1) ? (*pOut = *pIn) : SafeSwapFloat(pOut, pIn); }
inline void SwapFloat(float *pOut, const float *pIn) { SafeSwapFloat(pOut, pIn); }

#endif
