
#ifndef DKUTIL_COMPRESSION_BLOCKSORT_HPP
#define DKUTIL_COMPRESSION_BLOCKSORT_HPP


#include <dkutil_c/dkcBlockSort.h>
#include <dkutil/compression/interface.hpp>

namespace dkutil{



class CBlockSort : public IArrayProcess{

	size_t mEncodedSize;

	struct CBlockSortHeader{
		///シグネチャ
		ULONG sig;
		///BlockSortの状態
		DKC_BLOCKSORT_INFO info;
	};
	BOOST_STATIC_CONSTANT(int,header_size = sizeof(CBlockSortHeader));

	bool check_sig(CBlockSortHeader *p){
		return (p->sig == getSignature());
	}
public:
	///@see reset()
	CBlockSort(ULONG signature=edk_BLOCKSORT_SIGNATURE){
		reset(signature);
		
	}
	~CBlockSort(){
		
	}
	///@param signature[in] BlockSortで圧縮されていることを証明するID（デフォルトでは dkcdBlockSort_SIGNATURE )
	bool reset(ULONG signature=edk_BLOCKSORT_SIGNATURE){
		setSignature(signature);
		setResult(edk_FAILED);
		mEncodedSize = 0;
		return true;
	}

	int decode(const BYTE *src,size_t size,BYTE *dest,size_t destsize){
		const BYTE *sp = src + header_size;
		size_t ssize = size - header_size;
		int r = edk_FAILED;
		//バッファの先頭にヘッダファイルがある。
		CBlockSortHeader *hp = (CBlockSortHeader*)src;

		dkcmNOT_ASSERT(check_sig(hp)==FALSE);
		if(check_sig(hp)==FALSE){
			return r;
		}
		if(destsize < ssize){
			return r;
		}
		memcpy(dest,sp,ssize);

		r = dkcBlockSortDecode(
			dest,ssize,
			&(hp->info)
		);

		//結果を入れる。
		setResult(r);

		return r;

	}

	int encode(const BYTE *src,size_t size,BYTE *dest,size_t destsize){
		BYTE *bp = dest + header_size;
		size_t bsize = destsize - header_size;
		int r = edk_FAILED;
		DKC_BLOCKSORT_INFO info;
		
		if(size > bsize){
			return r;
		}
		//destにコピー
		memcpy(bp,src,size);

		//destをソート
		r = dkcBlockSortEncode(bp,size,&info);
		if(DKUTIL_FAILED(r)){
			return r;
		}

		//update
		CBlockSortHeader *hp = (CBlockSortHeader *)dest;
		hp->sig = getSignature();
		hp->info = info;

		mEncodedSize = size + header_size;
		setResult(r);
		
		return r;
	}	
	
	
	virtual size_t getEncodedSize()const{
		return mEncodedSize;
	}
	
	///エンコード時の出力予定のサイズ (普通より大きめの値を返されます。) 
	virtual size_t getEncodeOutputSize(size_t size)const{
		return size + header_size;
	}
	/**
	@param pHeader[in] デコードする予定のデータ
	@param size[in] デコードする予定のサイズ
	@throw アクセス不可な所へアクセスしようとすると std::runtime_errorをぷっぱなす。
	*/
	///デコード時の出力予定のサイズ　
	virtual size_t getDecodeOutputSize(const void *pHeader,size_t size)const{
		if(size < header_size){
			DKUTIL_THROW_OR_NOTICE(std::runtime_error("CBLockSort::getDecodeOutputSize() size argument exception"));
			return 0;
		}
		CBlockSortHeader *p = (CBlockSortHeader *)pHeader;
		size_t s = size + header_size;
		return s;
	}

};
		

}//end of dkutil namespace



#endif