#include "app.h"
/****************************************************************************
 *	main
 ****************************************************************************/
#ifdef  USE_LUA
static int atpanic(lua_State* L) {
	die("atpanic: %s", luaL_checkstring(L, -1));
}
#endif//USE_LUA
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int main(int argc, char* argv[]) {
	int exitCode = EXIT_SUCCESS;
#ifdef  _DEBUG
	remove("syslog.out");			//毎回ログを削除する事にした。
    #ifndef USE_JOB_DEBUG
	openlog(NULL, LOG_PERROR, LOG_USER);	//デバッグビルドでは、システムログを標準エラーにも出力する。ただし、デバッグジョブを使用する場合は、デバッグジョブのcurses表示と衝突しないよう、標準エラーには出力しない。
    #endif//USE_JOB_DEBUG
#else //_DEBUG
	setlogmask(LOG_UPTO(LOG_INFO));		//リリースビルドでは、LOG_DEBUGを抑制する。
#endif//_DEBUG
#if     (defined(GC_H) && !defined(USE_BISON_FLEX))
	putenv("GC_LOG_FILE=CON");//ログ出力先を指定する。
	GC_set_find_leak(1);//メモリリーク検出を開始する。
#endif//(defined(GC_H) && !defined(USE_BISON_FLEX))
#ifdef  __CLIP_SEH_H__
	SEH_init();
#endif//__CLIP_SEH_H__
//{{DATA
#ifdef  __CLIP_REG_H__
	if(!(TBL_RegTbl = (const unsigned char*)LockResource(LoadResource(NULL, FindResource(NULL, "RegTbl", "RegTbl"))))) { DIE(); }
#endif//__CLIP_REG_H__
#ifdef  __CLIP_ANMS_H__
	if(!(TBL_AnmSeqNo = (const int*)LockResource(LoadResource(NULL, FindResource(NULL, "AnmSeq", "AnmSeq"))))) { DIE(); }
#endif//__CLIP_ANMS_H__
#ifdef  __CLIP_NCSS_H__
	if(!(TBL_NcsSeqNo = (const int*)LockResource(LoadResource(NULL, FindResource(NULL, "NcsSeq", "NcsSeq"))))) { DIE(); }
#endif//__CLIP_NCSS_H__
#ifdef  __CLIP_DIRS_H__
	if(!(TBL_DirTblNo = (const int*)LockResource(LoadResource(NULL, FindResource(NULL, "DirSeq", "DirSeq"))))) { DIE(); }
#endif//__CLIP_DIRS_H__
#ifdef  __CLIP_EVTM_H__
	if(!(TBL_EvtTmrNo = (const int*)LockResource(LoadResource(NULL, FindResource(NULL, "EvtTmr", "EvtTmr"))))) { DIE(); }
#endif//__CLIP_EVTM_H__
#ifdef  __CLIP_LEDS_H__
	if(!(TBL_LedSeqNo = (const int*)LockResource(LoadResource(NULL, FindResource(NULL, "LedDef", "LedDef"))))) { DIE(); }
#endif//__CLIP_LEDS_H__
#ifdef  __CLIP_TAPS_H__
	if(!(TBL_TapSeqNo = (const int*)LockResource(LoadResource(NULL, FindResource(NULL, "TapDef", "TapDef"))))) { DIE(); }
#endif//__CLIP_TAPS_H__
#ifdef  __CLIP_AFXB_H__
	if(!(TBL_AfxSeqNo = (const int*)LockResource(LoadResource(NULL, FindResource(NULL, "AfxBin", "AfxBin"))))) { DIE(); }
#endif//__CLIP_AFXB_H__
#ifdef  __CLIP_LOT_H__
	if(!(TBL_LotTblNo = (const int*)LockResource(LoadResource(NULL, FindResource(NULL, "LotTbl", "LotTbl"))))) { DIE(); }
//	LotRom_Init(TBL_LotTblNo, (int (*)())rnd16, &seed);		//┐
//	LotRom_Init(TBL_LotTblNo, (int (*)())mrand48, NULL/*ダミー*/);	//├どれか一つを選択して下さい。
	LotRom_Init(TBL_LotTblNo, (int (*)())WELL_next, &well);		//┘
#endif//__CLIP_LOT_H__
#ifdef  __CLIP_ENM_H__
	if(!(pEnmKey = REG_open_key(TBL_RegTbl, RegKey_EnmDef))) { DIE(); }
#endif//__CLIP_ENM_H__
#ifdef  __CLIP_PRP_H__
	if(!(pPrpKey = REG_open_key(TBL_RegTbl, RegKey_PrpTbl))) { DIE(); }
	PrpHdr_init(phApp, pPrpKey, PrpTbl_App);
#endif//__CLIP_PRP_H__
#ifdef  __CLIP_FSM_H__
	if(!(pFsmKey = REG_open_key(TBL_RegTbl, RegKey_FsmMap))) { DIE(); }
	FsmObj_Init(&foApp, pFsmKey, FsmMap_App, NULL);
#endif//__CLIP_FSM_H__
#ifdef  __CLIP_ACT_H__
	aoApp = ActObj_New(NULL);
#endif//__CLIP_ACT_H__
//}}DATA
#ifdef  __CLIP_WKST_H__
	pWS = Worksheet_new();
#endif//__CLIP_WKST_H__
#ifdef  USE_SQLITE
	if(!(db = sqlite_open(":memory:", 0, NULL))) { DIE(); }
#endif//USE_SQLITE
#ifdef  USE_PDCURSES
	initscr();
	refresh();//initscr()の直後にrefresh()を呼び出しておくのはPDCursesの定石です。
#endif//USE_PDCURSES
#ifdef  USE_GDIPLUS
	Gdiplus_Init();
#endif//USE_GDIPLUS
#ifdef  USE_PCL
	co_thread_init();
#endif//USE_PCL
#ifdef  USE_LUA
	if(!(L = luaL_newstate())) { DIE(); }
	lua_atpanic(L, atpanic);
	luaL_openlibs(L);
#endif//USE_LUA
#ifdef  USE_ACTIVETCL
	if(!(interp = Tcl_CreateInterp())) { DIE(); }
	Tcl_FindExecutable(argv[0]);
	if(Tcl_Init(interp) || Tk_Init(interp)) { DIE(); }
	if(Tcl_VarEval(interp, "wm title . {", argv[0], "}", NULL)) { DIE(); }
#endif//USE_ACTIVETCL
	app_init(argc, argv);
	exitCode = app_main(argc, argv);
	app_exit();
#ifdef  USE_ACTIVETCL
	Tcl_DeleteInterp(interp);
#endif//USE_ACTIVETCL
#ifdef  USE_LUA
	lua_close(L);
#endif//USE_LUA
#ifdef  USE_PCL
	co_thread_cleanup();
#endif//USE_PCL
#ifdef  USE_GDIPLUS
	Gdiplus_Exit();
#endif//USE_GDIPLUS
#ifdef  USE_PDCURSES
	endwin();
#endif//USE_PDCURSES
#ifdef  USE_SQLITE
	sqlite_close(db);
#endif//USE_SQLITE
#if     (defined(GC_H) && !defined(USE_BISON_FLEX))
	CHECK_LEAKS();//メモリリークを検出する。
#endif//(defined(GC_H) && !defined(USE_BISON_FLEX))
#ifdef  USE_ACTIVETCL
	Tcl_Exit(exitCode);
	/* NOTREACHED */
#endif//USE_ACTIVETCL
	return exitCode;
}
/****************************************************************************
 *	usage
 ****************************************************************************/
__declspec(noreturn) static void usage() {
	//※TODO:
	exit(EXIT_FAILURE);
}
/****************************************************************************
 *	
 ****************************************************************************/
void app_init(int argc, char* argv[]) {
//{{アプリケーション特有の処理
	{
		seed = GetTickCount();
		srand(seed);
		srand48(seed);
		WELL_init(&well, seed);
	}
//}}アプリケーション特有の処理
#ifdef  USE_DXLIB
	cpp_init(argc, argv);
#endif//USE_DXLIB
}
/*--------------------------------------------------------------------------*/
void app_exit() {
//{{アプリケーション特有の処理
	{
		//※TODO:
	}
//}}アプリケーション特有の処理
#ifdef  USE_DXLIB
	cpp_exit();
#endif//USE_DXLIB
}
/*--------------------------------------------------------------------------*/
#ifdef  __cplusplus
#ifdef  USE_GDIPLUS
static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	switch(uMsg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_PAINT:
		{
			PAINTSTRUCT ps;
			HDC hDC = BeginPaint(hWnd, &ps);
			Graphics* graphics = new Graphics(hDC);
			if(graphics->GetLastStatus()) { DIE(); }
			if(graphics->Clear(Color.Red)) { DIE(); }
			wchar_t* fname = strdup_ShiftJisToUnicode("C:/usr/PIECE/HTML/IMAGE/MENULOGO.GIF");
			Image* image = new Image(fname);
			if(image->GetLastStatus()) { DIE(); }
			free(fname);
			if(graphics->DrawImage(image, 0, 0)) { DIE(); }
			delete image;
			delete graphics;
			EndPaint(hWnd, &ps);
		}
		return 0;
	}
	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
#endif//USE_GDIPLUS
#endif//__cplusplus
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int app_main(int argc, char* argv[]) {
	int exitCode = EXIT_SUCCESS;
#if 0
	{
		int opt;
		opterr = 0; //オプションエラーは当プログラム内で処理するので、getopt()内でのエラー表示は不要。
		while((opt = getopt(argc, argv, "eh")) != -1) {	//コマンドラインオプションを処理する。
			switch(opt) {
		    #ifdef  USE_BISON_FLEX
			case 'e':
				{
					//エラーログファイル名を作成する。
					// - カレントフォルダに'実行ファイル名.err'という名前で生成する事にした。この動作は、'lk33.exe'の仕様を参考にした。
					char fname[MAX_FNAME];
					splitpath(argv[0], NULL, NULL, fname, NULL);
					makepath(err_path, NULL, NULL, fname, ".err");
					//'-e'オプションが指定されたら、最初に確実に、既存のエラーログファイルを削除しておく。
					//前回に生成したエラーログが残っていて、今回生成したエラーログと混同する危険を避けるためである。
					//尚、'-e'オプションが指定されなかった場合は、既存のエラーログファイルを削除する処理は行わない。
					remove(err_path);
				}
				break;
		    #endif//USE_BISON_FLEX
			case 'h':
			default:
				usage();
			}
		}
	}
	{
		char* glbuf = NULL;	//┬getline()用バッファ
		int   glcap = 0;	//┘
		FILE* fp = stdin;	//入力ファイルが指定されていなければ、標準入力を一回処理する。
		do {
			if(optind < argc) {	//入力ファイルが指定されていたら…
				fp = fopen(argv[optind], "r");		//入力ファイルを開く。
				if(!fp) { error(EXIT_FAILURE, errno, "%s が開けません。", argv[optind]); }
			}
			while(getline(&glbuf, &glcap, fp) != EOF) {	//一行読み込む。ファイル終端でなければ…
				//※TODO:
			}
			if(optind < argc) {	//入力ファイルが指定されていたら…
				fclose(fp);	//入力ファイルを閉じる。
				optind++;	//次の入力ファイルへ進める。
			}
		} while(optind < argc);
		free(glbuf);	//getline()用バッファを開放する。
	}
#endif
#ifdef  __cplusplus
#ifdef  USE_GDIPLUS
	{
		WNDCLASS wc;
		HWND hWnd;
		MSG msg;
		memset(&wc, 0, sizeof wc);
		wc.style = (CS_HREDRAW|CS_VREDRAW);
		wc.lpfnWndProc = WndProc;
		wc.hInstance = GetModuleHandle(NULL);
		wc.hCursor = LoadCursor(NULL, IDC_ARROW);
		wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
		wc.lpszClassName = program_invocation_short_name;
		if(!RegisterClass(&wc)) { DIE(); }
		hWnd = CreateWindow(
			program_invocation_short_name,
			program_invocation_short_name,
			WS_OVERLAPPEDWINDOW,
			CW_USEDEFAULT, CW_USEDEFAULT,
			CW_USEDEFAULT, CW_USEDEFAULT,
			NULL, NULL, wc.hInstance, NULL);
		if(!hWnd) { DIE(); }
		ShowWindow(hWnd, SW_SHOW);
		UpdateWindow(hWnd);
		while(GetMessage(&msg, NULL, 0, 0)) {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
#endif//USE_GDIPLUS
#endif//__cplusplus
#if     (defined(USE_ACTIVETCL) && !defined(USE_DXLIB))
	while(Tk_GetNumMainWindows()) {
		while(Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT)) { /** no job **/ }
		//※TODO:
	}
#endif//(defined(USE_ACTIVETCL) && !defined(USE_DXLIB))
#ifdef  __CLIP_RRS_H__
	//汎用の同期ルートを初期化する。
	syncRoot.req = 2/*変更可*/;
	//Round Robin Scheduler (RRS)を初期化する。
	RRS_new_l(&pRRS, 0/*stacksize*/,
	    #ifdef  USE_JOB_DEBUG
		job_debug,	//デバッグジョブ
	    #endif//USE_JOB_DEBUG
		job_main,	//計算ジョブ
		//{{TODO:ここにジョブ関数を追加して下さい。}}
		NULL/*終端*/);
#endif//__CLIP_RRS_H__
#ifdef  __CLIP_MSGH_H__
	//メッセージハンドシェイクを初期化する。
	MsgHsk_Init(&stMsgHsk, pRRS);
#endif//__CLIP_MSGH_H__
#ifdef  USE_DXLIB
	exitCode = cpp_main(argc, argv);	//UIジョブ
#else //USE_DXLIB
    #ifdef  __CLIP_RRS_H__
	for(;;) { RRS_yield(pRRS); }	//UIジョブを実行せず,かつ,RRSを使用する場合は、ここで無限ループする事にしました。そうしないとすぐにプロセスが終了してしまい、計算ジョブを実行する前にプロセスが終了してしまうからです。
    #endif//__CLIP_RRS_H__
#endif//USE_DXLIB
	return exitCode;
}
/****************************************************************************
 *	デバッグジョブ
 ****************************************************************************/
#ifdef  USE_JOB_DEBUG
void job_debug(ST_RRS* pRRS) {
	ST_PrpEdt* pPrpEdt = PrpEdt_new(phApp->pPrpKey, phApp->iTbl, phApp + 1, 0, fnVarFmt, stdscr, PRPEDT_PATH_W, PRPEDT_VAL_W);
	nodelay(stdscr, 1);
	curs_set(0);
	for(;;) {
		wnoutrefresh(stdscr);
		doupdate();
		RRS_yield(pRRS);
		if(PrpEdt_exec(pPrpEdt) == '\x1B') { break; }
		PrpEdt_draw(pPrpEdt);
	}
	PrpEdt_free(pPrpEdt);
	exit(EXIT_SUCCESS);
}
#endif//USE_JOB_DEBUG
/****************************************************************************
 *	計算ジョブ
 ****************************************************************************/
#ifdef  __CLIP_RRS_H__
void job_main(ST_RRS* pRRS) {
	for(;;) {
	    #ifdef  USE_DXLIB
		schedule();	//計算ジョブからもschedule()を呼び出せるようにしました。計算ジョブ特有の周期処理が不要な場合はRRS_yield(pRRS)を呼び出しても構いません。
	    #else //USE_DXLIB
		RRS_yield(pRRS);
	    #endif//USE_DXLIB
	}
	exit(EXIT_SUCCESS);
}
#endif//__CLIP_RRS_H__
//{{DATA
/****************************************************************************
 *	変数フォーマッタ
 ****************************************************************************/
#ifdef  __CLIP_PRP_H__
void fnVarFmt(char* buf/*[cap]*/, int cap, int iFmt, int iVal) {
	if(iVal >= 0) {
#ifdef  __CLIP_ENM_H__
		int iRegKey;
		switch(iFmt) {
		default:DIE();
		case PrpFmt_Color:	iRegKey = RegKey_Color;		break;
		//{{TODO:ここにPrpFmt_〜の処理を追加して下さい。}}
		}
		snprintf(buf, cap, "%d(%s)", iVal, EnmDef_ToStr(pEnmKey, iRegKey, iVal));
#else //__CLIP_ENM_H__
		switch(iFmt) {
		default:DIE();
		case PrpFmt_Color:
			{
				//'MkNamDef.bat Define.h'で生成,編集しました。
				static const char* const TBL_NamDef_Color[5]={
				"白",     //0 Color_White
				"灰(淡)", //1 Color_GlayW
				"灰(濃)", //2 Color_GlayB
				"黒",     //3 Color_Black
				"マスク", //4 Color_Mask 
				};
				if((unsigned)iVal >= ARRAY_SIZE(TBL_NamDef_Color)) { DIE(); }
				snprintf(buf, cap, "%d(%s)", iVal, TBL_NamDef_Color[iVal]);
			}
			break;
		//{{TODO:ここにPrpFmt_〜の処理を追加して下さい。}}
		}
#endif//__CLIP_ENM_H__
	} else {
		snprintf(buf, cap, "%d", iVal);
	}
}
#endif//__CLIP_PRP_H__
//}}DATA
