
#ifndef DKUTIL_SIGNATURE_IN_A_MASS_HPP
#define DKUTIL_SIGNATURE_IN_A_MASS_HPP


//#include <dkutil/shared_buffer.hpp>
#include <dkutil/signature/base.hpp>
#include <dkutil/signature/signature_buffer.hpp>
#include <dkutil/registration.hpp>
#include <dkutil/filesystem/big_filestream.hpp>

#include <dkutil/signature/md5.hpp>
#include <dkutil/signature/sha1.hpp>
#include <dkutil/signature/sha256.hpp>
#include <dkutil/signature/sha512.hpp>
#include <dkutil/signature/sha384.hpp>
namespace dkutil{


///シグネチャをまとめて計算してくれるありがたい奴
class CSignatureCalculateInAMass : public ISignature{ 
public:
	typedef registration<ISignature,uint32> container_type;
	typedef container_type::element_sptr_type element_sptr_type;
	typedef container_type::iterator iterator;
	typedef container_type::const_iterator const_iterator;
	typedef CSignatureCalculateInAMass self_type;

	CSignatureCalculateInAMass(){}
	virtual ~CSignatureCalculateInAMass(){}
	void check_limit(){
		if(mCount >= UINT_MAX){
			DKUTIL_THROW_OR_NOTICE(
				signature_error("CSignatureCalculateInAMass::check_limit() limit over")
			);
		}
	}
	void regist(ISignature *p){
		check_limit();
		element_sptr_type tp(p);
		mC.regist(mCount,tp);
		mCount++;
	}
	void clear(){
		mCount = 0;
		mC.clear();
	}
	virtual void init(){
		iterator it = mC.begin();
		for(;it != mC.end();it++)
		{
			(*it).second->init();
		}
	}
	virtual void load(const BYTE *src,size_t size){
		iterator it = mC.begin();
		for(;it != mC.end();it++)
		{
			(*it).second->load(src,size);
		}
	}
	virtual void final(){
		iterator it = mC.begin();
		for(;it != mC.end();it++)
		{
			(*it).second->final();
		}
	}
	///登録した順番でハッシュをdestに吐く
	virtual bool getSignature(BYTE *dest,size_t size,int flag){
		iterator it = mC.begin();
		size_t offset = 0;
		bool r;
		for(;it != mC.end();it++)
		{
			size_t os = (*it).second->getOutputSize(flag);
			r = (*it).second->getSignature(&dest[offset],size - offset,flag);
			offset += os;
			if(false==r) return r;
		}
		return r;
	}


	///@return 登録したオブジェクトのgetOutputSize()すべてを足した数を返す
	virtual size_t getOutputSize(int flag)const{
		size_t size = 0;//no check overflow;
		const_iterator it = mC.begin();
		for(;it != mC.end();it++)
		{
			size += (*it).second->getOutputSize(flag);
		}
		return size;
	}
	container_type &getContainer(){
		return mC;
	}
	typedef std::vector<shared_buffer> output_container;
	///登録した順番で
	bool output(output_container &x,int flag){
		size_t size = 0;//no check overflow;
		iterator it = mC.begin();
		shared_buffer buff;
		bool r;
		for(;it != mC.end();it++)
		{
			size = (*it).second->getOutputSize(flag);
			buff.reset(size);
			r = (*it).second->getSignature(buff.get(),buff.size(),flag);
			x.push_back(buff);
			if(false==r) return r;
		}
		return r;
	}
	template<class SELF_T>
	struct div_read_signatures_functor{
		SELF_T *mcp;
		div_read_signatures_functor(SELF_T *p){
			mcp = p;
		}
		void operator()(const uint8 *buff,size_t size){
			mcp->load(buff,size);

		}
	};
	bool fileToSignatures(parm_string filename,output_container &dest,int flag)
	{
		
		big_filestream rs;
		if(false==rs.reset(filename.c_str(),read_mode | binary_mode) || 
			false==rs.open())
		{
			return false;
		}
		
		typedef div_read_signatures_functor<self_type> drsf_t;
		drsf_t func(this);
		div_read_each_functor<big_filestream,drsf_t> div_read_each;
		div_read_each(&rs,func);
		final();
		return output(dest,flag);
	}
	bool memoryToSignatures(const BYTE *src,size_t srcsize,output_container &dest,int flag)
	{
		init();
		load(src,srcsize);
		final();
		return output(dest,flag);
	}
private:
	container_type mC;
	uint32 mCount;
};

}//end of dkutil namespace



#endif//end of include once

