/**
@filename endian.hpp
@brief endianを指定のendianに変える機構
@note

*/
#ifndef DKUTIL_ENDIAN_HPP
#define DKUTIL_ENDIAN_HPP

#include <dkutil/detail/serialize_interface.hpp>
#include <dkutil/detail/stream_interface.hpp>

namespace dkutil{

template<typename POD_T>
class endian_reverse{
public:

	static bool isBig(){
		static bool isBigEndian = !IStream::isLittleEndian() ;
		if(isBigEndian)
			return true;
		return false;
	}
	static bool isLittle(){
		return !isBig();
	}
	typedef POD_T value_type;
	//endian_reverse(){}
	value_type operator()(value_type x){
		return reverse(x);
	}
	static inline uint16 reverse16(value_type x){
		return dkcREVERSE_ENDIAN16(x);
	}
	static inline uint32 reverse32(value_type x){
		return dkcREVERSE_ENDIAN32(x);
	}
	static inline uint64 reverse64(value_type x){
		return dkcREVERSE_ENDIAN64(x);
	}
	static inline value_type reverse(value_type x){
		value_type t;
		switch(sizeof(value_type)){
		case 2:
			t = dkcREVERSE_ENDIAN16(x);
			break;
		case 4:
			t = dkcREVERSE_ENDIAN32(x);
			break;
		case 8:
			t = dkcREVERSE_ENDIAN64(x);
			break;
		}
		return t;
	}
	static value_type toBig(value_type x){
		if(isBig()) return x;
		return reverse(x);
	}
	static value_type toLittle(value_type x){
		if(isLittle()) return x;
		return reverse(x);
	}
	
	///@param num[in] srcのbyte単位のサイズ / sizeof(POD_T) byte単位のサイズじゃないのに注意
	static void for_array(value_type *dest,value_type *src,size_t num)
	{
		size_t i;
		for(i=0;i<num;i++){
			dest[i] = reverse(src[i]);
		}
	}
};
/*
template<typename POD_T>
struct reverse_endian_each{

};
*/




class CEndianIndependentStreamAdapter : public ISerializeStream{
public:
	typedef ISerializeStream base_type;
	typedef CEndianIndependentStreamAdapter self_type;

protected:
	 IStreamAction *mAction;
public:
	
	CEndianIndependentStreamAdapter() : ISerializeStream(false){
	}
	
	bool reset(IStreamAction *func,bool isLittle,bool isRead){
		mAction = func;
		return base_type::reset(isLittle,isRead);
	}
	virtual ~CEndianIndependentStreamAdapter(){
	
	}
	virtual void store(void *pd,size_t size){
		bool r = mAction->action((uint8*)pd,size);
		if(false==r){
			DKUTIL_THROW_OR_NOTICE(std::runtime_error("CEndianIndependentStreamAdapter::store() return false;"));
		}
	}
};

}//end of dkutil namespace



#endif