#include <windows.h>
#include <stdio.h>
#include "kbsc68_config.h"

static const wchar_t SEC_GENERAL[] = L"General";
static const wchar_t KEY_SAMPLERATE[] = L"SampleRate";
static const wchar_t KEY_ASID[] = L"asid";
static const wchar_t KEY_YM_ENGINE[] = L"ym-engine";
static const wchar_t KEY_YM_FILTER[] = L"ym-filter";
static const wchar_t KEY_YM_VOLMODEL[] = L"ym-volmodel";
static const wchar_t KEY_AGA_BLEND[] = L"amiga-blend";
static const wchar_t KEY_AGA_FILTER[] = L"amiga-filter";
static const wchar_t KEY_AGA_CLOCK[] = L"amiga-clock";

static const DWORD SAMPLERATE_DEFAULT = 44100;
static const wchar_t SZ_SAMPLERATE_DEFAULT[] = L"44100";
static const DWORD ASID_DEFAULT = 0;
static const wchar_t SZ_ASID_DEFAULT[] = L"0";
static const DWORD YM_ENGINE_DEFAULT = 0;
static const wchar_t SZ_YM_ENGINE_DEFAULT[] = L"0";
static const DWORD YM_FILTER_DEFAULT = 0;
static const wchar_t SZ_YM_FILTER_DEFAULT[] = L"0";
static const DWORD YM_VOLMODEL_DEFAULT = 0;
static const wchar_t SZ_YM_VOLMODEL_DEFAULT[] = L"0";
static const DWORD AGA_BLEND_DEFAULT = 80;
static const wchar_t SZ_AGA_BLEND_DEFAULT[] = L"80";
static const DWORD AGA_FILTER_DEFAULT = 0;
static const wchar_t SZ_AGA_FILTER_DEFAULT[] = L"0";
static const DWORD AGA_CLOCK_DEFAULT = 0;
static const wchar_t SZ_AGA_CLOCK_DEFAULT[] = L"0";


extern HINSTANCE g_hKpi;
/////////////////////////////////////////////////////////////////////////////
BOOL __fastcall kbsc68_EnumConfig(IKpiConfigEnumerator *pEnumerator)
{
    static const KPI_CFG_SECTION sec[] = {
        {SEC_GENERAL, L"General", L"kbsc68.kpi に関する一般的な設定です。"},
        {NULL, NULL, NULL}
    };
    static const KPI_CFG_KEY key[] = {
    //   type, section, key, keydesc, default, min, max, list, listdesc, help
        {KPI_CFG_TYPE_INT, SEC_GENERAL, KEY_SAMPLERATE, L"再生周波数",
            SZ_SAMPLERATE_DEFAULT, NULL, NULL, //default/min/max
            L"44100\t48000\t88200\t96000\t-44100\t-48000\t-88200\t-96000", //list
            L"44100Hz\t48000Hz\t88200Hz\t96000Hz\t"
            L"44100Hz(要求を無視)\t48000Hz(要求を無視)\t88200Hz(要求を無視)\t96000Hz(要求を無視)", //listdesc
            L"本体からの要求が 0 の場合の再生周波数です。\r\n"
            L"\r\n"
            L"負の値を指定すると本体からの要求を無視します。\r\n"
            L""            
            },//help
        {KPI_CFG_TYPE_INT, SEC_GENERAL, KEY_ASID, L"aSIDfier",
            SZ_ASID_DEFAULT, NULL, NULL, //default/min/max
            L"0\t1\t2", //list
            L"off\ton\tforce", //listdesc
            L"0: off\r\n"
            L"1: on\r\n"
            L"2: force\r\n"
            L"\r\n"
            L"on にする場合は「ドキュメント」部の「aSid」の値が 1\r\n"
            L"である曲に対して有効なようです。\r\n"
            L"force にする場合は「aSid」の値に関わらず有効なようです。\r\n"
            L""
            },//help
        {KPI_CFG_TYPE_INT, SEC_GENERAL, KEY_YM_ENGINE, L"YM-2149 engine",
            SZ_YM_ENGINE_DEFAULT, NULL, NULL, //default/min/max
            L"0\t1\t2", //list
            L"blep\tpulse\tdump",//listdesc
            L"0: blep\r\n"
            L"1: pulse\r\n"
            L"2: dump\r\n"
            L"\r\n"
            L"「ドキュメント」部の「Hardware」の値が「Yamaha-2149」\r\n"
            L"である曲に対して有効なようです。\r\n"
            L"dump にすると音が鳴らなくなるようです。\r\n"
            L""
            },//help
        {KPI_CFG_TYPE_INT, SEC_GENERAL, KEY_YM_FILTER, L"YM-2149 filter",
            SZ_YM_FILTER_DEFAULT, NULL, NULL, //default/min/max
            L"0\t1\t2\t3\t4\t5", //list
            L"2-poles\tmixed\t1-pole\tboxcar\tnone\tdacout",//listdesc
            L"0: 2-poles\r\n"
            L"1: mixed\r\n"
            L"2: 1-pole\r\n"
            L"3: boxcar\r\n"
            L"4: none\r\n"
            L"5: dacout\r\n"
            L"\r\n"
            L"「YM-2149 engine」が pulse のときに有効です。\r\n"
            L"\r\n"
            L"「ドキュメント」部の「Hardware」の値が「Yamaha-2149」\r\n"
            L"である曲に対して有効なようです。\r\n"
            L""
            },//help
        {KPI_CFG_TYPE_INT, SEC_GENERAL, KEY_YM_VOLMODEL, L"YM-2149 volume model",
            SZ_YM_VOLMODEL_DEFAULT, NULL, NULL, //default/min/max
            L"0\t1", //list
            L"atari\tlinear",//listdesc
            L"0: atari\r\n"
            L"1: linear\r\n"
            L"\r\n"
            L"「ドキュメント」部の「Hardware」の値が「Yamaha-2149」\r\n"
            L"である曲に対して有効なようです。\r\n"
            L""
            },//help
        {KPI_CFG_TYPE_INT, SEC_GENERAL, KEY_AGA_BLEND, L"left/right voices blending factor",
            SZ_AGA_BLEND_DEFAULT, L"0", L"255", //default/min/max
            L"0\t20\t40\t60\t80\t100\t120\t128\t140\t160\t180\t200\t220\t240\t255", //list
            NULL, //listdesc
            L"「ドキュメント」部の「Hardware」の値が「Amiga/Paula」\r\n"
            L"である曲に対して有効なようです。\r\n"
            L""
            },//help
        {KPI_CFG_TYPE_BOOL, SEC_GENERAL, KEY_AGA_FILTER, L"paula resample filter",
            SZ_AGA_FILTER_DEFAULT, NULL, NULL, //default/min/max
            NULL, //list
            NULL, //listdesc
            L"「ドキュメント」部の「Hardware」の値が「Amiga/Paula」\r\n"
            L"である曲に対して有効なようです。\r\n"
            L""
            },//help
        {KPI_CFG_TYPE_INT, SEC_GENERAL, KEY_AGA_CLOCK, L"paula clock",
            SZ_AGA_CLOCK_DEFAULT, NULL, NULL, //default/min/max
            L"0\t1", //list
            L"pal\tntsc", //listdesc
            L"0: pal\r\n"
            L"1: ntsc\r\n"
            L"\r\n"
            L"「ドキュメント」部の「Hardware」の値が「Amiga/Paula」\r\n"
            L"である曲に対して有効なようです。\r\n"
            L""
            },//help
       {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
    };
    for(int i = 0; sec[i].cszSection; i++){
        pEnumerator->EnumSection(&sec[i]);
    }
    for(int i = 0; key[i].cszSection; i++){
        pEnumerator->EnumKey(&key[i]);
    }
    return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
DWORD __fastcall kbsc68_ApplyConfig(IKpiConfig *pConfig,
                               const wchar_t *cszSection,//セクション名
                               const wchar_t *cszKey,    //キー名
                               INT64  nValue, //変更後の値(BOOL/INT の場合)
                               double dValue, //変更後の値(FLOAT の場合)
                               const wchar_t *cszValue)////変更後の値(文字列)
{
    pConfig->SetStr(cszSection, cszKey, cszValue);
    if(wcscmp(cszSection, SEC_GENERAL) == 0){
        if(wcscmp(cszSection, KEY_SAMPLERATE) == 0 ||
           wcscmp(cszSection, KEY_ASID) == 0){
        //ファイルの開き直しで反映可能
            return KPI_CFGRET_RELOAD_DATA;
        }
        return KPI_CFGRET_RELOAD_KPI;//プラグインの再ロードが必要
    }
/*
    KPI_CFGRET_OK,          //設定は即座に反映される
    KPI_CFGRET_NOTIFY,      //デコーダインスタンス等への変更通知が必要(IKpiXXX::Update()が呼ばれたら反映)
    KPI_CFGRET_RELOAD_DATA, //データの再ロードが必要(次にIKpiXXXModule::Open()が呼ばれた分から反映)
    KPI_CFGRET_RELOAD_KPI,  //プラグインの再ロードが必要
    KPI_CFGRET_REBOOT_PLAYER,//プレイヤー本体の再起動が必要(特別な事情がない限り
                             //RELOAD_KPI で足りる筈だが)
    KPI_CFGRET_REBOOT_OS,    //OS の再起動が必要
    KPI_CFGRET_UNKNOWN = (DWORD)-1
                             //不明(外部プログラムを呼び出す等、設定関係の依存
                             //コードの詳細が分からない等)
*/
    return KPI_CFGRET_OK;
}
/////////////////////////////////////////////////////////////////////////////
void __fastcall kbsc68_GetSettings(IKpiConfig *pConfig, kbsc68_Settings *pSettings)
{
    pSettings->nSampleRate = pConfig->GetInt(SEC_GENERAL, KEY_SAMPLERATE, SAMPLERATE_DEFAULT);
    pSettings->nASID = pConfig->GetInt(SEC_GENERAL, KEY_ASID, ASID_DEFAULT);
    pSettings->nYMEngine = pConfig->GetInt(SEC_GENERAL, KEY_YM_ENGINE, YM_ENGINE_DEFAULT);
    pSettings->nYMFilter = pConfig->GetInt(SEC_GENERAL, KEY_YM_FILTER, YM_FILTER_DEFAULT);
    pSettings->nYMVolModel = pConfig->GetInt(SEC_GENERAL, KEY_YM_VOLMODEL, YM_VOLMODEL_DEFAULT);
    pSettings->nAmigaBlend = pConfig->GetInt(SEC_GENERAL, KEY_AGA_BLEND, AGA_BLEND_DEFAULT);
    pSettings->nAmigaFilter = pConfig->GetInt(SEC_GENERAL, KEY_AGA_FILTER, AGA_FILTER_DEFAULT) != 0;
    pSettings->nAmigaClock = pConfig->GetInt(SEC_GENERAL, KEY_AGA_CLOCK, AGA_CLOCK_DEFAULT) != 0;

    //範囲チェック
    switch(pSettings->nSampleRate){
    case 44100: case 48000: case 88200: case 96000:
    case -44100: case -48000: case -88200: case -96000:break;
    default: pSettings->nSampleRate = 44100;break;
    }
    switch (pSettings->nASID) {
    case 0: case 1: case 2: break;
    default: pSettings->nASID = ASID_DEFAULT; break;
    }
    switch(pSettings->nYMEngine){
    case 0: case 1: case 2: break;
    default: pSettings->nYMEngine = YM_ENGINE_DEFAULT;break;
    }
    if(pSettings->nYMFilter < 0){
        pSettings->nYMFilter = 0;
    }
    else if(pSettings->nYMFilter > 5){
        pSettings->nYMFilter = 0;
    }
    switch(pSettings->nYMVolModel){
        case 0: case 1: break;
        default: pSettings->nYMVolModel = 0;break;
    }
    if(pSettings->nAmigaBlend < 0 || pSettings->nAmigaBlend > 255){
        pSettings->nAmigaBlend = AGA_BLEND_DEFAULT;
    }
    switch(pSettings->nAmigaClock){
        case 0: case 1: break;
        default : pSettings->nAmigaClock = AGA_CLOCK_DEFAULT;break;
    }
}
/////////////////////////////////////////////////////////////////////////////
