
#ifndef DKUTIL_SIGNATURE_CRC_CCITT_HPP
#define DKUTIL_SIGNATURE_CRC_CCITT_HPP


#include <dkutil/signature/interface.hpp>

/// x^{16}+x^{12}+x^5+1
#define DKUTIL_CRC16_CCITT_POLY1  0x1021U 
/// DKUTIL_CRC16POLY1の左右逆転 
#define DKUTIL_CRC16_CCITT_POLY2  0x8408U

namespace dkutil{
namespace detail{
	
class crc16_ccitt_left{
	static unsigned int crctable[UCHAR_MAX + 1];

	static void makecrctable(void)
	{
		static bool inited = false;
		unsigned int i, j, r;
		if(inited){
			return ;
		}

		for (i = 0; i <= UCHAR_MAX; i++) {
			r = i << (16 - CHAR_BIT);
			for (j = 0; j < CHAR_BIT; j++)
				if (r & 0x8000U) r = (r << 1) ^ DKUTIL_CRC16_CCITT_POLY1;
				else             r <<= 1;
			crctable[i] = r & 0xFFFFU;
		}
		inited = true;
	}
	unsigned int mR;
	unsigned int mResult;
public:
	crc16_ccitt_left(){
		makecrctable();
		Init();
	}
	///一気に値を求める。@return CRC値
	static unsigned long signature(const BYTE c[],int n)
	{
		unsigned int r;
		makecrctable();

		r = 0xFFFFU;
		while (--n >= 0)
			r = (r << CHAR_BIT) ^ crctable[(unsigned char)(r >> (16 - CHAR_BIT)) ^ *c++];
		return ~r & 0xFFFFU;
	}
	///初期化する
	void Init(){
		mR = 0xFFFFU;
		mResult = 0;
	}
	///データをぶち込む
	void Load(const BYTE c[], int n){
		while (--n >= 0)
			mR = (mR << CHAR_BIT) ^ crctable[(unsigned char)(mR >> (16 - CHAR_BIT)) ^ *c++];
	}
	/*!
	@note
	Finalを二回呼び出すと不正な値になる。
	*/
	///最後に計算する。@return GetDigestと同じ
	ULONG Final(void){
		mResult  = ~mR & 0xFFFFU;
		return mResult;
	}
	///@return 求めた値を返す。
	ULONG GetDigest()const{
		return mResult;
	}
};

class crc16_ccitt_right{
	static unsigned int crctable[UCHAR_MAX + 1];


	static void makecrctable(void)
	{
		static bool inited = false;
		unsigned int i, j, r;
		if(inited){
			return;
		}

		for (i = 0; i <= UCHAR_MAX; i++) {
			r = i;
			for (j = 0; j < CHAR_BIT; j++)
				if (r & 1) r = (r >> 1) ^ DKUTIL_CRC16_CCITT_POLY2;
				else       r >>= 1;
			crctable[i] = r;
		}
		inited = true;
	}
	unsigned int mR;
	unsigned int mResult;


public:
	crc16_ccitt_right(){
		makecrctable();
		Init();
	}
	///@return 一気にCRCを求めて返す。
	static unsigned long signature(const BYTE c[],int n)
	{
		unsigned int r;
		makecrctable();

		r = 0xFFFFU;
		int i = 0;
		/*while (--n >= 0)//               (byte)
			r = (r >> CHAR_BIT) ^ crctable[(BYTE)r ^ *c++];*/
		while(--n >= 0){
			r = (r >> CHAR_BIT) ^ crctable[(BYTE)r ^ c[i++]];
		}
		return r ^ 0xFFFFU;
	}
	///初期化する
	void Init(){
		mR = 0xFFFFU;
		mResult = 0;
	}
	///データをぶち込む
	void Load(const BYTE c[], int n){
		while (--n >= 0)
			mR = (mR >> CHAR_BIT) ^ crctable[(BYTE)mR ^ *c++];
	}
	/*!
	@note
	Finalを二回呼び出すと不正な値になる。
	*/
	///最後に計算する。@return GetDigestと同じ
	ULONG Final(void){
		mResult  = mR ^ 0xFFFFU;
		return mResult;
	}
	///@return 求めた値を返す。
	ULONG GetDigest()const{
		return mResult;
	}
};

}//end of detail
}//end of dkutil
	
#if defined(DKUTIL_NOT_USE_SELF_LIBRARY) && !defined(DKUTIL_SIGNATURE_CRC_CPP)
#include <dkutil/signature/crc.cpp>
#endif



#endif