#include <windows.h>
#include <stdio.h>
#include <mbstring.h>
#include <Commctrl.h>
#include "kbmsxplug_config.h"
#include "maskdlg/maskdlg.h"
#include "edit2413/edit2413.h"
//#include "plsdlg/plsdlg.h"

/*static*/ extern const wchar_t SEC_MSXPLUG[] = L"MSXplug";//kbmsxplug_decoder.cpp から参照される
static const wchar_t SEC_GENERAL[] = L"General";
static const wchar_t KEY_CFG_DLG[] = L"ConfigDlg";
static const wchar_t KEY_MASK_DLG[] = L"MaskDlg";
static const wchar_t KEY_2413_DLG[] = L"2413Dlg";
//static const wchar_t KEY_PLS_DLG[] = L"PlsDlg";
static const wchar_t KEY_CFG_RESET[] = L"ConfigReset";
static const wchar_t KEY_CALC_LENGTH[] = L"CalcLength";
static const wchar_t KEY_EnableKSS[] = L"EnableKSS";
static const wchar_t KEY_EnableMGS[] = L"EnableMGS";
static const wchar_t KEY_EnableBGM[] = L"EnableBGM";
static const wchar_t KEY_EnableMPK[] = L"EnableMPK";
static const wchar_t KEY_EnableOPX[] = L"EnableOPX";
static const wchar_t KEY_EnableMBM[] = L"EnableMBM";
static const wchar_t KEY_EnableMGSLYR[] = L"EnableMGSLyr";
static const wchar_t KEY_MGSLYRFONT[] = L"MGSLyrFont";
static const wchar_t KEY_MGSLYRFONTHEIGHT[] = L"MGSLyrFontHeight";//MGS歌詞フォントの高さ

static const wchar_t KEY_MGSDRV[] = L"MGSDRV";
static const wchar_t KEY_KINROU[] = L"KINROU";
static const wchar_t KEY_MPK103[] = L"MPK103";
static const wchar_t KEY_MPK106[] = L"MPK106";
static const wchar_t KEY_OPXDRV[] = L"OPXDRV";
static const wchar_t KEY_FMBIOS[] = L"FMBIOS";
static const wchar_t KEY_MBMDRV[] = L"MBMDRV";
static const wchar_t KEY_MBKPATH[] = L"MBK_PATH";
static const wchar_t KEY_MBKDUMMY[] = L"MBK_DUMMY";
static const wchar_t KEY_ILL[] = L"ILL";

//ダイアログ位置、プロパティページ保存用
static const wchar_t KEY_CFG_TOPLEFT[] = L"CFG_TOPLEFT";  //設定ダイアログ左上座標
static const wchar_t KEY_CFG_PROPPAGE[] = L"CFG_PROPPAGE";//設定ダイアログ選択ページ
static const wchar_t KEY_MASK_TOPLEFT[] = L"MASK_TOPLEFT";//マスクダイアログ左上座標
static const wchar_t KEY_2413_TOPLEFT[] = L"2413_TOPLEFT";//音色ダイアログ左上座標
static const wchar_t KEY_OPT_TOPLEFT[] = L"OPT_TOPLEFT";//MGS歌詞ダイアログ左上座標
extern HINSTANCE g_hKpi;
static EDIT2413 *g_edit2413 = NULL;

static const wchar_t g_cszMsGothic[] = L"ＭＳ ゴシック";

static int CALLBACK EnumFontProc(const LOGFONT* logFont,
                                 const TEXTMETRIC *textmetric,
                                 DWORD  dwType,
                                 LPARAM lParam)
{
    wchar_t **ppszFonts = (wchar_t**)lParam;
    if(logFont->lfCharSet == SYMBOL_CHARSET){
        return 1;
    }
    if(logFont->lfFaceName[0] == '@'){
        return 1;
    }
    if(!(logFont->lfPitchAndFamily & FIXED_PITCH)){
        return 1;
    }
    wchar_t *pszFont;
    if(*ppszFonts){
        int new_len = wcslen(*ppszFonts) + wcslen(logFont->lfFaceName) + 1 + 1;//タブ文字1字分余計に確保
        pszFont = (wchar_t*)realloc(*ppszFonts, new_len * sizeof(wchar_t));
        wcsncat_s(pszFont, new_len, L"\t", _TRUNCATE);
        wcsncat_s(pszFont, new_len, logFont->lfFaceName, _TRUNCATE);
    }
    else{
        pszFont = _wcsdup(logFont->lfFaceName);
    }
    *ppszFonts = pszFont;
    return 1;
}
static void GetDefaultFont(const wchar_t *cszFonts, wchar_t *pszFontName, int nSize)
{//EnumFontProc から得たフォントリスト(タブ文字で区切られている)を元に
 //デフォルトフォント名を返す
    //MS ゴシックがあるか探す
    const wchar_t *p = cszFonts ? wcsstr(cszFonts, g_cszMsGothic) : NULL;
    if(p){
        if((p[_countof(g_cszMsGothic)-1] == 0 || p[_countof(g_cszMsGothic)-1] == L'\t') &&
            (p == cszFonts || p[-1] == L'\t')){
                wcsncpy_s(pszFontName, nSize, g_cszMsGothic, _TRUNCATE);
                return;
        }
    }
    //MS ゴシックがない
    LOGFONT lfDef = {0};
    GetObject(GetStockObject(SYSTEM_FIXED_FONT), sizeof(LOGFONT), &lfDef);
    wcsncpy_s(pszFontName, nSize, lfDef.lfFaceName, _TRUNCATE);
}
/////////////////////////////////////////////////////////////////////////////
void GetTopLeft(LONG topleft, int *left, int *top)
{
    *top = (short)HIWORD(topleft);
    *left =  (short)LOWORD(topleft);
    //はみ出し防止(マルチモニタは考慮しない)
    if(*top > GetSystemMetrics(SM_CYSCREEN) - 100){
        *top = GetSystemMetrics(SM_CYSCREEN) - 100;
    }
    if(*left > GetSystemMetrics(SM_CXSCREEN) - 100){
        *left = GetSystemMetrics(SM_CXSCREEN) - 100;
    }
    if(*top < 0){
        *top = 0;
    }
    if(*left < 0){
        *left = 0;
    }
}
LONG GetTopLeftFromHwnd(HWND hWnd)
{
    WINDOWPLACEMENT wp = {0};
    wp.length = sizeof(wp);
    wp.flags = 0;
    GetWindowPlacement(hWnd, &wp);
    WORD left = wp.rcNormalPosition.left;
    WORD top = wp.rcNormalPosition.top;
    return MAKELONG(left, top);
}
/////////////////////////////////////////////////////////////////////////////
BOOL __fastcall kbmsxplug_EnumConfig(IKpiConfigEnumerator *pEnumerator)
{
    static const KPI_CFG_SECTION sec[] = {
        {SEC_MSXPLUG, NULL, 
            L"MSXplug の設定です。(in_msx.dll 互換)\r\n"
            L"「その他」タブの MBK 検索パスと規定の MBK ファイルの設定は無視されます。\r\n"
            L"(General セクションの方が適用されます)"},
        {SEC_GENERAL, NULL, 
            L"kbmsxplug.kpi に関する一般的な設定です。"},
        {NULL, NULL, NULL}
    };
    static /*const*/ KPI_CFG_KEY key[] = {//const 不可
        {KPI_CFG_TYPE_BIN, SEC_MSXPLUG, KEY_CFG_DLG, L"設定画面を開く", 
            NULL, NULL, NULL, //default/min/max
            NULL, NULL, //list/listdesc
            L"MSXplug の設定画面を開きます。(in_msx.dll 互換)\r\n"
            L"設定画面上で「適用」ボタンをクリックしても設定は即座には反映されません。\r\n"
            L"ダイアログを閉じてから反映されます。\r\n"
            L"\r\n"
            L"「ミキサー」タブの PSG/SCC/OPLL/OPL を「Mute」すると音が鳴らなくなります。\r\n"
            L"画面上では Mute が有効であることが判別しづらいため、注意が必要です。\r\n"
            L"\r\n"
            L"「その他」タブの MBK 検索パスと規定の MBK ファイルに関する設定は無視されます。\r\n"
            L"(General セクションの方で設定して下さい)"
            },//help
        {KPI_CFG_TYPE_BIN, SEC_MSXPLUG, KEY_MASK_DLG, L"チャンネルマスク", 
            NULL, NULL, NULL, //default/min/max
            NULL, NULL, //list/listdesc
            L"チャンネルマスクの設定画面を開きます。\r\n"
            L"in_msx.dll とは異なり、チャンネルマスクの設定は終了時に保存されます。\r\n"
            L"次回起動時以降、演奏がおかしい場合は設定を確認して下さい。"
            },//help
        {KPI_CFG_TYPE_BIN, SEC_MSXPLUG, KEY_2413_DLG, L"EMU2413 音色エディタ", 
            NULL, NULL, NULL, //default/min/max
            NULL, NULL, //list/listdesc
            L"EMU2413 音色エディタを開きます。音色ファイル(ILLファイル)を作成することが出来ます。\r\n"
            L"作成した ILL ファイルを使用する場合は General セクションで指定して下さい。\r\n"
            L"General セクションで指定している ILL を編集した場合は、曲を開き直せば編集した結果が反映されます。"
            },//help
        /*{KPI_CFG_TYPE_BIN, SEC_MSXPLUG, KEY_PLS_DLG, L"プレイリストエディタ", 
            NULL, NULL, NULL, //default/min/max
            NULL, NULL, //list/listdesc
            L"プレイリストエディタを開きます。"
            },//help
        */
        {KPI_CFG_TYPE_BIN, SEC_MSXPLUG, KEY_CFG_RESET, L"設定を初期値に戻す", 
            NULL, NULL, NULL, //default/min/max
            NULL, NULL, //list/listdesc
            L"MSXplug の設定を初期値に戻します。\r\n"
            L"チャンネルマスクの設定も初期値に戻します。\r\n"
            L"ここでは General セクションの設定は初期値に戻しません。\r\n"
            },//help
    //General
       {KPI_CFG_TYPE_INT, SEC_GENERAL, KEY_CALC_LENGTH, L"曲長計算(秒)",
            L"0", L"0", L"1800", //default/min/max
            L"0\t180\t300\t360\t480\t600\t900\t1200",
            L"しない\t3分\t5分\t6分\t8分\t10分\t15分\t20分",
            L"曲の長さを計算します。\r\n"
            L"指定時間が大きいと長さが不明の曲の計算に時間がかかります。\r\n"
            L"指定時間が小さいと曲長の取得に失敗しやすくなります。\r\n"
            L"0 にすると曲長計算を行いません。\r\n"
            L"\r\n"
            L"例えば指定時間を 5 分にした場合、5分以内に演奏終了または1ループ目の終了位置が見つからない場合は曲長の取得に失敗します。\r\n"
            L"5 分以内に1ループ目の終了位置が見つかっても、2ループ目の終了位置が 5 分より先だとループ時間が不明となります。\r\n"
            L"ループ時間が不明の場合はループ時間=1ループ目の終了位置と見なします。イントロがある曲ではイントロ時間も含めた長さがループ時間と見なされるため、"
            L"ループ回数指定が正しく機能しなくなります。\r\n"
            L"曲長の取得に失敗した場合は曲長不明なループ曲と見なします。本体の「デフォルトの曲の長さ」だけ再生されます。\r\n" 
            L"最後まで確実に再生されるようにするには単曲リピートを有効にするか「デフォルトの曲の長さ」を大きくする必要があります。"},//
        {KPI_CFG_TYPE_BOOL, SEC_GENERAL, KEY_EnableKSS, NULL,
            L"1", NULL, NULL, //default/min/max
            NULL, //list
            NULL, //listdesc
            L"KSS の拡張子(.kss)を有効にします。\r\n"
            L"KSS は他のプラグインで再生したい場合は false にして下さい。",//help
            },
        {KPI_CFG_TYPE_BOOL, SEC_GENERAL, KEY_EnableMGS, NULL,
            L"1", NULL, NULL, //default/min/max
            NULL, //list
            NULL, //listdesc
            L"MGSDRV の拡張子(.mgs)を有効にします。\r\n"
            L"MGSDRV は他のプラグインで再生したい場合は false にして下さい。",//help
            },
        {KPI_CFG_TYPE_BOOL, SEC_GENERAL, KEY_EnableBGM, NULL,
            L"1", NULL, NULL, //default/min/max
            NULL, //list
            NULL, //listdesc
            L"MuSICA の拡張子(.bgm/.bgr)を有効にします。\r\n"
            L"MuSICA は他のプラグインで再生したい場合は false にして下さい。",//help
            },
        {KPI_CFG_TYPE_BOOL, SEC_GENERAL, KEY_EnableMPK, NULL,
            L"1", NULL, NULL, //default/min/max
            NULL, //list
            NULL, //listdesc
            L"MPK の拡張子(.mpk)を有効にします。\r\n"
            L"MPK は他のプラグインで再生したい場合は false にして下さい。",//help
            },
        {KPI_CFG_TYPE_BOOL, SEC_GENERAL, KEY_EnableOPX, NULL,
            L"1", NULL, NULL, //default/min/max
            NULL, //list
            NULL, //listdesc
            L"OPLL Driver の拡張子(.opx)を有効にします。\r\n"
            L"OPLL Driver は他のプラグインで再生したい場合は false にして下さい。",//help
            },
        {KPI_CFG_TYPE_BOOL, SEC_GENERAL, KEY_EnableMBM, NULL,
            L"1", NULL, NULL, //default/min/max
            NULL, //list
            NULL, //listdesc
            L"MoonSound の拡張子(.mbm)を有効にします。\r\n"
            L"MoonSound は他のプラグインで再生したい場合は false にして下さい。",//help
            },
        {KPI_CFG_TYPE_FILE, SEC_GENERAL, KEY_MGSDRV, L"MGSDRV.COM", 
            L"", L"MGSDRV.COM\t*.com", NULL, //default/min/max
            NULL, NULL, //list/listdesc
            L"MGS の再生に必要な MGSDRV.COM を指定します。内蔵しているため、通常は未指定で問題ありません。"},//help
        {KPI_CFG_TYPE_FILE, SEC_GENERAL, KEY_KINROU, L"KINROU5.DRV", 
            L"", L"KINROU5.DRV\t*.drv", NULL, //default/min/max
            NULL, NULL, //list/listdesc
            L"BGM の再生に必要な KINROU5.DRV を指定します。内蔵しているため、通常は未指定で問題ありません。"},//help
        {KPI_CFG_TYPE_FILE, SEC_GENERAL, KEY_MPK103, L"MPK103.BIN", 
            L"", L"MPK103.BIN\t*.bin", NULL, //default/min/max
            NULL, NULL, //list/listdesc
            L"MPK の再生に必要な MPK103.BIN を指定します。内蔵しているため、通常は未指定で問題ありません。"},//help
        {KPI_CFG_TYPE_FILE, SEC_GENERAL, KEY_MPK106, L"MPK.BIN", 
            L"", L"MPK106.BIN\t*.bin", NULL, //default/min/max
            NULL, NULL, //list/listdesc
            L"MPK の再生に必要な MPK.BIN を指定します。内蔵しているため、通常は未指定で問題ありません。"},//help
        {KPI_CFG_TYPE_FILE, SEC_GENERAL, KEY_OPXDRV, L"OPX4KSS.BIN", 
            L"", L"OPX4KSS.BIN\t*.bin", NULL, //default/min/max
            NULL, NULL, //list/listdesc
            L"OPX の再生に必要な OPX4KSS.BIN を指定します。内蔵しているため、通常は未指定で問題ありません。"},//help
        {KPI_CFG_TYPE_FILE, SEC_GENERAL, KEY_FMBIOS, L"FMPAC.ROM", 
            L"", L"FMPAC.ROM\t*.rom", NULL, //default/min/max
            NULL, NULL, //list/listdesc
            L"OPX の再生に必要な FMPAC.ROM を指定します。FMPAC.ROM は内蔵していません。FMPAC.ROM があると OPX 再生時の再現性が向上します。"
            L"FMPAC.ROM がない場合、拡張音色は全てPSG風の音で再生されます。"},//help
        {KPI_CFG_TYPE_FILE, SEC_GENERAL, KEY_MBMDRV, L"MBR143.001", 
            L"", L"MBR143.001\t*.001", NULL, //default/min/max
            NULL, NULL, //list/listdesc
            L"MBM の再生に必要な MBR143.001 を指定します。内蔵しているため、通常は未指定で問題ありません。"},//help
        {KPI_CFG_TYPE_FILE, SEC_GENERAL, KEY_ILL, L"音色ファイル", 
            L"", L"ILL ファイル(*.ILL)\t*.ill", NULL, //default/min/max
            NULL, NULL, //list/listdesc
            L"ILL2 形式の音色ファイルに対応しています．音色ファイルを読み込ませる場合は指定します。\n"
            L"MSXplug セクションの EMU2413 音色エディタで音色ファイルを作成することが出来ます。"
            },//help
        {KPI_CFG_TYPE_FOLDER, SEC_GENERAL, KEY_MBKPATH, L"MBK 検索パス", 
            NULL, NULL, NULL, //default/min/max
            NULL, NULL, //list/listdesc
            L"MBM 再生時に使用される MBK の検索パスを指定します。\r\n"
            L"MSXplug の設定画面(「その他」タブ)で設定しても無視されます。\r\n"
            L"\r\n"
            L"以下の順に MBK ファイルを検索します。\r\n"
            L"・MBM ファイルと同名の MBK ファイル(MBM ファイルと同一フォルダ)\r\n"
            L"・MBM ファイルのヘッダに記述された MBK ファイル(MBM ファイルと同一フォルダ)\r\n"
            L"・MBM ファイルのヘッダに記述された MBK ファイル(MBK 検索パスで指定したフォルダ)\r\n"
            L"・「規定の MBK ファイル」で指定した MBK ファイル(MBM ファイルと同一フォルダ)"},//help
        {KPI_CFG_TYPE_STR, SEC_GENERAL, KEY_MBKDUMMY, L"規定の MBK ファイル", 
            L"__DUMMY.MBK", NULL, NULL, //default/min/max
            NULL, NULL, //list/listdesc
            L"MBM 再生時に使用される MBK の既定のファイル名を指定します。MBK の検索順序については「MBK 検索パス」を参照して下さい。\r\n"
            L"MSXplug の設定画面(「その他」タブ)で設定しても無視されます。"},//help
        {KPI_CFG_TYPE_BOOL, SEC_GENERAL, KEY_EnableMGSLYR, L"MGS 歌詞表示",
            L"1", NULL, NULL, //default/min/max
            NULL, //list
            NULL, //listdesc
            L"true にすると MGS 内蔵の歌詞を表示します。\r\n"
            L"歌詞はプレイヤー本体からは独立したウィンドウに表示されます。",//help
            },
        {KPI_CFG_TYPE_STR, SEC_GENERAL, KEY_MGSLYRFONT, L"MGS 歌詞フォント",
            L"1", NULL, NULL, //default/min/max
            NULL, //list
            NULL, //listdesc
            L"使用出来るのは固定幅フォントのみです。\r\n"
            L"歌詞ウィンドウのサイズを変えれば文字サイズも変わりますが、"
            L"フォントとサイズの組み合わせによっては表示が不自然になることがあります。",//help
            },
        {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
    };

    LOGFONT lf = {0};
    lf.lfCharSet = SHIFTJIS_CHARSET;
    wchar_t *pszFonts = NULL;
    HDC hDC = GetDC(NULL);
    EnumFontFamiliesEx(hDC, &lf, EnumFontProc,(LPARAM)&pszFonts, 0);
    ReleaseDC(NULL, hDC);
    wchar_t szDefFont[LF_FACESIZE];
    GetDefaultFont(pszFonts, szDefFont, _countof(szDefFont));
    for(int i = 0; sec[i].cszSection; i++){
        pEnumerator->EnumSection(&sec[i]);
    }
    for(int i = 0; key[i].cszSection; i++){
        if(key[i].cszKey == KEY_MGSLYRFONT){
            key[i].cszDefault = szDefFont;
            key[i].cszList = pszFonts;
        }
        pEnumerator->EnumKey(&key[i]);
        if(key[i].cszKey == KEY_MGSLYRFONT){
            key[i].cszDefault = NULL;//念の為
            key[i].cszList = NULL;   //念の為
        }
    }
    free(pszFonts);
    return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
DWORD __fastcall kbmsxplug_ApplyConfig(IKpiConfig *pConfig,
                               const wchar_t *cszSection,//セクション名
                               const wchar_t *cszKey,    //キー名
                               INT64  nValue, //変更後の値(BOOL/INT の場合)
                               double dValue, //変更後の値(FLOAT の場合)
                               const wchar_t *cszValue)////変更後の値(文字列)
{
    if(_wcsicmp(cszKey, KEY_CFG_DLG) == 0){
        kbmsxplug_Settings settings;
        kbmsxplug_GetSettings(pConfig, &settings);
        for(int i=0; i<EDSC_MAX; i++){
            settings.config->curvol[i] = settings.config->vol[i];
        }
        LONG topleft = pConfig->GetInt(SEC_MSXPLUG, KEY_CFG_TOPLEFT, 0);
        int page = pConfig->GetInt(SEC_MSXPLUG, KEY_CFG_PROPPAGE, 0);
        int left, top;
        GetTopLeft(topleft, &left, &top);
        CONFIG_dialog_show(settings.config, NULL, g_hKpi, page, left, top);
        HWND hDlg = settings.config->dialog;
        //ダイアログが閉じられるまで待つ
        MSG msg;
        while(GetMessage(&msg, NULL, 0, 0) > 0){
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            if(!settings.config->dialog){
                break;
            }
        }
        pConfig->SetInt(SEC_MSXPLUG, KEY_CFG_TOPLEFT, settings.config->topleft);
        pConfig->SetInt(SEC_MSXPLUG, KEY_CFG_PROPPAGE, settings.config->prop_page);
        CONFIG_save(settings.config, pConfig);
        CONFIG_delete(settings.config);
        return KPI_CFGRET_RELOAD_DATA;
    }
    else if(_wcsicmp(cszKey, KEY_MASK_DLG) == 0){
        kbmsxplug_Settings settings;
        kbmsxplug_GetSettings(pConfig, &settings);
        LONG topleft = pConfig->GetInt(SEC_MSXPLUG, KEY_MASK_TOPLEFT, 0);
        int left, top;
        GetTopLeft(topleft, &left, &top);
        MASKDLG dlg = {0};
        dlg.cfg = settings.config;
        MASKDLG_open(&dlg, NULL, g_hKpi, left, top);
        //ダイアログが閉じられるまで待つ
        MSG msg;
        while(GetMessage(&msg, NULL, 0, 0) > 0){
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            if(!dlg.dialog){
                break;
            }
        }
        pConfig->SetInt(SEC_MSXPLUG, KEY_MASK_TOPLEFT, dlg.topleft);
        CONFIG_save(settings.config, pConfig);
        CONFIG_delete(settings.config);
        return KPI_CFGRET_RELOAD_DATA;
    }
    else if(_wcsicmp(cszKey, KEY_2413_DLG) == 0){
        LONG topleft;
        int left, top;
        if(!g_edit2413){
            g_edit2413 = EDIT2413_new();
            topleft = pConfig->GetInt(SEC_MSXPLUG, KEY_2413_TOPLEFT, 0);
        }
        else if(!g_edit2413->hMain){
            topleft = g_edit2413->topleft;
        }
        else{
            return KPI_CFGRET_OK;
        }
        GetTopLeft(topleft, &left, &top);
        EDIT2413_open(g_edit2413, NULL, g_hKpi, left, top);
        SetWindowPos(g_edit2413->hMain, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
        //ダイアログが閉じられるまで待つ
        /*MSG msg;
        while(GetMessage(&msg, NULL, 0, 0) > 0){
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            if(!g_edit2413->hMain){
                break;
            }
        }
        EDIT2413_delete(g_edit2413);
        g_edit2413 = NULL;*/
        return KPI_CFGRET_OK;
    }
    /*else if(_wcsicmp(cszKey, KEY_PLS_DLG) == 0){
        PLSDLG *plsdlg = PLSDLG_new();
        PLSDLG_open(plsdlg, g_hKpi, NULL);
        //ダイアログが閉じられるまで待つ
        MSG msg;
        while(GetMessage(&msg, NULL, 0, 0) > 0){
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            if(!plsdlg->hDialog){
                break;
            }
        }
        PLSDLG_delete(plsdlg) ;
        return KPI_CFGRET_OK;
    }*/
    else if(_wcsicmp(cszKey, KEY_CFG_RESET) == 0){
        int nRet = MessageBox(NULL, L"MSXplug の設定を初期値に戻しますか?", L"確認", MB_YESNO|MB_DEFBUTTON2);
        if(nRet == IDYES){
            CONFIG *cfg = CONFIG_new(L"", (wchar_t*)SEC_MSXPLUG);
            //CONFIG_load(cfg, pConfig);//ロードしないで保存すれば初期値に戻る
            CONFIG_save(cfg, pConfig);
            CONFIG_delete(cfg);
            //設定ダイアログの位置も初期値に戻す(念の為)
            pConfig->SetInt(SEC_MSXPLUG, KEY_CFG_TOPLEFT, 0);
            pConfig->SetInt(SEC_MSXPLUG, KEY_CFG_PROPPAGE, 0);
            pConfig->SetInt(SEC_MSXPLUG, KEY_MASK_TOPLEFT, 0);
            pConfig->SetInt(SEC_MSXPLUG, KEY_2413_TOPLEFT, 0);
            pConfig->SetInt(SEC_MSXPLUG, KEY_OPT_TOPLEFT, 0);
            return KPI_CFGRET_RELOAD_DATA;
        }
        return KPI_CFGRET_OK;
    }
    static const struct CFGRET_TABLE
    {
        const wchar_t *cszKey;
        DWORD dwRet;
    }cfgret_table[] = {
        {KEY_MBKPATH, KPI_CFGRET_RELOAD_DATA},
        {KEY_MBKDUMMY, KPI_CFGRET_RELOAD_DATA},
        {KEY_ILL, KPI_CFGRET_RELOAD_DATA},
        {NULL, 0},
    };
    pConfig->SetStr(cszSection, cszKey, cszValue);
    for(int i = 0; cfgret_table[i].cszKey; i++){
        if(_wcsicmp(cszKey, cfgret_table[i].cszKey) == 0){
            return cfgret_table[i].dwRet;
        }
    }
    if(!cszKey[0]){
        return KPI_CFGRET_OK;
    }
    return KPI_CFGRET_RELOAD_KPI;//デフォルトは KPI_CFGRET_RELOAD_KPI
}
/////////////////////////////////////////////////////////////////////////////
void __fastcall kbmsxplug_GetSettings(IKpiConfig *pConfig, kbmsxplug_Settings *pSettings)
{//CONFIG の save/delete は呼び出し側で行う
    CONFIG *cfg = CONFIG_new(L"", (wchar_t*)SEC_MSXPLUG);
    CONFIG_load(cfg, pConfig);
    pSettings->config = cfg;
    pConfig->GetStr(SEC_GENERAL, KEY_MBKPATH, pSettings->szMbkPath, sizeof(pSettings->szMbkPath), L"");
    pConfig->GetStr(SEC_GENERAL, KEY_MBKDUMMY, pSettings->szMbkDummy, sizeof(pSettings->szMbkDummy), L"__DUMMY.MBK");
    if(!pSettings->szMbkDummy[0]){
        wcsncpy_s(pSettings->szMbkDummy, L"__DUMMY.MBK", _TRUNCATE);
    }
    pConfig->GetStr(SEC_GENERAL, KEY_ILL, pSettings->szILL, sizeof(pSettings->szMbkDummy), L"");
    pConfig->GetStr(SEC_GENERAL, KEY_MGSLYRFONT, pSettings->szFont, sizeof(pSettings->szFont), g_cszMsGothic);
    if(!pSettings->szFont[0]){
        wcsncpy_s(pSettings->szFont, g_cszMsGothic, _TRUNCATE);
    }
    pSettings->nMgsDlgFontHeight = pConfig->GetInt(SEC_GENERAL, KEY_MGSLYRFONTHEIGHT, 18);
    pSettings->nMgsDlgTopLeft = pConfig->GetInt(SEC_MSXPLUG, KEY_OPT_TOPLEFT, 0);
    pSettings->bEnableMgsLyr = pConfig->GetInt(SEC_GENERAL, KEY_EnableMGSLYR, 1) != 0;
    pSettings->dwCalcLengthSec = pConfig->GetInt(SEC_GENERAL, KEY_CALC_LENGTH, 0);
    if(pSettings->dwCalcLengthSec > 30*60){//最大30分(念の為)
        pSettings->dwCalcLengthSec = 30*60;        
    }
}
/////////////////////////////////////////////////////////////////////////////
void __fastcall kbmsxplug_GetDriverPaths(IKpiConfig *pConfig, kbmsxplug_DriverPaths *pDriverPaths)
{
    struct{//static不可
        const wchar_t *cszKey;
        wchar_t *pszData;
        int      nSize;
    }s[] = {
        {KEY_MGSDRV, pDriverPaths->szMGSDRV, sizeof(pDriverPaths->szMGSDRV)},//MGSDRV.COM
        {KEY_KINROU, pDriverPaths->szKINROU, sizeof(pDriverPaths->szKINROU)},//KINROU5.DRV
        {KEY_MPK106, pDriverPaths->szMPK106, sizeof(pDriverPaths->szMPK106)},//MPK.BIN
        {KEY_MPK103, pDriverPaths->szMPK103, sizeof(pDriverPaths->szMPK103)},//MPK103.BIN
        {KEY_OPXDRV, pDriverPaths->szOPXDRV, sizeof(pDriverPaths->szOPXDRV)},//OPX4KSS.BIN
        {KEY_FMBIOS, pDriverPaths->szFMBIOS, sizeof(pDriverPaths->szFMBIOS)},//FMPAC.ROM
        {KEY_MBMDRV, pDriverPaths->szMBMDRV, sizeof(pDriverPaths->szMBMDRV)},//MBR143.001
        {NULL, NULL, 0}
    };
    for(int i= 0; s[i].cszKey; i++){
        pConfig->GetStr(SEC_GENERAL, s[i].cszKey, s[i].pszData, s[i].nSize, L"");
    }
}
/////////////////////////////////////////////////////////////////////////////
void __fastcall kbmsxplug_GetSupportExts(IKpiConfig* pConfig, wchar_t *pszExts, int nSize)
{
    static const struct{
        const wchar_t *cszKey;
        const wchar_t *cszExts;
    }s[] = {
        {KEY_EnableKSS, L".kss"},
        {KEY_EnableMGS, L".mgs"},
        {KEY_EnableBGM, L".bgm/.bgr"},
        {KEY_EnableMPK, L".mpk"},
        {KEY_EnableOPX, L".opx"},
        {KEY_EnableMBM, L".mbm"},
        {NULL, NULL}
    };
    pszExts[0] = 0;
    for(int i = 0; s[i].cszKey; i++){
        if(pConfig->GetInt(SEC_GENERAL, s[i].cszKey, 1) != 0){
            if(pszExts[0])wcsncat_s(pszExts, nSize, L"/", _TRUNCATE);
            wcsncat_s(pszExts, nSize, s[i].cszExts, _TRUNCATE);
        }
    }
}
/////////////////////////////////////////////////////////////////////////////
void __fastcall kbmsxplug_DeleteDlg(IKpiConfig *pConfig)//アンロード前に呼び出す
{
    if(g_edit2413){
        EDIT2413_close(g_edit2413);
        pConfig->SetInt(SEC_MSXPLUG, KEY_2413_TOPLEFT, g_edit2413->topleft);
        EDIT2413_delete(g_edit2413);
        g_edit2413 = NULL;
    }
}
/////////////////////////////////////////////////////////////////////////////
void __fastcall kbmsgplug_SetMgsDlgSettings(IKpiConfig *pConfig, int nTopLeft, int  nFontHeight)
{
    pConfig->SetInt(SEC_MSXPLUG, KEY_OPT_TOPLEFT, nTopLeft);
    pConfig->SetInt(SEC_GENERAL, KEY_MGSLYRFONTHEIGHT, nFontHeight);
}
