
#ifndef _dkutilOutput__h_
#define _dkutilOutput__h_

#include "dKingyoMacro.h"
#include "dkutilDefinedC.h"
#include "dkutilLog.h"
#if defined(__GNUG__)
#	include <dkutil/config/dkutilUserConfig.h>
#endif

namespace dkutil{
	



/*!
できればReleaseビルド時は使わないようにしてください。内部で面倒な処理が入りますので。<br>
*/
///OutputDebugStringの引数拡張OKバージョン(Debugビルドのみしか機能しません。)
inline bool dOutputDebugString(char *str,...){
	char s[1024 * 2];
	SET_VA_LIST_INSERT_YEN_N(s,sizeof(s),str);
	OutputDebugString(s);
	//fprintf(stderr,s);
	return true;
}

inline void dODS(const char *str,...){
	char s[1024]="";
	SET_VA_LIST_INSERT_YEN_N(s,1024,str);
	dOutputDebugString(s);
	/*char s[1024];
	SET_VA_LIST_INSERT_YEN_N(s,1024,str);
	OutputDebugString(s);*/
}
inline void dODSNoConst(char *str,...){
	char s[1024]="";
	SET_VA_LIST_INSERT_YEN_N(s,1024,str);
	dOutputDebugString(s);
}
inline void dODSNoNewLine(const char *str,...){
	char s[1024]="";
	SET_VA_LIST(s,1024,str);
	OutputDebugString(s);
	//fprintf(stderr,s);
}

inline bool SuperODS(const char *str,...){
	char s[2048]="";
	SET_VA_LIST(s,sizeof(s),str);
	dOutputDebugString(s);
	printf(s);
	return true;
}


/*
class Win32LastError{
	DKConfigUtility mUtil;
	static std::string mbuf;
protected:
	void MTLockToString(std::string &mbuf,DWORD ErrorID,bool flag)
	{
		DKUTIL_LOCKTHREAD(mUitl);
		ToString(mbuf,ErrorID,flag);
		DKUTIL_UNLOCKTHREAD(mUitl);
	}
public:
	Win32LastError(){}
	virtual ~Win32LastError(){}
	const char *operator()(){
		MTLockToString(mbuf,0,false);
		return mbuf.c_str();
	}
	const char *operator()(DWORD ErrorID){
		MTLockToString(mbuf,ErrorID,true);
		return mbuf.c_str();
	}
	void ToString(std::string &buf,DWORD ErrorID,bool flag=false)
	{
		mbuf.clear();
		LPVOID lpMsgBuf;
		if(flag){
			::FormatMessage(
				FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
				NULL, 
				ErrorID, 
				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL 
				);
		}else{
			::FormatMessage(
				FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
				NULL, 
				GetLastError(), 
				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL 
				);
		}
		mbuf = "ERROR Message:";
		mbuf += (LPCTSTR)lpMsgBuf;
		LocalFree( lpMsgBuf );
	}

	DWORD GetLastError(){
		DWORD ErrorID;
		DKUTIL_MULTITHREAD_SYNDROME_LOCK(mUitl);
		ErrorID = ::GetLastError();
		DKUTIL_MULTITHREAD_SYNDROME_UNLOCK(mUitl);
		return ErrorID;
	}
};


std::string Win32LastError::mbuf;
*/	
class Win32LastError{
	DKConfigUtility mUtil;
	std::string mbuf;
protected:
	void MTLockToString(std::string &mbuf,DWORD ErrorID,bool flag)
	{
		DKUTIL_LOCKTHREAD(mUitl);
		ToString(mbuf,ErrorID,flag);
		DKUTIL_UNLOCKTHREAD(mUitl);
	}
public:
	Win32LastError(){}
	virtual ~Win32LastError(){}
	const char *operator()(){
		MTLockToString(mbuf,0,false);
		return mbuf.c_str();
	}
	const char *operator()(DWORD ErrorID){
		MTLockToString(mbuf,ErrorID,true);
		return mbuf.c_str();
	}
	void ToString(std::string &buf,DWORD ErrorID,bool flag=false)
	{
		mbuf.clear();
		LPVOID lpMsgBuf;
		if(flag){
			::FormatMessage(
				FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
				NULL, 
				ErrorID, 
				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL 
				);
		}else{
			::FormatMessage(
				FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
				NULL, 
				GetLastError(), 
				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL 
				);
		}
		mbuf = "ERROR Message:";
		mbuf += (LPCTSTR)lpMsgBuf;
		LocalFree( lpMsgBuf );
	}

	DWORD GetLastError(){
		DWORD ErrorID;
		DKUTIL_MULTITHREAD_SYNDROME_LOCK(mUitl);
		ErrorID = ::GetLastError();
		DKUTIL_MULTITHREAD_SYNDROME_UNLOCK(mUitl);
		return ErrorID;
	}
};


///アサート関数
inline bool dkassert(const char *expression,
										 const char *filename,size_t line,const char *message,...)
{
	char s[1024]="";
	if(message){
		SET_VA_LIST_INSERT_YEN_N(s,sizeof(s),message);
	}else{
		SET_VA_LIST_INSERT_YEN_N(s,sizeof(s),"No message");
	}
	char ss[1024 * 2]="";
	_snprintf(ss,sizeof(ss),
		"DKUTIL_ASSERT(%s):\nfile:%s / \n line:%d / \n message: %s",
		expression,filename,line,s);
	dOutputDebugString(ss);
#ifdef NDEBUG
#	ifdef WIN32
	//::MessageBox(NULL,ss,"ERROR ASSERTION !!",MB_OK);
	{
		LPCTSTR name="ERROR_TEMP.txt";
		{
			//ファイルをオープン
			FILE *fp;
			if(NULL != (fp = fopen( name , "at" ))){
			
				// エラーログファイルに書き出す
				fputs( ss , fp ) ;
				fclose( fp ) ;
			}
		}
		::ShellExecute(NULL, "open",name, NULL, NULL, SW_SHOWNORMAL);
		::DeleteFile(name);
	}
	MB("このテキストをこのソフトの開発者に渡せば、バグ発見の近道なります。\n \
		開発者に知らせるときはこのテキストを転記してあげましょう。");
	if(IDYES==::MessageBox(NULL,
		"このままこのソフトを起動しつづけると、更なるエラーが発生する可能性があります。\n終了しますか？",
		"あってはいけない エラー!!!",
		MB_YESNO))
	{
		exit(edk_FAILED);
		//terminate();
	}else{
	}
#	endif	

#else
	assert(!expression);
#endif
	return true;
}

#ifndef NDEBUG
#	define DKUTIL_TRUE_ASSERT(ex) ( (ex) && dkassert(#ex,__FILE__,__LINE__,NULL) )
#	define DKUTIL_ASSERT(ex) ( (ex) || dkassert(#ex,__FILE__,__LINE__,NULL) )
#	define DKUTIL_TRUE_ASSERT_MESSAGE(ex,mes) ( (ex) && dkassert(#ex,__FILE__,__LINE__,mes) )
#	define DKUTIL_ASSERT_MESSAGE(ex,mes) ( (ex) || dkassert(#ex,__FILE__,__LINE__,mes) )
#else
#	define DKUTIL_TRUE_ASSERT_MESSAGE(ex,mes) ((void)0)
#	define DKUTIL_ASSERT_MESSAGE(ex,mes) ((void)0)
#	define DKUTIL_TRUE_ASSERT(ex) ((void)0)
#	define DKUTIL_ASSERT(ex) ((void)0)
#endif


#	define SET_VA_LIST_DMB(a1,a2) SET_VA_LIST(a1,sizeof(a1),a2)	
inline void dMB(char *str,...){
	char s[1024]="";
	SET_VA_LIST_DMB(s,str);
	::MessageBox(NULL,s,"Message",MB_OK);
}
inline void dMB(HWND hWnd,char *title,UINT uType,char *str,...){
	char s[1024];
	SET_VA_LIST_DMB(s,str);
	::MessageBox(hWnd,s,title,uType);
}
inline void dMB(char *title,char *str,...){
	char s[1024];
	SET_VA_LIST_DMB(s,str);
	::MessageBox(NULL,s,title,MB_OK);
}
inline void dMB(UINT uType,char *str,...){
	char s[1024];
	SET_VA_LIST_DMB(s,str);
	::MessageBox(NULL,s,"Message",uType);
}

inline void dMB(const char *s){
	::MessageBox(NULL,s,"Message",MB_OK);
}
#	undef SET_VA_LIST_DMB

	
}//end of dkutil namespace

#endif //end of include once

