
#ifndef DKUTIL_MEMORY_CHECK_LEAK_HPP
#define DKUTIL_MEMORY_CHECK_LEAK_HPP


#include <dkutil/memory/interface.hpp>
#include <dkutil/parser/string_util.hpp>
#include <dkutil/boost/strong_typedef.hpp>
#include <new>
namespace dkutil{


class MemoryLeakChecker{
public:
	typedef set_ex_adapter<std::set<std::string> > filename_set_type;
	typedef filename_set_type::iterator fns_iterator;
	typedef std::pair<fns_iterator,bool> fns_result;
	typedef void *pointer;
	typedef struct data_type{
		uint64 size;
		pointer p;
		fns_iterator fn_it;
		uint64 line_;
	}DATA_TYPE;

		
	typedef std::deque<DATA_TYPE> container_type;
	typedef container_type::iterator iterator;
protected:
	filename_set_type mFN;
	container_type mC;
	container_type mDeleteWait;
	uint64 mTotalAllocSize;
	uint64 mLeakSize;
	bool mCheckFlag;
	
	data_type set_data(uint64 size,pointer p,const char *filename,uint64 line_)
	{
		data_type data;
		data.size = size;
		data.p = p;
		fns_result r = mFN.insert(std::string(filename));
		data.fn_it = r.first;
		dkcmNOT_ASSERT(mFN.end() == data.fn_it);
		data.line_ = line_;
		return data;
		
	}
	std::string data_to_string(data_type &x){
		std::string str;
		str = "size : ";
		str += to_string_uint64(x.size);
		str +="line : ";
		str += to_string_uint64(x.line_);
		str += " / file : ";
		str += (*x.fn_it);
		str += "\n";
		return str;
	}
public:
	MemoryLeakChecker(){
		mCheckFlag = false;
	}
	~MemoryLeakChecker(){
		if(mCheckFlag){
			free_all();
			leak_output_debugstring();
		}
	}

	void *allocate(size_t size,const char *filename,uint64 line_){
		void *p = malloc(size);
		if(mCheckFlag)
			mC.push_back(set_data(size,p,filename,line_));	
		return p;
	}
	iterator find(void *p){
		iterator it = mC.begin();
		for(;it != mC.end();it++)
		{
			DATA_TYPE &x = (*it);
			if(p == x.p){
				return it;
			}
		}
		return it;//end()
	}
	void free_all(){
		iterator dit = mDeleteWait.begin();
		for(;dit != mDeleteWait.end();dit++)
		{
			DATA_TYPE &pt = (*dit);
			iterator it = find(pt.p);
			if(mC.end() == it){
				DATA_TYPE &x = (*it);
				std::string str ="line : ";
				str += to_string_uint64(x.line_);
				str += " / file : ";
				str += (*x.fn_it);
				
				std::string er = "MemoryLeakChecker::deallocate() pointer not found\n";
				er += str;
				DKUTIL_THROW_OR_NOTICE(std::runtime_error(er.c_str()));
				//return;
			}
			mC.erase(it);
		}
		mDeleteWait.clear();
	}
	void deallocate(void *p,const char *filename,uint64 line_){
		free(p);
		if(mCheckFlag)
			mDeleteWait.push_back(set_data(0,p,filename,line_));
	}
	void leak_output(std::string &str){
		iterator it = mC.begin();
		for(;it != mC.end();it++)
		{
			str += data_to_string((*it));
		}		
	}
	void leak_output(std::ostream *p){
		iterator it = mC.begin();
		for(;it != mC.end();it++)
		{
			std::string str = data_to_string((*it));
			*p << str;
		}		
	}
	void leak_output_debugstring(){
		iterator it = mC.begin();
		for(;it != mC.end();it++)
		{
			std::string str = data_to_string((*it));
			OutputDebugString(str.c_str());
		}	
	}
	void leak_output_printf(){
		iterator it = mC.begin();
		for(;it != mC.end();it++)
		{
			std::string str = data_to_string((*it));
			printf(str.c_str());
		}	
	}
	void setCheckFlag(bool f){
		//if(false==f){
			free_all();
		//}
		mCheckFlag = f;
	}
	/*
	struct new_local_obj{
		
		int t;
	};
	*/
	typedef int new_local_obj;
};

extern void check_memoryleak(bool flag);
extern void leak_output_debugstring();
extern void leak_output_printf();
extern MemoryLeakChecker::pointer check_memoryleak_alloc_base(size_t size,const char *filename,uint64 line);
extern void check_memoryleak_free_base(MemoryLeakChecker::pointer ,const char *,uint64);

#define dkutil_check_memoryleak_alloc(size) check_memoryleak_alloc_base(size,__FILE__,__LINE__)
#define dkutil_check_memoryleak_free(p) check_memoryleak_free_base(p,__FILE__,__LINE__)





}//end of dkutil namespace
/*
//BOOST_STRONG_TYPEDEF(MemoryLeakChecker::new_local_obj,check_memoryleak_sig);
struct check_memoryleak_sig{};
//extern check_memoryleak_sig dkutil_cml_obj;

extern void *operator new(size_t size,check_memoryleak_sig sig,const char *filename,size_t line_);

extern void* operator new[] (size_t size,check_memoryleak_sig sig,const char *filename,size_t line_);

extern void operator delete (void *p,check_memoryleak_sig sig,const char *filename,size_t line_);

extern void operator delete[] (void *p,check_memoryleak_sig sig,const char *filename,size_t line_);

extern check_memoryleak_sig sig;

#define DKUTIL_CHECK_LEAK_NEW new(sig,(const char *)__FILE__,(int)__LINE__)
#define DKUTIL_CHECK_LEAK_NEW_ARRAY new[](sig,__FILE__,__LINE__)

#define DKUTIL_CHECK_LEAK_DELETE(p) ::operator delete(p,sig,__FILE__,__LINE__)
#define DKUTIL_CHECK_LEAK_DELETE_ARRAY(p) ::operator delete[](p,sig,__FILE__,__LINE__)
*/
#endif