/**
@file crc.hpp
@brief crc生成クラス boost::crcも読み込み。
@note



http://cgi33.plala.or.jp/biwakobo/showhtml.cgi?f=vba18　2004/11/24
参考．Webで調べた主な多項式(Polynomial)　より引用

CRC-8    : 0x07(x^8 + x^2 + x^1 + x^0)
CCITT-8  : 0x31(x^8 + x^5 + x^4 + x^0)
CRC-16   : 0x8005(x^16 + x^15 + x^2 + x^0)
CCITT-16 : 0x1021(x^16 + x^12 + x^5 + x^0)
CRC-32   : 0x04C11DB7(x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + x^0)
CCITT-32 : 0xEDB88320(x^32 + x^31 + x^30 + x^29 + x^27 + x^26 + x^24 + x^23 + x^21 + x^20 + x^19 + x^15 + x^9 + x^8 + x^5)

*/
#ifndef DKUTIL_SIGNATURE_CRC_HPP
#define DKUTIL_SIGNATURE_CRC_HPP


#include <dkutil_c/dkcCRC.h>
#include <dkutil/signature/base.hpp>
#include <dkutil/boost/crc.hpp>
#include <dkutil/bit.hpp>
#include <dkutil/string.hpp>
#include <dkutil/signature/crc32.hpp>
#include <dkutil/signature/crc_ccitt.hpp>


namespace dkutil{

namespace detail{
	inline size_t crc_binary_result_size(size_t Bits){
		return Bits / 8;// >> 3
		//return NumOfBits((0xFFFFFFFF >> (32 - Bits)) ) / 8;
	}
	inline size_t crc_string_result_size(size_t Bits){
		return Bits / 4;// >> 2
	}
}//end of detail


inline std::string crc_to_string(unsigned long crc,size_t Bits){
	std::string buff = "%0";
	buff += to_string(detail::crc_string_result_size(Bits));
	buff += "lX";
	buff = boost::io::str( 
		//boost::format("%08lX") % crc
		boost::format(buff.c_str()) % crc
	);
	return buff;
}

class CCRC : public ISignature_Base{
private:
	DKC_CRC mH;
	ULONG mTable[0x100];
public:
	CCRC( size_t Bits, ULONG TruncPoly,
        ULONG InitRem, ULONG FinalXor,
        bool ReflectIn, bool ReflectRem){
		init(Bits,TruncPoly,InitRem,FinalXor,ReflectIn,ReflectRem);
	}
	bool init(size_t Bits, ULONG TruncPoly,
        ULONG InitRem, ULONG FinalXor,
			bool ReflectIn, bool ReflectRem)
	{
		return DKUTIL_SUCCEEDED_BOOL(
			dkcCRCInit(&mH,mTable,Bits,TruncPoly,InitRem,FinalXor,ReflectIn,ReflectRem)
		);
	}
	virtual void init(){
		dkcCRCInit(&mH,mTable,
			mH.mBits,mH.mTruncPoly,
			mH.mInitRem,mH.mFinalXor,
			mH.mReflectIn,mH.mReflectRem
		);
	}
	virtual void load(const BYTE *buffer,size_t size){
		dkcCRCLoad(&mH,buffer,size);
	}
	virtual void final(){
		dkcCRCFinal(&mH);
	}
	virtual bool getSignature(BYTE *buffer,size_t size,int flag){
		ULONG r;
		r = getSignature();
		int result;
		if(binary_signature == flag){
			result = dkmemcpy(buffer,size,&r,sizeof(r));
		}else{//文字列
			std::string str = crc_to_string(r,mH.mBits);
			result = dkstrcpy((char *)buffer,size,str.c_str(),str.size());
		}
		return DKUTIL_SUCCEEDED_BOOL(result);
	}
	virtual size_t getOutputSize(int flag)const{
		if(binary_signature == flag){
			return detail::crc_binary_result_size(mH.mBits);
		}else{ //if(string_signature
			return detail::crc_string_result_size(mH.mBits);
		}
	}
	ULONG getSignature()const{
		return dkcCRCResult(&mH);
	}
	ULONG *getTable(){
		return mTable;
	}
	size_t getUseTableSize()const{
		return dkcCRCGetUseTableSize(mH.mBits);
	}
	/*virtual size_t getStringOutputSize()const{
		return CRC_STR_BUFFER_SIZE;
	}*/
};

typedef CCRC<32, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, FALSE, FALSE> CCRC_32left;
typedef CCRC<32, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, TRUE, TRUE> CCRC_32right;

typedef CCRC<16, 0x1021, 0xFFFF, 0, FALSE,FALSE> CCRC_ccitt_left;
typedef CCRC<16, 0x8005, 0xFFFF, 0, TRUE,TRUE> CCRC_ccitt_right;


typedef CCRC<16, 0x8005, 0, 0, TRUE,TRUE) CCRC_ansi16left;
typedef CCRC<16, 0xa001, 0, 0, FALSE,FALSE) CCRC_ansi16right;

typedef CCRC<16, 0x8408, 0, 0, TRUE,TRUE> CCRC_xmodem;

/*


typedef CCRC<16, 0x51, 0xFFFF, 0, FALSE,FALSE> CCRC_7left;
typedef CCRC<16, 0x8a, 0xFFFF, 0, TRUE,TRUE> CCRC_7right;

*/

}//end of dkutil namespace


namespace boost{

}//end of boost



#endif