// SettingsDlg.cpp: файл реализации
//

#include "stdafx.h"
#include "afxdialogex.h"
#include "resource.h"
#include "SettingsDlg.h"
#include <string>

// Диалоговое окно CSettingsDlg

IMPLEMENT_DYNAMIC(CSettingsDlg, CDialogEx)


const LPCTSTR CSettingsDlg::KEY_USELONGBIN = _T("UseLongBinFormat");
const LPCTSTR CSettingsDlg::KEY_FRONTANALYSE = _T("FrontAnalyse");
const LPCTSTR CSettingsDlg::KEY_FRONTALIASING = _T("FrontAliasing");
const LPCTSTR CSettingsDlg::KEY_FRONTLEVELS = _T("FrontLevels");
const LPCTSTR CSettingsDlg::KEY_IGNORECRC = _T("IgnoreCRC");
const LPCTSTR CSettingsDlg::KEY_IGNOREERRORS = _T("IgnoreErrors");
const LPCTSTR CSettingsDlg::KEY_WORKLOG = _T("StoreWorkLog");
const LPCTSTR CSettingsDlg::KEY_TUNESCATTER = _T("TuneScatter");
const LPCTSTR CSettingsDlg::KEY_DELTAIMPULSE = _T("DeltaImpulse");
const LPCTSTR CSettingsDlg::KEY_MULTIFILE = _T("MultiFile");
const LPCTSTR CSettingsDlg::KEY_VALTRUE = _T("Yes");
const LPCTSTR CSettingsDlg::KEY_VALFALSE = _T("No");

CSettingsDlg::CSettingsDlg(CWnd *pParent /*=nullptr*/)
	: CDialogEx(IDD_SETTINGS_DIALOG, pParent)
{
	auto s = std::to_wstring(m_dDeltaImp);
	m_strDeltaImp = s.c_str();
	m_strDeltaImp.TrimRight(_T('0'));
}

CSettingsDlg::~CSettingsDlg()
    = default;

CSettingsDlg g_Settings;

using TOOLTIP_STRUCT = struct
{
	int     nID;
	CString nStr;
};

static const TOOLTIP_STRUCT tt_strc[] =
{
	{ IDC_CHECK_LONG_BIN,       _T("Будут сохраняться файлы в полном формате: адрес загрузки, длина, оригинальное имя и контрольная сумма в конце массива.")},
	{ IDC_CHECK_FRONT_ANALYSE,  _T("Делается анализ не амплитуд, а направление - рост и спад амплитуд, для этого берётся производная от wave функции.")},
	{ IDC_CHECK_FRONT_ALIAS,    _T("НЧ фильтрация производной, для устранения паразитных колебаний. При слишком больших искажениях не поможет, а сделает только хуже.")},
	{ IDC_CHECK_FRONT_LEVELS,   _T("Дополнительный анализ производной амплитудным методом. Изредка помогает, но в большинстве своём - нет.")},
	{ IDC_EDIT_TUNESCATTER,     _T("Фактически, если разность длительностей двух соседних периодов укладывается в это значение - значит считается что это настроечная последовательность, иначе - сбой и поиск заново с места сбоя.")},
	{ IDC_EDIT_DELTAIMP,        _T("Коэффициент разброса длительности импульса.")},
	{ IDC_CHECK_WORKLOG,        _T("Подробный лог работы, который выводится в большое поле в программе, сохраняется в файл для последующего вдумчивого рассмотрения. Полезно для ручной корректировки файла, который нужно во что бы то ни стало восстановить.")},
	{ IDC_CHECK_IGNORECRC,      _T("Сохранять файлы, которые были успешно распознаны, но не совпала КС.")},
	{ IDC_CHECK_IGNOREERRORS,   _T("Полностью игнорировать ошибки распознавания и сохранить как есть то, что распозналось. Это для самых тяжёлых случаев.")},
	{ IDC_CHECK_MULTIFILE,      _T("Считать, что в Wav файле несколько файлов для распознавания, иначе - только один файл, если включить - то будет wav считаться мультифайлом, в котором несколько файлов. Но эта функция может пропускать файлы.")},
	{ IDOK,                     _T("Закрыть окно и сохранить настройки.")},
	{ IDCANCEL,                 _T("Выйти без сохранения настроек.")}
};

void CSettingsDlg::DoDataExchange(CDataExchange *pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Check(pDX, IDC_CHECK_LONG_BIN, m_bUseLongBinFormat);
	DDX_Check(pDX, IDC_CHECK_FRONT_ANALYSE, m_bFrontAnalyse);
	DDX_Check(pDX, IDC_CHECK_FRONT_ALIAS, m_bFrontAliasing);
	DDX_Check(pDX, IDC_CHECK_FRONT_LEVELS, m_bFrontLevels);
	DDX_Text(pDX, IDC_EDIT_TUNESCATTER, m_nTuneImpScatter);
	DDV_MinMaxInt(pDX, m_nTuneImpScatter, 1, 20);
	DDX_Check(pDX, IDC_CHECK_IGNORECRC, m_bIgnoreCRC);
	DDX_Check(pDX, IDC_CHECK_WORKLOG, m_bWorkLog);
	DDX_Text(pDX, IDC_EDIT_DELTAIMP, m_strDeltaImp);
	DDX_Check(pDX, IDC_CHECK_MULTIFILE, m_bMultiFile);
	DDX_Check(pDX, IDC_CHECK_IGNOREERRORS, m_bIgnoreErrors);
}


BOOL CSettingsDlg::PreTranslateMessage(MSG *pMsg)
{
	if (WM_MOUSEFIRST <= pMsg->message && pMsg->message <= WM_MOUSELAST)
	{
		m_tt.RelayEvent(pMsg);
	}

	return CDialogEx::PreTranslateMessage(pMsg);
}

BEGIN_MESSAGE_MAP(CSettingsDlg, CDialogEx)
	ON_BN_CLICKED(IDC_CHECK_FRONT_ANALYSE, &CSettingsDlg::OnBnClickedCheckFrontAnalyse)
END_MESSAGE_MAP()


// Обработчики сообщений CSettingsDlg


BOOL CSettingsDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();
	// создаём объект тултипов
	m_tt.Create(this);
	m_tt.SetMaxTipWidth(256);

	for (const auto &tt : tt_strc)
	{
		m_tt.AddTool(GetDlgItem(tt.nID), tt.nStr.GetString());
	}

	UpdateData(FALSE);
	SetCheckbox();
	return TRUE;  // return TRUE unless you set the focus to a control
	// Исключение: страница свойств OCX должна возвращать значение FALSE
}


void CSettingsDlg::OnOK()
{
	UpdateData(TRUE);
	CString s = m_strDeltaImp;
	s.Replace(_T('.'), _T(','));
	m_dDeltaImp = _tcstod(s, nullptr);
	CDialogEx::OnOK();
}


void CSettingsDlg::OnBnClickedCheckFrontAnalyse()
{
	SetCheckbox();
}


void CSettingsDlg::SetCheckbox()
{
	const auto btn = reinterpret_cast<CButton *>(GetDlgItem(IDC_CHECK_FRONT_ANALYSE));
	const BOOL bCond = (BST_CHECKED == btn->GetCheck());
	GetDlgItem(IDC_CHECK_FRONT_ALIAS)->EnableWindow(bCond);
	GetDlgItem(IDC_CHECK_FRONT_LEVELS)->EnableWindow(bCond);
}

void CSettingsDlg::Init()
{
	LSTATUS lResult = ::RegOpenKeyEx(HKEY_CURRENT_USER, m_strRegKeyName, 0, KEY_ALL_ACCESS, &m_hkeyRegKey);

	if (lResult != ERROR_SUCCESS)
	{
		lResult = ::RegCreateKeyEx(HKEY_CURRENT_USER, m_strRegKeyName, 0, nullptr, 0, KEY_ALL_ACCESS,
		                           nullptr, &m_hkeyRegKey, nullptr);
	}
}

void CSettingsDlg::Done() const
{
	::RegCloseKey(m_hkeyRegKey);
}

bool CSettingsDlg::SaveStringValue(LPCTSTR sName, CString &strValue) const
{
	LSTATUS lResult = ::RegSetValueEx(m_hkeyRegKey, sName, 0, REG_SZ, reinterpret_cast<const BYTE *>(strValue.GetString()),
	                                  (static_cast<unsigned long long>(strValue.GetLength()) + 1) * sizeof(TCHAR));
	return (lResult == ERROR_SUCCESS);
}

bool CSettingsDlg::LoadStringValue(LPCTSTR sName, CString &strValue) const
{
	auto pBuffer = strValue.GetBufferSetLength(_MAX_PATH);
	DWORD dwBufLength = _MAX_PATH * sizeof(TCHAR); // размер буфера в байтах
	memset(pBuffer, 0, dwBufLength);
	DWORD dwType{};
	LSTATUS lResult = ::RegQueryValueEx(m_hkeyRegKey, sName, nullptr, &dwType, reinterpret_cast<LPBYTE>(pBuffer), &dwBufLength);
	strValue.ReleaseBuffer();

	if (lResult == ERROR_SUCCESS && dwType == REG_SZ)
	{
		return true;
	}

	strValue.Empty();
	return false;
}


void CSettingsDlg::ConfigSettings()
{
	const CWinApp *pWinApp = AfxGetApp();
	m_hkeyRegKey = HKEY(INVALID_HANDLE_VALUE);
	m_strRegKeyName = _T("Software\\") + CString(pWinApp->m_pszRegistryKey) + _T("\\") +
	                  CString(pWinApp->m_pszProfileName);
}

void CSettingsDlg::LoadSettings()
{
	Init();
	CString strVal;
	LoadStringValue(KEY_USELONGBIN, strVal);

	if (!strVal.IsEmpty())
	{
		m_bUseLongBinFormat = !(strVal.CompareNoCase(_T("Yes")) && strVal.CompareNoCase(_T("1")));
	}

	LoadStringValue(KEY_FRONTANALYSE, strVal);

	if (!strVal.IsEmpty())
	{
		m_bFrontAnalyse = !(strVal.CompareNoCase(_T("Yes")) && strVal.CompareNoCase(_T("1")));
	}

	LoadStringValue(KEY_FRONTALIASING, strVal);

	if (!strVal.IsEmpty())
	{
		m_bFrontAliasing = !(strVal.CompareNoCase(_T("Yes")) && strVal.CompareNoCase(_T("1")));
	}

	LoadStringValue(KEY_FRONTLEVELS, strVal);

	if (!strVal.IsEmpty())
	{
		m_bFrontLevels = !(strVal.CompareNoCase(_T("Yes")) && strVal.CompareNoCase(_T("1")));
	}

	LoadStringValue(KEY_IGNORECRC, strVal);

	if (!strVal.IsEmpty())
	{
		m_bIgnoreCRC = !(strVal.CompareNoCase(_T("Yes")) && strVal.CompareNoCase(_T("1")));
	}

	LoadStringValue(KEY_IGNOREERRORS, strVal);

	if (!strVal.IsEmpty())
	{
		m_bIgnoreErrors = !(strVal.CompareNoCase(_T("Yes")) && strVal.CompareNoCase(_T("1")));
	}

	LoadStringValue(KEY_WORKLOG, strVal);

	if (!strVal.IsEmpty())
	{
		m_bWorkLog = !(strVal.CompareNoCase(_T("Yes")) && strVal.CompareNoCase(_T("1")));
	}

	LoadStringValue(KEY_MULTIFILE, strVal);

	if (!strVal.IsEmpty())
	{
		m_bMultiFile = !(strVal.CompareNoCase(_T("Yes")) && strVal.CompareNoCase(_T("1")));
	}

	LoadStringValue(KEY_TUNESCATTER, strVal);

	if (!strVal.IsEmpty())
	{
		m_nTuneImpScatter = StrToInt(strVal);
	}

	LoadStringValue(KEY_DELTAIMPULSE, strVal);

	if (!strVal.IsEmpty())
	{
		m_strDeltaImp = strVal;
		strVal.Replace(_T('.'), _T(','));
		m_dDeltaImp = _tcstod(strVal, nullptr);
	}

	Done();
}

void CSettingsDlg::SaveSettings()
{
	Init();
	CString strVal = m_bUseLongBinFormat ? KEY_VALTRUE : KEY_VALFALSE;
	SaveStringValue(KEY_USELONGBIN, strVal);
	strVal = m_bFrontAnalyse ? KEY_VALTRUE : KEY_VALFALSE;
	SaveStringValue(KEY_FRONTANALYSE, strVal);
	strVal = m_bFrontAliasing ? KEY_VALTRUE : KEY_VALFALSE;
	SaveStringValue(KEY_FRONTALIASING, strVal);
	strVal = m_bFrontLevels ? KEY_VALTRUE : KEY_VALFALSE;
	SaveStringValue(KEY_FRONTLEVELS, strVal);
	strVal = m_bIgnoreCRC ? KEY_VALTRUE : KEY_VALFALSE;
	SaveStringValue(KEY_IGNORECRC, strVal);
	strVal = m_bIgnoreErrors ? KEY_VALTRUE : KEY_VALFALSE;
	SaveStringValue(KEY_IGNOREERRORS, strVal);
	strVal = m_bWorkLog ? KEY_VALTRUE : KEY_VALFALSE;
	SaveStringValue(KEY_WORKLOG, strVal);
	strVal = m_bMultiFile ? KEY_VALTRUE : KEY_VALFALSE;
	SaveStringValue(KEY_MULTIFILE, strVal);
	strVal.Format(_T("%d"), m_nTuneImpScatter);
	SaveStringValue(KEY_TUNESCATTER, strVal);
	SaveStringValue(KEY_DELTAIMPULSE, m_strDeltaImp);
	Done();
}

