/**
@filename macro.hpp
@brief マクロ郡 マクロの動作はconfig.hppで設定してください。
@note

path_stringが見つからない時は
@code
#include <dkutil/filesystem/path_string.hpp>としてみてください。
@endcode

dkutil_cがコンパイルされ、ライブラリをリンクしないと使用できません。
*/
#ifndef DKUTIL_MACRO_HPP
#define DKUTIL_MACRO_HPP

#include <cstddef>
#include <dkutil/config.hpp>
#ifndef DKUTIL_NOT_USE_DKUTIL_C
#	include <dkutil/dkutil_c.hpp>
#else
#	include <crtdbg.h>
#	include <dkutil_c/dkutil_cstd/macro.h>
#endif

#include <helper/boost_assert.hpp>

#ifdef DKUTIL_NOT_USE_DKUTIL_C
#	ifdef DKUTIL_C_DKC_H
#		error DKUTIL_NOT_USE_DKUTIL_C mode
#	endif
#endif

namespace dkutil{


#if 0
inline int error_message(const char *expression,
							const char *filename,size_t line,const char *message,...);

#ifndef DKUTIL_ASSERT_FILENAME_FULLPATH
class path_string;
#endif


inline int error_message(const char *expression,
							const char *filename,size_t line,const char *message,...)
{
	char buff[1024];
	SET_VA_LIST(buff,sizeof(buff),message);
#ifndef DKUTIL_ASSERT_FILENAME_FULLPATH
	path_string ps = filename;
	std::string ts = ps.filename();
	filename = ts.c_str();
#endif
	dkcErrorMessage(expression,filename,line,buff);

#ifdef DKUTIL_ASSERT_EXIT_CALL
	exit(edk_FAILED);
#endif

}
#endif //end of if 0

//typedef std::size_t size_t;
#ifndef DKUTIL_NOT_USE_THROW
#	define DKUTIL_THROW_OR_NOTICE(s) throw s
#	define DKUTIL_THROW(s) throw s
#else
#	ifdef DKUTIL_NOT_USE_DKUTIL_C
#		define DKUTIL_THROW_OR_NOTICE(ex) _ASSERT(#ex)
#	else
#		define DKUTIL_THROW_OR_NOTICE(ex) ( dkcErrorMessage(#ex,__FILE__,__LINE__,NULL) )
#	endif
#	define DKUTIL_THROW(s)
#endif


#ifdef WIN32

///GetLastError 可視化
#define VISUAL_LASTERROR() \
{\
  LPVOID lpMsgBuf;\
  FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,\
			   NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL );\
  ::MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );\
  LocalFree( lpMsgBuf );\
}



#else

#define VISUAL_LASTERROR()

#endif

#ifdef _DEBUG

#ifndef DEBUG
#	define DEBUG 1
#endif
/*!
<PRE>
注意：
例えば以下のようにしないこと
if(hogehoge == hoge) DEBUGMB("ERROR");
訂正
if(hogehoge == hoge) { DEBUGMB("ERROR"); }
</PRE>
*/
///デバッグ時のみのメッセージボックス
#	define DEBUGMB(s) ::MessageBox(NULL,s,"DEBUG MESSAGE BOX",MB_OK)
///デバッグ時のみのOutputDebugString 注意:DEBUGMB()を見てください。
#	define DEBUGODS(s) ::OutputDebugString(s)
///デバッグ時のみのassart
#	include <assert.h>
#	define DEBUGASSERT(s) assert(s)
#else
#	define DEBUGMB(s) {} //念のため{}でもつけておく
#	define DEBUGODS(s) {}
#	define DEBUGASSERT(s) {}
#endif


/*!
SET_VA_LISTの文字列の最後に'\n'を付け足すバージョン<br>
文字列バッファが全部埋まっている場合でも強制的に付け足す。<br>
また、strncatにバッファ数を指定しても文字列最後のNULL文字を破壊する行為)も回避します。<br>
@param s[out] char *のバッファを入れる
@param snum[in] バッファの数
@param origin[in] 元の文字列
*/
///SET_VA_LISTの文字列の最後に'\n'を付け足すバージョン
///警告･･･これにバッファオーバーフロウの危険性があるかも！？誰か指摘してクレイ･･･
#define SET_VA_LIST_INSERT_YEN_N(s,snum,origin) \
	{\
		SET_VA_LIST(s,snum,(origin));\
		size_t len = strlen(s);\
		bool isYen = s[len-1] != '\n';\
		if(len >= snum - 1){\
			if(isYen){\
				s[len-1]='\n';\
			}\
		}else{\
			if(isYen){\
				s[len] = '\n';\
				s[len + 1] = '\0';\
			}\
		}\
	}
/*
#define SET_VA_LIST_INSERT_YEN_N(s,snum,origin) \
	{\
		SET_VA_LIST(s,snum,origin);\
		size_t len = strlen(s);\
		if(s[len-1] != '\n'){\
			if(len >= snum - 1){\
				s[len-1]='\n';\
			}else{\
				strncat(s,"\n",len);\
			}\
		}\
	}*/
/*
//可変引数関数を作る時,文字列バッファを使う場合に必要なバッファの数を得る
#define GET_VALIST_CHAR_BUFF_NUM(origin) \
	{
		va_list VaList;\
		va_start( VaList , origin ) ;\
		int len = strlen(origin);
		for(int i=0;i<len;i++){
			if (_ismbblead((int) origin[i])){
				i++;
				continue;
			}
			if(origin[i] == '%'){//％を見つけたなり
				if(!(i + 1 >= len)){//バッファオーバーフローしないようであれば
					switch(origin[i+1]){
					case 'c'://文字
					case 's'://文字列
					case 'd'://
					case 'u':

				 printf("%i : %o - 符号付8進数（%dと冗長）と符号なし8進数\n" , 0xff , 0xff);
        printf("%x : %X - 符号なし16進数、小文字と大文字\n" , 0xff , 0xff);

        printf("%e : %E - [-]d.dddd e [sign]ddd 形式符号付きの値\n" , 1.24 , 1.24);
        printf("%f - [-]dddd.dddd 形式の符号付きの値\n" , 1.24);
        printf("%g : %G - f,eうち精度を表現できる短い方の書式\n" , 1.24 , 1.24);

        printf("%s : %S - ヌル文字までの文字列\n", STR , STR);

        printf("Kitty%n <- ここまでの出力数を保存\n" , &i);
        printf("%d - ストリームまたはバッファに書き込まれた文字数\n" , i);
        printf("%p - ポインタを表示\n" , i);
*/
/*!
@param result[out] 成功したかどうかを返す true = 成功 false = 失敗
@param s[out] char *　の変数を渡す。これに文字列を格納する内部でmallocするのでEND_GET_MANY_ARGを呼び出すこと
@param add[in] size_t (unsigned long)型の文字列拡張バッファのbyte単位の数を渡す。大体200前後が目安(凄い長い文字列の場合はやっぱりかなり必要になりそう
@param str[in] 元の文字列を渡す
*/
///沢山引数をつける関数のサポート(高機能版)
#define BEGIN_GET_MANY_ARG(result,s,add,str) \
	{ \
		size_t strnum = strlen(str) + add;\
		s = (char *)::malloc(strnum);\
		result = false;\
		if(s){\
			SET_VA_LIST(s,strnum,str);\
			result = true;\
		}\
	}
/*!
@param mem[in] BEGIN_GET_MANY_ARGのsでもらったものを渡す
*/
///沢山引数をつける関数のサポートを終了する
#define END_GET_MANY_ARG(mem) \
	{\
		if(mem){::free(mem);mem=NULL;}\
	}

//	WARNINGマクロ(yane SDKより
#ifdef _DEBUG
#	define DK_WARNING(s) {\
	CHAR buf[256];				\
	wsprintf(buf,"%sファイルの%d行 \n%s",__FILE__,__LINE__,s);	\
	MessageBox(NULL,buf,"WARNING!!",MB_OK);	\
	* LPLONG(0xcdcdcdcd) = 0;	\
	}
#	define YANE_WARNING(b,s)				\
		if(b) {						\
			CHAR buf[256];				\
			wsprintf(buf,"%sファイルの%d行 %s\n",__FILE__,__LINE__,s);	\
			MessageBox(NULL,buf,"WARNING!!",MB_OK);	\
			* LPLONG(0xcdcdcdcd) = 0;	\
		}
	//	最後の* LPLONG(0xcdcdcdcd) = 0;の部分は、メモリエラーをわざと起こすコード
#else
#	define YANE_WARNING(var,s) {}
#	define DK_WARNING(s) 
#endif

//**********************************************************
//その他もろもろのセッティング
//**********************************************************

///状況に応じてインラインを作る(dkutilはC++オンリーだからすでにもう無用のものかも！？
#ifdef __cplusplus
#	define DINLINE inline
#	if _MSC_VER >= 1200
#		undef DINLINE
#		define DINLINE __inline
#	endif//end of __inline
#else
#	define DINLINE 
#endif//end of __cplusplus


///if(false==なんたらかんたら){return false;}を簡略化するためのマクロ
#define DKUTIL_RETURN_FALSE(func) if(false==func){return false;}



#ifndef BOOST_NO_PRIVATE_IN_AGGREGATE //なぜか boost 対応･･･

#	define BOOST_PROTECTED public
#	define BOOST_PRIVATE public

#else
#	define BOOST_PROTECTED protected
#	define BOOST_PRIVATE private
#endif

#ifdef DKUTIL_DEBUG //dkutil debug mode...

#	define DKUTIL_PROTECTED public
#	define DKUTIL_PRIVATE public

#else

#	define DKUTIL_PROTECTED protected
#	define DKUTIL_PRIVATE private

#endif

#define DKUTIL_ARRAY_NUM_OF(s) ( sizeof(s) / sizeof(s[0]) )



}//end of dkutil namespace



#endif
