
#include "stdafx.h"
#include "Globals.h"
#include "Config.h"
#include "BKMessageBox.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif


static const BK_MODEL_PARAMETERS g_mstrConfigBKModelParameters[] =
{
	{ _T("BK-0010-01"),          _T("БК0010-01"),                     MSF_CONF_BK1001,        DEV_FDD_NONE },
	{ _T("BK-0010-01_MSTD"),     _T("БК0010-01 + блок Фокал-МСТД"),   MSF_CONF_BK1001_MSTD,   DEV_FDD_NONE },
	{ _T("BK-0010-01_EXT32RAM"), _T("БК0010-01 + доп. 32кб ОЗУ"),     MSF_CONF_BK1001_EXT32,  DEV_FDD_NONE },
	{ _T("BK-0010-01_FDD"),      _T("БК0010-01 + стандартный КНГМД"), MSF_CONF_BK1001_FDD,    DEV_FDD_STD },
	{ _T("BK-0010-01_A16M"),     _T("БК0010-01 + контроллер A16M"),   MSF_CONF_BK1001_FDD,    DEV_FDD_A16M },
	{ _T("BK-0010-01_SMK512"),   _T("БК0010-01 + контроллер SMK512"), MSF_CONF_BK1001_FDD,    DEV_FDD_SMK512 },
	{ _T("BK-0010-01_SAMARA"),   _T("БК0010-01 + контроллер Samara"), MSF_CONF_BK1001_FDD,    DEV_FDD_SAMARA },
	{ _T("BK-0011"),             _T("БК0011 + МСТД"),                 MSF_CONF_BK11,          DEV_FDD_NONE },
	{ _T("BK-0011_FDD"),         _T("БК0011 + стандартный КНГМД"),    MSF_CONF_BK11_FDD,      DEV_FDD_STD },
	{ _T("BK-0011_A16M"),        _T("БК0011 + контроллер A16M"),      MSF_CONF_BK11_FDD,      DEV_FDD_A16M }, //невозможная конфигурация, т.к. А16М использует монитор БК11М
	{ _T("BK-0011_SMK512"),      _T("БК0011 + контроллер SMK512"),    MSF_CONF_BK11_FDD,      DEV_FDD_SMK512 }, //невозможная конфигурация, т.к. СМК 512 использует монитор БК11М
	{ _T("BK-0011_SAMARA"),      _T("БК0011 + контроллер Samara"),    MSF_CONF_BK11_FDD,      DEV_FDD_SAMARA },
	{ _T("BK-0011M"),            _T("БК0011М + МСТД"),                MSF_CONF_BK11M,         DEV_FDD_NONE },
	{ _T("BK-0011M_FDD"),        _T("БК0011М + стандартный КНГМД"),   MSF_CONF_BK11M_FDD,     DEV_FDD_STD },
	{ _T("BK-0011M_A16M"),       _T("БК0011М + контроллер A16M"),     MSF_CONF_BK11M_FDD,     DEV_FDD_A16M },
	{ _T("BK-0011M_SMK512"),     _T("БК0011М + контроллер SMK512"),   MSF_CONF_BK11M_FDD,     DEV_FDD_SMK512 },
	{ _T("BK-0011M_SAMARA"),     _T("БК0011М + контроллер Samara"),   MSF_CONF_BK11M_FDD,     DEV_FDD_SAMARA }
};

CConfig g_Config; //глобально доступный конфиг.


CConfig::CConfig()
{
	m_BKFDDModel = DEV_FDD_NONE;
	m_nSoundSampleRate = 44100;
	/*
	 Получение версии виндовса.
	 Выход: TRUE - версию получить удалось,
	        FALSE - версию получить не удалось по каким-то причинам

	Если dwMajor < 6 то это winxp или хуже того, вин 2000 какой-нибудь
	в зависимости от этого надо выбирать разные рендеры осциллографа и экрана.
	 */
	BOOL bRet = FALSE;
	//Пытаемся вызвать GetVersionEx используя структуру OSVERSIONINFOEX.
	//В случае ошибки пытаемся проделать тоже самое со структурой OSVERSIONINFO.
	ZeroMemory(&m_osvi, sizeof(OSVERSIONINFOEX));
	m_osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

	if (!(bRet = GetVersionEx(reinterpret_cast<OSVERSIONINFO *>(&m_osvi))))
	{
		// Если OSVERSIONINFOEX не работает, то используем OSVERSIONINFO.
		m_osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
		bRet = GetVersionEx(reinterpret_cast<OSVERSIONINFO *>(&m_osvi));
	}
}

CConfig::~CConfig()
{
	UnInitConfig();
}

//инициализация конфига и всяких переменных, типа пути к проге
void CConfig::InitConfig(const CString &strIniName)
{
	m_strCurrentPath = _GetCurrentPath();
	m_strIniFilePath = m_strCurrentPath + strIniName;
	iniFile.SetIniFileName(m_strIniFilePath);
	CFile file;

	if (file.Open(m_strIniFilePath, CFile::modeRead | CFile::shareDenyWrite))
	{
		// если файл открылся, значит всё в порядке, он существует
		file.Close();
	}
	else
	{
		// иначе - создадим конфиг по умолчанию
		DefaultConfig();
	}

	LoadConfig();
}

void CConfig::UnInitConfig()
{
	SaveConfig();
	iniFile.Clear();
}

const CString &CConfig::GetCurrentPath()
{
	if (m_strCurrentPath.IsEmpty())
	{
		m_strCurrentPath = _GetCurrentPath();
	}

	return m_strCurrentPath;
}

CString &CConfig::NormalizePath(CString &strPath)
{
	if (!strPath.IsEmpty())
	{
		strPath.TrimRight(_T('\\'));
		strPath += _T('\\');
	}

	return strPath;
}

CString CConfig::_GetCurrentPath()
{
	TCHAR pDrive[_MAX_DIR] = { 0 };
	TCHAR pPath[_MAX_PATH] = { 0 };
	TCHAR pModuleName[_MAX_PATH] = { 0 };
	::GetModuleFileName(AfxGetInstanceHandle(), pModuleName, _MAX_PATH);
	_tsplitpath_s(pModuleName, pDrive, _MAX_DIR, pPath, _MAX_PATH, nullptr, 0, nullptr, 0);
	return NormalizePath(CString(pDrive).Trim() + CString(pPath).Trim());
}

CString CConfig::GetFilePath(const CString &strPath)
{
	TCHAR pDrive[_MAX_DIR] = { 0 };
	TCHAR pPath[_MAX_PATH] = { 0 };
	_tsplitpath_s(strPath, pDrive, _MAX_DIR, pPath, _MAX_PATH, nullptr, 0, nullptr, 0);
	return NormalizePath(CString(pDrive).Trim() + CString(pPath).Trim());
}

CString CConfig::GetFileTitle(const CString &strPath)
{
	TCHAR pName[_MAX_FNAME] = { 0 };
	_tsplitpath_s(strPath, nullptr, 0, nullptr, 0, pName, _MAX_FNAME, nullptr, 0);
	return CString(pName).Trim();
}

CString CConfig::GetFileName(const CString &strPath)
{
	TCHAR pName[_MAX_FNAME] = { 0 };
	TCHAR pExt[_MAX_EXT] = { 0 };
	_tsplitpath_s(strPath, nullptr, 0, nullptr, 0, pName, _MAX_FNAME, pExt, _MAX_EXT);
	return CString(pName).Trim() + CString(pExt).Trim();
}

CString CConfig::GetFileExt(const CString &strPath)
{
	TCHAR pExt[_MAX_EXT] = { 0 };
	_tsplitpath_s(strPath, nullptr, 0, nullptr, 0, nullptr, 0, pExt, _MAX_EXT);
	return CString(pExt).Trim();
}

//статические переменные и массивы переменных
//Rom модули
CString CConfig::m_strBK10_017_Monitor,
        CConfig::m_strBK10_018_Focal,
        CConfig::m_strBK10_019_MSTD,
        CConfig::m_strBK10_106_basic1,
        CConfig::m_strBK10_107_basic2,
        CConfig::m_strBK10_108_basic3,
        CConfig::m_strBK11_201_bos,
        CConfig::m_strBK11_202_ext,
        CConfig::m_strBK11_203_mstd,
        CConfig::m_strBK11_198_basic1,
        CConfig::m_strBK11_199_basic2,
        CConfig::m_strBK11_200_basic3,
        CConfig::m_strBK11m_324_bos,
        CConfig::m_strBK11m_325_ext,
        CConfig::m_strBK11m_330_mstd,
        CConfig::m_strBK11m_327_basic1,
        CConfig::m_strBK11m_328_basic2,
        CConfig::m_strBK11m_329_basic3,
        CConfig::m_strFDD_Std,
        CConfig::m_strFDD_Std253,
        CConfig::m_strFDD_A16M,
        CConfig::m_strFDD_SMK512,
        CConfig::m_strFDD_Samara,
        CConfig::m_strBK11Pg121,
        CConfig::m_strBK11Pg122,
        CConfig::m_strBK11Pg131,
        CConfig::m_strBK11Pg132;
//Директории
CString CConfig::m_strBinPath,
        CConfig::m_strToolsPath,
        CConfig::m_strMemPath,
        CConfig::m_strSavesPath,
        CConfig::m_strTapePath,
        CConfig::m_strScriptsPath,
        CConfig::m_strROMPath,
        CConfig::m_strIMGPath,
        CConfig::m_strScreenShotsPath;


confStringParam CConfig::m_romModules[] =
{
	{ IDS_INI_BK10_RE2_017_MONITOR, &m_strBK10_017_Monitor, _T("bk10_017_mon.rom")        },
	{ IDS_INI_BK10_RE2_018_FOCAL,   &m_strBK10_018_Focal,   _T("bk10_018_focal.rom")      },
	{ IDS_INI_BK10_RE2_019_MSTD,    &m_strBK10_019_MSTD,    _T("bk10_019_mstd.rom")       },
	{ IDS_INI_BK10_RE2_106_BASIC1,  &m_strBK10_106_basic1,  _T("bk10_106_basic1.rom")     },
	{ IDS_INI_BK10_RE2_107_BASIC2,  &m_strBK10_107_basic2,  _T("bk10_107_basic2.rom")     },
	{ IDS_INI_BK10_RE2_108_BASIC3,  &m_strBK10_108_basic3,  _T("bk10_108_basic3.rom")     },
	{ IDS_INI_BK11_RE2_201_BOS,     &m_strBK11_201_bos,     _T("bk11_201_bos.rom")        },
	{ IDS_INI_BK11_RE2_202_EXT,     &m_strBK11_202_ext,     _T("bk11_202_ext.rom")        },
	{ IDS_INI_BK11_RE2_203_MSTD,    &m_strBK11_203_mstd,    _T("bk11_203_mstd.rom")       },
	{ IDS_INI_BK11_RE2_198_BASIC1,  &m_strBK11_198_basic1,  _T("bk11_198_basic1.rom")     },
	{ IDS_INI_BK11_RE2_199_BASIC2,  &m_strBK11_199_basic2,  _T("bk11_199_basic2.rom")     },
	{ IDS_INI_BK11_RE2_200_BASIC3,  &m_strBK11_200_basic3,  _T("bk11_200_basic3.rom")     },
	{ IDS_INI_BK11M_RE2_324_BOS,    &m_strBK11m_324_bos,    _T("bk11m_324_bos.rom")       },
	{ IDS_INI_BK11M_RE2_325_EXT,    &m_strBK11m_325_ext,    _T("bk11m_325_ext.rom")       },
	{ IDS_INI_BK11M_RE2_330_MSTD,   &m_strBK11m_330_mstd,   _T("bk11m_330_mstd.rom")      },
	{ IDS_INI_BK11M_RE2_327_BASIC1, &m_strBK11m_327_basic1, _T("bk11m_327_basic1.rom")    },
	{ IDS_INI_BK11M_RE2_328_BASIC2, &m_strBK11m_328_basic2, _T("bk11m_328_basic2.rom")    },
	{ IDS_INI_BK11M_RE2_329_BASIC3, &m_strBK11m_329_basic3, _T("bk11m_329_basic3.rom")    },
	{ IDS_INI_FDR,                  &m_strFDD_Std,          _T("DISK_326.rom")            },
	{ IDS_INI_FDR253,               &m_strFDD_Std253,       _T("DISK_253.rom")            },
	{ IDS_INI_FDR_A16M,             &m_strFDD_A16M,         _T("DISK_A16M_v2.41.rom")     },
	{ IDS_INI_FDR_SMK512,           &m_strFDD_SMK512,       _T("DISK_SMK512_v2.05.rom")   },
	{ IDS_INI_FDR_SAMARA,           &m_strFDD_Samara,       _T("DISK_SAMARA_HDD+FIS.rom") },
	{ IDS_INI_BK11_RE_OPT_PG12_1,   &m_strBK11Pg121,        g_strEmptyUnit                },
	{ IDS_INI_BK11_RE_OPT_PG12_2,   &m_strBK11Pg122,        g_strEmptyUnit                },
	{ IDS_INI_BK11_RE_OPT_PG13_1,   &m_strBK11Pg131,        g_strEmptyUnit                },
	{ IDS_INI_BK11_RE_OPT_PG13_2,   &m_strBK11Pg132,        g_strEmptyUnit                },
	{ 0,                            nullptr,                _T("")                        }
};

confStringParam CConfig::m_Directories[] =
{
	{ IDS_INI_PROGRAM_DIRECTORY,    &m_strBinPath,          _T("Bin")         },
	{ IDS_INI_TOOLS_DIRECTORY,      &m_strToolsPath,        _T("Tools")       },
	{ IDS_INI_MEM_DIRECTORY,        &m_strMemPath,          _T("Memory")      },
	{ IDS_INI_SAVES_DIRECTORY,      &m_strSavesPath,        _T("UserSaves")   },
	{ IDS_INI_TAPES_DIRECTORY,      &m_strTapePath,         _T("Tapes")       },
	{ IDS_INI_SCRIPTS_DIRECTORY,    &m_strScriptsPath,      _T("Scripts")     },
	{ IDS_INI_ROM_DIRECTORY,        &m_strROMPath,          _T("ROM")         },
	{ IDS_INI_IMG_DIRECTORY,        &m_strIMGPath,          _T("Img")         },
	{ IDS_INI_SSHOT_DIRECTORY,      &m_strScreenShotsPath,  _T("Screenshots") },
	{ 0,                            nullptr,                _T("") }
};

void CConfig::_intLoadConfig(bool bLoadMain)
{
	// Инициализация Rom модулей, читаем их лишь для того, чтобы проверить наличие
	int id, i = 0;

	while ((id = m_romModules[i].nID) != 0)
	{
		*m_romModules[i++].pstrValue = iniFile.GetValueString(IDS_INI_SECTIONNAME_ROMMODULES, id, _T(""));
	}

	// Инициализация директорий
	i = 0;

	while ((id = m_Directories[i].nID) != 0)
	{
		*m_Directories[i].pstrValue = NormalizePath(GetCurrentPath() + iniFile.GetValueString(IDS_INI_SECTIONNAME_DIRECTORIES, id, m_Directories[i].defValue));
		i++;
	}

	// Инициализация параметров
	if (bLoadMain)
	{
		//      Основные параметры
		m_strBKBoardType = iniFile.GetValueString(IDS_INI_SECTIONNAME_MAIN, IDS_INI_BKMODEL, g_mstrConfigBKModelParameters[CONFIG_BKMODEL_NUMBER_BK_0010_01].strBKModelConfigName);
		m_nScreenshotNumber = iniFile.GetValueInt(IDS_INI_SECTIONNAME_MAIN, IDS_INI_SSHOT_NUM, 1);
		m_nScreenRenderType = iniFile.GetValueInt(IDS_INI_SECTIONNAME_MAIN, IDS_INI_SCRRENDER_TYPE, ((IsWindowsVistaOrGreater()) ? CONF_SCREEN_RENDER_D2D : CONF_SCREEN_RENDER_DIB));

		//проверим на корректность подсунутых нам значений из ini
		if (m_nScreenRenderType < CONF_SCREEN_RENDER_OGL || m_nScreenRenderType > CONF_SCREEN_RENDER_D3D)
		{
			m_nScreenRenderType = CONF_SCREEN_RENDER_D2D;
		}

		if (!IsWindowsVistaOrGreater())
		{
			//если windows xp, то проверим на предмет неподдержиывемых рендеров
			if (m_nScreenRenderType == CONF_SCREEN_RENDER_D2D) //D2D не поддерживается
			{
				m_nScreenRenderType = CONF_SCREEN_RENDER_DIB; //заменяется на DIB
			}
		}

		m_nOscRenderType = iniFile.GetValueInt(IDS_INI_SECTIONNAME_MAIN, IDS_INI_OSCRENDER_TYPE, ((IsWindowsVistaOrGreater()) ? CONF_OSCILL_RENDER_D2D : CONF_OSCILL_RENDER_OGL));

		//проверим на корректность подсунутых нам значений из ini
		if (m_nOscRenderType < CONF_OSCILL_RENDER_OGL || m_nOscRenderType > CONF_OSCILL_RENDER_GDI)
		{
			m_nOscRenderType = CONF_OSCILL_RENDER_D2D;
		}

		if (!IsWindowsVistaOrGreater())
		{
			//если windows xp, то проверим на предмет неподдержиывемых рендеров
			if (m_nOscRenderType == CONF_OSCILL_RENDER_D2D) //D2D не поддерживается
			{
				m_nOscRenderType = CONF_OSCILL_RENDER_OGL; //заменяется на OGL
			}
		}
	}
	//теперь подготовим индивидуальное имя секции
	CString strCustomize = m_strBKBoardType;
	//      Вариативные параметры
	m_nCPURunAddr       = OctStringToWord(iniFile.GetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_PARAMETERS, IDS_INI_CPU_RUN_ADDR, _T("0")));  //если 0, то берётся значение по умолчанию для своей конфигурации
	m_nCPUFrequency     = iniFile.GetValueIntEx(strCustomize, IDS_INI_SECTIONNAME_PARAMETERS, IDS_INI_CPU_FREQUENCY, 0);  //если 0, то берётся значение по умолчанию для своей конфигурации
	m_nRegistersDumpInterval = iniFile.GetValueIntEx(strCustomize, IDS_INI_SECTIONNAME_PARAMETERS, IDS_INI_REGSDUMP_INTERVAL, 0);  //если 0, то выключено
	CString strSoundVal = iniFile.GetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_PARAMETERS, IDS_INI_SOUNDVOLUME, _T("30%"));// Громкость
	m_nSoundVolume      = 0xffff * _tstoi(strSoundVal) / 100;
	// Инициализация опций
	m_bSavesDefault     = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_SAVES_DEFAULT, false);
	m_bSpeaker          = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_SPEAKER, true);
	m_bSpeakerFilter    = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_SPEAKER_FILTHER, true);
	m_bCovox            = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_COVOX, true);
	m_bCovoxFilter      = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_COVOX_FILTHER, true);
	m_bStereoCovox      = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_COVOX_STEREO, false);
	m_bAY8910           = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_AY8910, true);

	if (m_bAY8910) //у сопра приоритет перед ковоксом
	{
		m_bCovox = false;
	}

	m_bAY8910Filter     = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_AY8910_FILTHER, true);
	m_bBKKeyboard       = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_BKKEYBOARD, true);
	m_bJoystick         = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_JOYSTICK, true);
	m_bColorMode        = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_COLOR_MODE, true); //параметры экрана
	m_bAdaptBWMode      = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_BLACK_WHITE, false);
	m_bLuminoforeEmulMode = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_LUMINOFOREMODE, false);
	m_bFullscreenMode   = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_FULL_SCREEN, false);
	m_bPauseCPUAfterStart = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_PAUSE_CPU, false);
	m_bAskForBreak      = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_ASK_FOR_BREAK, false);
	m_bEmulateLoadTape  = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_EMUL_LOAD_TAPE, true);
	m_bEmulateSaveTape  = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_EMUL_SAVE_TAPE, true);
	m_bTapeAutoBeginDetection = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_AUTO_BEG_TAPE, true);
	m_bTapeAutoEnsDetection = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_AUTO_END_TAPE, true);
	m_bShowPerformance  = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_SHOW_PERFORMANCE_STRING, true);
	m_bEmulateFDDIO     = iniFile.GetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_EMULATE_FDDIO, true);
	m_nAdrDump          = OctStringToWord(iniFile.GetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_ADDR_DUMP, _T("0")));
	m_nAdrAsm           = OctStringToWord(iniFile.GetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_ADDR_DISASM, _T("1000")));
	m_nVKBDType         = iniFile.GetValueIntEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_VKBD_TYPE, 0);
	// Инициализация приводов
	m_strDrives[0]      = iniFile.GetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_DRIVES, IDS_INI_DRIVEA, g_strEmptyUnit);
	m_strDrives[1]      = iniFile.GetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_DRIVES, IDS_INI_DRIVEB, g_strEmptyUnit);
	m_strDrives[2]      = iniFile.GetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_DRIVES, IDS_INI_DRIVEC, g_strEmptyUnit);
	m_strDrives[3]      = iniFile.GetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_DRIVES, IDS_INI_DRIVED, g_strEmptyUnit);
	m_strHDDrives[0]    = iniFile.GetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_DRIVES, IDS_INI_HDD0, g_strEmptyUnit);
	m_strHDDrives[1]    = iniFile.GetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_DRIVES, IDS_INI_HDD1, g_strEmptyUnit);
}


/*
В конфиге есть значения только для чтения, которые не будут изменяться
и есть текущие опции, которые как раз будут изменяться.
*/
void CConfig::LoadConfig(bool bLoadMain)
{
	_intLoadConfig(bLoadMain);
}

void CConfig::LoadConfig_FromMemory(BYTE *pBuff, UINT nSize)
{
	iniFile.ReadIniFromMemory(pBuff, nSize);
	_intLoadConfig(true);
}

//сохранять в память надо только main и кастомные секции
ULONGLONG CConfig::SaveConfig_ToMemory(BYTE *pBuff, UINT nSize)
{
	SaveConfig();
	CIni customIni; //новый ини файл.
	CString strSectionName, strCustomSection;
	//в память над сохранить:
	//1. секцию Main
	strSectionName.LoadString(IDS_INI_SECTIONNAME_MAIN);
	customIni.CopySection(&iniFile, strSectionName);
	//2. секцию RomModules.Custom если есть
	strSectionName.LoadString(IDS_INI_SECTIONNAME_ROMMODULES);
	strCustomSection = strSectionName + _T(".") + m_strBKBoardType;
	customIni.CopySection(&iniFile, strCustomSection);
	//3. секцию Parameters.Custom если есть
	strSectionName.LoadString(IDS_INI_SECTIONNAME_PARAMETERS);
	strCustomSection = strSectionName + _T(".") + m_strBKBoardType;
	customIni.CopySection(&iniFile, strCustomSection);
	//4. секцию Options.Custom если есть
	strSectionName.LoadString(IDS_INI_SECTIONNAME_OPTIONS);
	strCustomSection = strSectionName + _T(".") + m_strBKBoardType;
	customIni.CopySection(&iniFile, strCustomSection);
	//5. секцию Drives.Custom если есть
	strSectionName.LoadString(IDS_INI_SECTIONNAME_DRIVES);
	strCustomSection = strSectionName + _T(".") + m_strBKBoardType;
	customIni.CopySection(&iniFile, strCustomSection);
	return customIni.FlushIniToMemory(pBuff, nSize);
}


void CConfig::SaveConfig()
{
	//теперь подготовим индивидуальное имя секции
	CString strCustomize = m_strBKBoardType;
	// Сохранение Rom модулей - только по чтению, их не модифицируем
	int id, i = 0;

	while ((id = m_romModules[i].nID) != 0)
	{
		iniFile.SetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_ROMMODULES, id, *m_romModules[i++].pstrValue);
	}

	// Сохранение директорий - только по чтению, их не модифицируем
	// Сохранение параметров
	//      Основные параметры
	iniFile.SetValueString(IDS_INI_SECTIONNAME_MAIN, IDS_INI_BKMODEL, m_strBKBoardType);
	iniFile.SetValueInt(IDS_INI_SECTIONNAME_MAIN, IDS_INI_SSHOT_NUM, m_nScreenshotNumber);
	iniFile.SetValueInt(IDS_INI_SECTIONNAME_MAIN, IDS_INI_SCRRENDER_TYPE, m_nScreenRenderType);
	iniFile.SetValueInt(IDS_INI_SECTIONNAME_MAIN, IDS_INI_OSCRENDER_TYPE, m_nOscRenderType);
	//      Вариативные параметры
	iniFile.SetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_PARAMETERS, IDS_INI_CPU_RUN_ADDR, WordToOctString(m_nCPURunAddr));
	iniFile.SetValueIntEx(strCustomize, IDS_INI_SECTIONNAME_PARAMETERS, IDS_INI_CPU_FREQUENCY, m_nCPUFrequency);
	iniFile.SetValueIntEx(strCustomize, IDS_INI_SECTIONNAME_PARAMETERS, IDS_INI_REGSDUMP_INTERVAL, m_nRegistersDumpInterval);
	//Сохраняем Громкость
	CString strSoundVal;
	double d = (double)m_nSoundVolume * 100.0 / 0xffff + 0.01;
	strSoundVal.Format(_T("%d%%"), (int)d);
	iniFile.SetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_PARAMETERS, IDS_INI_SOUNDVOLUME, strSoundVal);
	// Сохранение опций
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_SAVES_DEFAULT, m_bSavesDefault);
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_SPEAKER, m_bSpeaker);
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_SPEAKER_FILTHER, m_bSpeakerFilter);
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_COVOX, m_bCovox);
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_COVOX_FILTHER, m_bCovoxFilter);
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_COVOX_STEREO, m_bStereoCovox);
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_AY8910, m_bAY8910);
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_AY8910_FILTHER, m_bAY8910Filter);
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_BKKEYBOARD, m_bBKKeyboard);
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_JOYSTICK, m_bJoystick);
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_COLOR_MODE, m_bColorMode);    //параметры экрана
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_BLACK_WHITE, m_bAdaptBWMode);
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_LUMINOFOREMODE, m_bLuminoforeEmulMode);
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_FULL_SCREEN, m_bFullscreenMode);
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_PAUSE_CPU, m_bPauseCPUAfterStart);
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_ASK_FOR_BREAK, m_bAskForBreak);
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_EMUL_LOAD_TAPE, m_bEmulateLoadTape);
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_EMUL_SAVE_TAPE, m_bEmulateSaveTape);
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_AUTO_BEG_TAPE, m_bTapeAutoBeginDetection);
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_AUTO_END_TAPE, m_bTapeAutoEnsDetection);
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_SHOW_PERFORMANCE_STRING, m_bShowPerformance);
	iniFile.SetValueBoolEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_EMULATE_FDDIO, m_bEmulateFDDIO);
	iniFile.SetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_ADDR_DUMP, WordToOctString(m_nAdrDump));
	iniFile.SetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_ADDR_DISASM, WordToOctString(m_nAdrAsm));
	iniFile.SetValueIntEx(strCustomize, IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_VKBD_TYPE, m_nVKBDType);
	// Сохранение приводов, принудительно в кастомную секцию
	iniFile.SetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_DRIVES, IDS_INI_DRIVEA, m_strDrives[0], true);
	iniFile.SetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_DRIVES, IDS_INI_DRIVEB, m_strDrives[1], true);
	iniFile.SetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_DRIVES, IDS_INI_DRIVEC, m_strDrives[2], true);
	iniFile.SetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_DRIVES, IDS_INI_DRIVED, m_strDrives[3], true);
	iniFile.SetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_DRIVES, IDS_INI_HDD0, m_strHDDrives[0], true);
	iniFile.SetValueStringEx(strCustomize, IDS_INI_SECTIONNAME_DRIVES, IDS_INI_HDD1, m_strHDDrives[1], true);
	iniFile.FlushIni();
	return;
}

void CConfig::DefaultConfig()
{
	//идея следующая.
	//Создадим конфиг со значениями по умолчанию, и сохраним его на диске.
	// Создание Rom модулей
	int id, i = 0;

	while ((id = m_romModules[i].nID) != 0)
	{
		iniFile.SetValueString(IDS_INI_SECTIONNAME_ROMMODULES, id, m_romModules[i].defValue);
		i++;
	}

	// Создание директорий
	i = 0;

	while ((id = m_Directories[i].nID) != 0)
	{
		iniFile.SetValueString(IDS_INI_SECTIONNAME_DIRECTORIES, id, m_Directories[i].defValue);
		i++;
	}

	// Создание параметров
	//      Основные параметры
	iniFile.SetValueString(IDS_INI_SECTIONNAME_MAIN, IDS_INI_BKMODEL, g_mstrConfigBKModelParameters[CONFIG_BKMODEL_NUMBER_BK_0010_01].strBKModelConfigName);
	iniFile.SetValueInt(IDS_INI_SECTIONNAME_MAIN, IDS_INI_SSHOT_NUM, 1);
	iniFile.SetValueInt(IDS_INI_SECTIONNAME_MAIN, IDS_INI_SCRRENDER_TYPE, ((IsWindowsVistaOrGreater()) ? CONF_SCREEN_RENDER_D2D : CONF_SCREEN_RENDER_DIB));
	iniFile.SetValueInt(IDS_INI_SECTIONNAME_MAIN, IDS_INI_OSCRENDER_TYPE, ((IsWindowsVistaOrGreater()) ? CONF_OSCILL_RENDER_D2D : CONF_OSCILL_RENDER_OGL));
	//      Вариативные параметры
	iniFile.SetValueString(IDS_INI_SECTIONNAME_PARAMETERS, IDS_INI_CPU_RUN_ADDR, _T("0"));  //если 0, то берётся значение по умолчанию для своей конфигурации
	iniFile.SetValueInt(IDS_INI_SECTIONNAME_PARAMETERS, IDS_INI_CPU_FREQUENCY, 0);  //если 0, то берётся значение по умолчанию для своей конфигурации
	iniFile.SetValueInt(IDS_INI_SECTIONNAME_PARAMETERS, IDS_INI_REGSDUMP_INTERVAL, 10);
	iniFile.SetValueString(IDS_INI_SECTIONNAME_PARAMETERS, IDS_INI_SOUNDVOLUME, _T("30%")); // Громкость
	// Создание опций
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_SAVES_DEFAULT, false);
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_SPEAKER, true);
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_SPEAKER_FILTHER, true);
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_COVOX, false);
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_COVOX_FILTHER, true);
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_COVOX_STEREO, false);
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_AY8910, true);
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_AY8910_FILTHER, true);
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_BKKEYBOARD, true);
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_JOYSTICK, true);
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_COLOR_MODE, true);    //параметры экрана
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_BLACK_WHITE, true);
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_LUMINOFOREMODE, false);
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_FULL_SCREEN, false);
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_PAUSE_CPU, false);
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_ASK_FOR_BREAK, false);
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_EMUL_LOAD_TAPE, true);
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_EMUL_SAVE_TAPE, true);
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_AUTO_BEG_TAPE, true);
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_AUTO_END_TAPE, true);
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_SHOW_PERFORMANCE_STRING, true);
	iniFile.SetValueBool(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_EMULATE_FDDIO, true);
	iniFile.SetValueString(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_ADDR_DUMP, _T("0"));
	iniFile.SetValueString(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_ADDR_DISASM, _T("1000"));
	iniFile.SetValueInt(IDS_INI_SECTIONNAME_OPTIONS, IDS_INI_VKBD_TYPE, 0);
	// Создание приводов
	iniFile.SetValueString(IDS_INI_SECTIONNAME_DRIVES, IDS_INI_DRIVEA, g_strEmptyUnit);
	iniFile.SetValueString(IDS_INI_SECTIONNAME_DRIVES, IDS_INI_DRIVEB, g_strEmptyUnit);
	iniFile.SetValueString(IDS_INI_SECTIONNAME_DRIVES, IDS_INI_DRIVEC, g_strEmptyUnit);
	iniFile.SetValueString(IDS_INI_SECTIONNAME_DRIVES, IDS_INI_DRIVED, g_strEmptyUnit);
	iniFile.SetValueString(IDS_INI_SECTIONNAME_DRIVES, IDS_INI_HDD0, g_strEmptyUnit);
	iniFile.SetValueString(IDS_INI_SECTIONNAME_DRIVES, IDS_INI_HDD1, g_strEmptyUnit);
	iniFile.FlushIni();
}

bool CConfig::VerifyRoms()
{
	int p = 0;
	CString strPath;
	CString strError;
	CString *pStr;
	CFile file;
	bool bRes = true;

	while ((pStr = m_romModules[p].pstrValue) != nullptr)   //берём очередной параметр
	{
		if (!pStr->IsEmpty()) //если значение параметра есть
		{
			if (*pStr != g_strEmptyUnit) //и это не заглушка
			{
				strPath = m_strROMPath + *pStr; //попробуем открыть этот файл

				if (file.Open(strPath, CFile::modeRead))
				{
					file.Close();
				}
				else
				{
					strError.LoadString(IDS_ERRMSG_NOTROM);
					CBKMessageBox(strError + _T(" \'") + strPath + _T("\'"), MB_OK | MB_ICONSTOP);
					bRes = false;
				}
			}
		}
		else
		{
			//если значения параметра нет, то тоже плохо
			strError.LoadString(IDS_ERRMSG_ROM_NOT_DEFINED);
			strPath.LoadString(m_romModules[p].nID);
			CBKMessageBox(strError + _T(" \'") + strPath + _T("\'"), MB_OK | MB_ICONSTOP);
			bRes = false;
		}

		p++;
	}

	return bRes;
}

//возвращает номер текущей конфигурации.
//выход: если найдено, то номер. если не найдено - то 0 (значение по умолчанию)
//выдавать m_BKConfigurationModelNumber нельзя, т.к. это значение как раз формируется из
//результата этой функции. Вот такая-вот загогулина
CONFIG_BKMODEL_NUMBER CConfig::GetBKModelNumber()
{
	for (int t = 0; t < CONFIG_BKMODEL_NUMBERS_NUMBER; ++t)
	{
		if (g_mstrConfigBKModelParameters[t].strBKModelConfigName == m_strBKBoardType)
		{
			return static_cast<CONFIG_BKMODEL_NUMBER>(t);
		}
	}

	return CONFIG_BKMODEL_NUMBER_BK_0010_01;
}

void CConfig::SetBKModelNumber(CONFIG_BKMODEL_NUMBER n)
{
	m_BKConfigurationModelNumber = n;
	m_strBKBoardType = g_mstrConfigBKModelParameters[n].strBKModelConfigName;
	m_BKBoardModel = g_mstrConfigBKModelParameters[n].nBKModel;
	m_BKFDDModel = g_mstrConfigBKModelParameters[n].nBKFDDModel;
}

CString CConfig::GetHDDriveImgName(int nDrive)
{
	nDrive &= 1;

	if (m_strHDDrives[nDrive].CompareNoCase(g_strEmptyUnit))
	{
		//прочитаем путь заданного привода
		CString strPath = GetFilePath(m_strHDDrives[nDrive]);

		if (strPath.IsEmpty()) //если путь в имени образа отсутствует
		{
			//то возвращаем имя с полным путём к домашней папке
			return m_strIMGPath + m_strHDDrives[nDrive];
		}
	}

	//иначе, возвращаем имя как есть, предполагаем, что там путь верный.
	return m_strHDDrives[nDrive];
}

CString CConfig::GetDriveImgName(int nDrive)
{
	nDrive &= 3;

	if (m_strDrives[nDrive].CompareNoCase(g_strEmptyUnit))
	{
		//прочитаем путь заданного привода
		CString strPath = GetFilePath(m_strDrives[nDrive]);

		if (strPath.IsEmpty()) //если путь в имени образа отсутствует
		{
			//то возвращаем имя с полным путём к домашней папке
			return m_strIMGPath + m_strDrives[nDrive];
		}
	}

	//иначе, возвращаем имя как есть, предполагаем, что там путь верный.
	return m_strDrives[nDrive];
}

void CConfig::SetDriveImgName(int nDrive, const CString &strPathName)
{
	nDrive &= 3;

	if (strPathName.CompareNoCase(g_strEmptyUnit))
	{
		CString strPath = GetFilePath(strPathName); //выделим путь из входного имени

		//если путь совпадает с путем к домашней директории
		if (strPath.CompareNoCase(m_strIMGPath) == 0)
		{
			//то его удалим
			m_strDrives[nDrive & 3] = GetFileName(strPathName);
			return;
		}
	}

	//иначе - сохраним как есть.
	m_strDrives[nDrive & 3] = strPathName;
}
