// MainNavigator.cpp :
// メインウインドウのナビゲータ

#include "stdafx.h"
#include "RNSF7.h"
#include "MainWindow.h" 
#include "MainSearchRsc.h"
#include "MainListview.h"
#include "OpenSetting.h"
#include "pre_interprete.h"

const char *OTHERS = "分類なし";

// 定義部から読み込めるデータより、mlviをセットする。lpmlvi->rsc_fname に、あらかじめファイル名を入れておく
bool setItemData(LPMLVI lpmlvi)
{
	// 初期化（lr失敗時の保険）
	lpmlvi->contextid = 1;
	lpmlvi->item = lpmlvi->info = lpmlvi->help = lpmlvi->author = lpmlvi->url = lpmlvi->category = NULL;
	lpmlvi->hicon = NULL;
	LOAD_RSC lr;

	if ( LR_OK == lr.source_load(lpmlvi->rsc_fname) ) {
		int ec;

		lr.searchItem(LR_SI_LOAD, NULL, 0, ec);
		if (ec == LR_OK) {
			lpmlvi->item = _strdup( lr.searchItem(LR_SI_ITEM, lpmlvi->rsc_fname, 0, ec) );			// タイトル
			lpmlvi->info = _strdup( lr.searchItem(LR_SI_INFORMATION, lpmlvi->rsc_fname, 0, ec) );	// 情報欄に表示される内容
			lpmlvi->help = _strdup( lr.searchItem(LR_SI_HELP, "none", 0, ec) );			// ヘルプファイル
			lpmlvi->contextid = atou( lr.searchItem(LR_SI_CONTEXTID, "0", 0, ec) );		// ヘルプID (.hlpの場合)
			lpmlvi->author = _strdup( lr.searchItem(LR_SI_AUTHOR, "", 0, ec) );			// 作者情報
			lpmlvi->url = _strdup( lr.searchItem(LR_SI_URL, "", 0, ec) );				// 作者のURL
			lpmlvi->category = _strdup( lr.searchItem(LR_SI_CATEGORY, OTHERS, 0, ec) );	// カテゴリ分類名
			char *r = _strdup( lr.searchItem(LR_SI_ICON, "", 0, ec) );					// アイコン

			if ( r && r[0] ) {
				// r == RNSF7.EXE だった場合は、このプログラムのリソースからアイコンを読み込む
				char *p, r_fname_part[LENGTH_LINE];

				lpmlvi->hicon = lpmlvi->hSmallIcon = 0;
				lstrcpy(r_fname_part, r);
				p = strstr(r_fname_part, ",-");
				if ( p ) {
					char exename[MAX_PATH*2], fname[_MAX_FNAME*2], ext[_MAX_EXT*2];

					// Icon=で指定されたファイル＋負のアイコン番号のうち、ディレクトリ名＋ファイル名の部分のみを取り出す
					// ただし、ディレクトリ名が付いていたら、ここで「自プログラムからのアイコンの読み出し」処理は飛ばされる
					// つまり、ここで有効なのは、ディレクトリ名が付いていないファイル名が指定された場合のみである
					*p = 0;

					// 現在実行中のプログラムファイル名のうち、ファイル名の部分のみを取り出す
					GetModuleFileName(NULL, exename, _countof(exename));
					_splitpath_s(exename, NULL, 0, NULL, 0, fname, _countof(fname), ext, _countof(ext));
					_makepath_s(exename, _countof(exename), NULL, NULL, fname, ext);

					if ( _stricmp(r_fname_part, exename) == 0 ) { // 自プログラム内からのアイコン読みだし
#pragma warning( disable : 4312 )
						lpmlvi->hicon = (HICON)LoadImage(hInst, (LPCSTR)atoi(p+2), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
						lpmlvi->hSmallIcon = (HICON)LoadImage(hInst, (LPCSTR)atoi(p+2), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
#pragma warning( default : 4312 )
					}
				}
				if ( lpmlvi->hicon == (HICON)0 && lpmlvi->hSmallIcon == (HICON)0 ) {
					// 普通にアイコンを読み込む(ExtractIconEx)
					LoadIconFromFileEx(r, &(lpmlvi->hicon), &(lpmlvi->hSmallIcon));
				}
			}
		}
	}

	// 定義部に該当するアイテムが見つからなかった場合
	if ( !lpmlvi->item ) {
		lpmlvi->item = lpmlvi->rsc_fname;
	}
	if ( !lpmlvi->info ) {
		lpmlvi->info = lpmlvi->rsc_fname;
	}
	if ( !lpmlvi->help ) {
		lpmlvi->help = _strdup( "none" );
	}
	if ( !lpmlvi->author ) {
		lpmlvi->author = _strdup( "" );
	}
	if ( !lpmlvi->url ) {
		lpmlvi->url = _strdup( "" );
	}
	if ( !lpmlvi->category ) {
		lpmlvi->category = _strdup( OTHERS );
	}
	if ( !lpmlvi->hicon ) {
		char *icofile_def = _strdup( lpmlvi->rsc_fname );

		if ( icofile_def ) {
			int i = lstrlen(icofile_def); // デフォルト文字列生成のために拡張子だけ ICO にする
			if ( i > 3 ) {
				icofile_def[i-3] = 'I'; icofile_def[i-2] = 'C'; icofile_def[i-1] = 'O';
			}
			LoadIconFromFileEx(icofile_def, &(lpmlvi->hicon), &(lpmlvi->hSmallIcon));
			safefree( icofile_def );
		}
	}
	if ( lpmlvi->hicon == (HICON)0 || lpmlvi->hicon == (HICON)1 ) { // error
		// デフォルトのrscアイコン
		lpmlvi->hicon = NULL;
	}
	if ( lpmlvi->hSmallIcon == (HICON)0 || lpmlvi->hSmallIcon == (HICON)1 ) { // error
		// デフォルトのrscアイコン
		lpmlvi->hSmallIcon = NULL;
	}

	return true;
}

bool searchRSCs( HWND hWnd )
{
	WIN32_FIND_DATA520 ffd;
	HANDLE	ffh;
	int     i, n, no_others = -1, num_categorys = 0;
	const char *trytry;
	LPMLVI tmp;

	// （あれば）リストビューの機能項目リストを削除
	SendMessage( hWnd, R7MW_DELETEICONS, 0, NULL );

	ItemCount = 0;
	num_categorys = n = 0;
	no_others = -1;

	// とりあえず RSCSTD
	// (標準で付属するスクリプトはRSCSTD個未満なので、とりあえずメモリはRSCSTD個分準備しておく)
    mlvi = (LPMLVI)calloc(RSCSTD+1, sizeof(MLVI));

	if ( INVALID_HANDLE_VALUE != (ffh = FindFirstFile520("*.RSC", &ffd)) ) {
		do {
			// 拡張子.rscを持つファイルはリストビューに並べる候補
			if ( !(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
				// goto :tryを実行してみてabortの返ってくるものは一覧に並べない(OSによって動作しないものを表示しないため)
				// 起動時の高速化のため、定義部に try=off または try=abort があったら tryは実行しない
				LOAD_RSC lr;
				int ec;

				if ( LR_OK != lr.source_load(ffd.cFileName) ) {
					continue;
				}

				lr.searchItem(LR_SI_LOAD, NULL, 0, ec);
				if ( ec != LR_OK ) {
					lr.errmes(hWnd);
					continue;
				}

				trytry = lr.searchItem(LR_SI_TRY, "ON", 0, ec);

				if ( _stricmp(trytry, "OFF") == 0 )
					;
				else if ( _stricmp(trytry, "ABORT") == 0 )
					continue;
				else if ( (trytry[0] == 'I' || trytry[0] == 'i') && (trytry[1] == 'F' || trytry[1] == 'f') ) {
					if ( !rsc1line(hWnd, trytry+2) )
						continue;
				}
				else if ( 2 == rsc(hWnd, ffd.cFileName, ":try", 1, NULL) )
					continue;

				if ( n >= RSCSTD ) { // 万が一、nがRSCSTD個を超えた場合は、メモリを再確保
					tmp = (LPMLVI)realloc( mlvi, sizeof(MLVI)*(n+1) );
				}
				else {
					tmp = mlvi;
				}


				if ( tmp ) {
					mlvi = tmp;
					// RSCファイル名の記録
					mlvi[n].rsc_fname = _strdup(ffd.cFileName);

					// アイテム名等の読み出し
					setItemData( &mlvi[n] );

					// 最終更新日時の記録 (ファイル最終更新日時をローカル日時に変換)
					FileTimeToLocalFileTime(&(ffd.ftLastWriteTime), &(mlvi[n].ft));

					// ファイルサイズ(4GB以下)
					mlvi[n].fsize = ffd.nFileSizeLow;

					// 検索結果フラグを初期化
					mlvi[n].foundflag = 0;

					// mlvi[n].category が新しいカテゴリ名なら、categorysをリサイズして追加する
					if ( categorys ) {
						for(i=0 ; categorys[i] ; i++) {
							if ( strcmp(categorys[i], mlvi[n].category) == 0 ) { // これまでのカテゴリ一覧から見つかった
								free( mlvi[n].category );
								mlvi[n].category = categorys[i]; // mlvi[n].categoryは解放し、既存のポインタを指させる
								break;
							}
						}
						if ( categorys[i] == NULL ) { // これまでのカテゴリの一覧からは見つからなかった
							char **tmp;

							tmp = (char **)realloc(categorys, sizeof(char *)*(i+2));
							if ( tmp ) {
								categorys = tmp;
							}
							else {
								i = -1;
							}
						}
						else { // これまでのカテゴリ一覧から見つかった
							i = -1;
						}
					}
					else { // categorys をはじめて作成する
						categorys = (char **)malloc(sizeof(char *)*2);
						i = 0;
					}
					if ( i >= 0 && categorys ) {
						categorys[i] = mlvi[n].category; // 既存のバッファへのポインタを指させるので、これをわざわざ解放してはいけない
						categorys[i+1] = NULL;			// 最終バッファの次には必ずNULLを入れる

						if ( strcmp(categorys[i], OTHERS) == 0 ) {
                            no_others = i;
						}

						num_categorys = i;
					}
					n++;
				}
			}
		} while( FindNextFile520( ffh, &ffd ) );
		FindClose( ffh );
	}

	if ( n < RSCSTD ) { // nがRSCSTD個に満たなかった場合は、メモリを削る
		tmp = (LPMLVI)realloc( mlvi, sizeof(MLVI)*(n+1) );
		if ( tmp ) {
			mlvi = tmp;
		}        
	}

	ItemCount = n;
	if ( no_others >= 0 && no_others != num_categorys ) { // 「分類なし」はカテゴリ一覧の一番最後に持って行く
		char *tmp;

		tmp = categorys[no_others];
		categorys[no_others] = categorys[num_categorys];
		categorys[num_categorys] = tmp;
	}

	return ItemCount>0?true:false;
}
