// emutools\IRPSConfDlg.cpp: файл реализации
//

#include "pch.h"
#include "Config.h"
#include "enumser.h"
#include "IRPSConfDlg.h"
#include "resource.h"       // основные символы


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

IMPLEMENT_DYNAMIC(CIRPSConfDlg, CBaseDialog)

CIRPSConfDlg::CIRPSConfDlg(CWnd *pParent /*=nullptr*/)
	: CBaseDialog(IDD_IRPSCONF_DLG, pParent)
{
}

CIRPSConfDlg::~CIRPSConfDlg()
{
	m_cl.clear();
}

void CIRPSConfDlg::DoDataExchange(CDataExchange *pDX)
{
	CBaseDialog::DoDataExchange(pDX);
}


BEGIN_MESSAGE_MAP(CIRPSConfDlg, CBaseDialog)
END_MESSAGE_MAP()

const std::array<CIRPSConfDlg::ComComboParam, HS_PARAMS_NUMBER> CIRPSConfDlg::m_HSMode =
{
	{
		{ _T("Нет"), 0},
		{ _T("Да"), 1},
		{ _T("Xon/Xoff"), 2},
		{ _T("Аппаратное"), 3}
	}
};

const std::array<CIRPSConfDlg::ComComboParam, static_cast<int>(IRPS_MODE::MODE_NUM)> CIRPSConfDlg::m_TTYModeParam =
{
	{
		{ _T("177560/60"),  static_cast<int>(IRPS_MODE::MODE_V060)},
		{ _T("176560/360"), static_cast<int>(IRPS_MODE::MODE_V360)},
		{ _T("176570/370"), static_cast<int>(IRPS_MODE::MODE_V370)},
		{ _T("177560/360"), static_cast<int>(IRPS_MODE::MODE_SMKC)},
	}
};

const std::array<CIRPSConfDlg::ComComboParam, COM_SPEEDS_NUMBER> CIRPSConfDlg::m_TTYSpeedParam =
{
	{
		{ _T("2400"),  2400},
		{ _T("4800"),  4800},
		{ _T("9600"),  9600},
		{ _T("19200"), 19200},
		{ _T("38400"), 38400},
		{ _T("57600"), 57600},
		{ _T("115200"), 115200},
	}
};

const std::array<CIRPSConfDlg::ComComboParam, BYTESIZE_PARAMS_NUMBER> CIRPSConfDlg::m_TTYByteSize =
{
	{
		{ _T("7 бит"),  7},
		{ _T("8 бит"),  8}
	}
};

const std::array<CIRPSConfDlg::ComComboParam, PARITY_PARAMS_NUMBER> CIRPSConfDlg::m_TTYParity =
{
	{
		{ _T("Нет"),  NOPARITY},
		{ _T("Чёт"),  EVENPARITY},
		{ _T("Нечет"),  ODDPARITY},
		{ _T("Маркер (1)"),  MARKPARITY},
		{ _T("Пробел (0)"),  SPACEPARITY}
	}
};

const std::array<CIRPSConfDlg::ComComboParam, STOPBITS_PARAMS_NUMBER> CIRPSConfDlg::m_TTYStopBits =
{
	{
		{ _T("1"),  ONESTOPBIT},
		{ _T("1.5"),  ONE5STOPBITS},
		{ _T("2"),  TWOSTOPBITS}
	}
};

// добавление имени порта в список
void CIRPSConfDlg::AddInList(CString &str)
{
	bool bFound = false;

	for (auto &pos : m_cl)
	{
		if (pos == str)
		{
			bFound = true;
			break;
		}
	}

	if (!bFound)
	{
		m_cl.emplace_back(str);
	}
}

void CIRPSConfDlg::GetComList()
{
#pragma warning(disable:4996)
	// с использованием WMI возникли проблемы. CoInitializeSecurity проинициализировано где-то кем-то по-другому
	// поэтому оно не работает. обойдёмся другими способами
#ifndef NO_CENUMERATESERIAL_USING_WMI
	bool bUsingWMI = true;
	// Initialize COM (Required by CEnumerateSerial::UsingWMI)
	HRESULT hr = CoInitialize(nullptr);

	if (FAILED(hr))
	{
		TRACE1("Failed to initialize COM, Error:%x\n", hr);
		bUsingWMI = false;
	}

	// Initialize COM security (Required by CEnumerateSerial::UsingWMI)
	hr = CoInitializeSecurity(nullptr, -1, nullptr, nullptr, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE, nullptr);

	if (FAILED(hr))
	{
		if (hr != RPC_E_TOO_LATE)
		{
			TRACE1("Failed to initialize COM security, Error:%08X\n", hr);
			bUsingWMI = false;
		}
	}

#endif
	CEnumerateSerial::CPortsArray ports;
	CEnumerateSerial::CPortAndNamesArray portAndNames;
	CEnumerateSerial::CNamesArray names;
	// заполняем комбо с именами портов
	m_cl.emplace_back(g_ConsoleName);
#ifndef NO_CENUMERATESERIAL_USING_CREATEFILE

	if (CEnumerateSerial::UsingCreateFile(ports))
	{
		CString str;

		for (const auto &port : ports)
		{
			str.Format(_T("COM%u\0"), port);
			AddInList(str);
		}
	}

#endif
#ifndef NO_CENUMERATESERIAL_USING_QUERYDOSDEVICE

	if (CEnumerateSerial::UsingQueryDosDevice(ports))
	{
		CString str;

		for (const auto &port : ports)
		{
			str.Format(_T("COM%u\0"), port);
			AddInList(str);
		}
	}

#endif
#ifndef NO_CENUMERATESERIAL_USING_GETDEFAULTCOMMCONFIG

	if (CEnumerateSerial::UsingGetDefaultCommConfig(ports))
	{
		CString str;

		for (const auto &port : ports)
		{
			str.Format(_T("COM%u\0"), port);
			AddInList(str);
		}
	}

#endif
#ifndef NO_CENUMERATESERIAL_USING_SETUPAPI1

	if (CEnumerateSerial::UsingSetupAPI1(portAndNames))
	{
		CString str;

		for (const auto &port : portAndNames)
		{
			str.Format(_T("COM%u\0"), port.first);
			AddInList(str);
		}
	}

#endif
#ifndef NO_CENUMERATESERIAL_USING_SETUPAPI2

	if (CEnumerateSerial::UsingSetupAPI2(portAndNames))
	{
		CString str;

		for (const auto &port : portAndNames)
		{
			str.Format(_T("COM%u\0"), port.first);
			AddInList(str);
		}
	}

#endif
#ifndef NO_CENUMERATESERIAL_USING_WMI

	if (bUsingWMI)
	{
		hr = CEnumerateSerial::UsingWMI(portAndNames);

		if (SUCCEEDED(hr))
		{
			CString str;

			for (const auto &port : portAndNames)
			{
				str.Format(_T("COM%u\0"), port.first);
				AddInList(str);
			}
		}
	}

#endif
#ifndef NO_CENUMERATESERIAL_USING_COMDB

	if (CEnumerateSerial::UsingComDB(ports))
	{
		CString str;

		for (const auto &port : ports)
		{
			str.Format(_T("COM%u\0"), port);
			AddInList(str);
		}
	}

#endif
#ifndef NO_CENUMERATESERIAL_USING_REGISTRY

	if (CEnumerateSerial::UsingRegistry(names))
	{
		for (const auto &name : names)
		{
			CString str = CString(name.c_str());
			AddInList(str);
		}
	}

#endif
#ifndef NO_CENUMERATESERIAL_USING_GETCOMMPORTS

	if (CEnumerateSerial::UsingGetCommPorts(ports))
	{
		CString str;

		for (const auto &port : ports)
		{
			str.Format(_T("COM%u\0"), port);
			AddInList(str);
		}
	}

#endif
}

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

BOOL CIRPSConfDlg::OnInitDialog()
{
	CBaseDialog::OnInitDialog();
	GetComList();
	const auto comboCOM = reinterpret_cast<CComboBox *>(GetDlgItem(IDC_COMBO_IRPSCONF_MAP_COM_PORT));
	int nDef = 0, n = 0;

	for (auto &pos : m_cl)
	{
		comboCOM->AddString(pos);

		if (pos == g_Config.m_strMapCOMPort)
		{
			nDef = n;
		}

		n++;
	}

	comboCOM->SetCurSel(nDef);
	// заполняем комбо с режимами управления потоком
	const auto comboCOMHS = reinterpret_cast<CComboBox *>(GetDlgItem(IDC_COMBO_IRPSCONF_COMHANDSHAKING));
	nDef = 0;

	for (int i = 0; i < HS_PARAMS_NUMBER; ++i)
	{
		comboCOMHS->AddString(m_HSMode[i].str);

		if (m_HSMode[i].value == g_Config.m_nCOMHSMode)
		{
			nDef = i;
		}
	}

	comboCOMHS->SetCurSel(nDef);
	// заполняем комбо с режимом работы контроллера ИРПС
	const auto comboIRPSMode = reinterpret_cast<CComboBox *>(GetDlgItem(IDC_COMBO_IRPSCONF_TTYMODE));
	nDef = 0;

	for (int i = 0; i < static_cast<int>(IRPS_MODE::MODE_NUM); ++i)
	{
		comboIRPSMode->AddString(m_TTYModeParam[i].str);

		if (m_TTYModeParam[i].value == g_Config.m_nTTYMode)
		{
			nDef = i;
		}
	}

	comboIRPSMode->SetCurSel(nDef);
	// заполняем комбо со скоростями обмена
	const auto comboCOMSpeed = reinterpret_cast<CComboBox *>(GetDlgItem(IDC_COMBO_IRPSCONF_TTYSPEED));
	nDef = 0;

	for (int i = 0; i < COM_SPEEDS_NUMBER; ++i)
	{
		comboCOMSpeed->AddString(m_TTYSpeedParam[i].str);

		if (m_TTYSpeedParam[i].value == g_Config.m_nTTYSpeed)
		{
			nDef = i;
		}
	}

	comboCOMSpeed->SetCurSel(nDef);
	// заполняем комбо с размером байта посылки
	const auto comboByteSize = reinterpret_cast<CComboBox *>(GetDlgItem(IDC_COMBO_IRPSCONF_TTYBYTESIZE));
	nDef = 0;

	for (int i = 0; i < BYTESIZE_PARAMS_NUMBER; ++i)
	{
		comboByteSize->AddString(m_TTYByteSize[i].str);

		if (m_TTYByteSize[i].value == g_Config.m_nTTYByteSize)
		{
			nDef = i;
		}
	}

	comboByteSize->SetCurSel(nDef);
	// заполняем комбо с режимом паритета
	const auto comboParity = reinterpret_cast<CComboBox *>(GetDlgItem(IDC_COMBO_IRPSCONF_TTYPARITY));
	nDef = 0;

	for (int i = 0; i < PARITY_PARAMS_NUMBER; ++i)
	{
		comboParity->AddString(m_TTYParity[i].str);

		if (m_TTYParity[i].value == g_Config.m_nTTYParity)
		{
			nDef = i;
		}
	}

	comboParity->SetCurSel(nDef);
	// заполняем комбо со стоповыми битами
	const auto comboStopBits = reinterpret_cast<CComboBox *>(GetDlgItem(IDC_COMBO_IRPSCONF_TTYSTOPBITS));
	nDef = 0;

	for (int i = 0; i < STOPBITS_PARAMS_NUMBER; ++i)
	{
		comboStopBits->AddString(m_TTYStopBits[i].str);

		if (m_TTYStopBits[i].value == g_Config.m_nTTYStopBits)
		{
			nDef = i;
		}
	}

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


void CIRPSConfDlg::OnOK()
{
	const auto comboCOM = reinterpret_cast<CComboBox *>(GetDlgItem(IDC_COMBO_IRPSCONF_MAP_COM_PORT));
	g_Config.m_strMapCOMPort = m_cl[comboCOM->GetCurSel()];
	const auto comboCOMHS = reinterpret_cast<CComboBox *>(GetDlgItem(IDC_COMBO_IRPSCONF_COMHANDSHAKING));
	g_Config.m_nCOMHSMode = m_HSMode[comboCOMHS->GetCurSel()].value;
	const auto comboIRPSMode = reinterpret_cast<CComboBox *>(GetDlgItem(IDC_COMBO_IRPSCONF_TTYMODE));
	g_Config.m_nTTYMode = m_TTYModeParam[comboIRPSMode->GetCurSel()].value;
	const auto comboCOMSpeed = reinterpret_cast<CComboBox *>(GetDlgItem(IDC_COMBO_IRPSCONF_TTYSPEED));
	g_Config.m_nTTYSpeed = m_TTYSpeedParam[comboCOMSpeed->GetCurSel()].value;
	const auto comboByteSize = reinterpret_cast<CComboBox *>(GetDlgItem(IDC_COMBO_IRPSCONF_TTYBYTESIZE));
	g_Config.m_nTTYByteSize = m_TTYByteSize[comboByteSize->GetCurSel()].value;
	const auto comboParity = reinterpret_cast<CComboBox *>(GetDlgItem(IDC_COMBO_IRPSCONF_TTYPARITY));
	g_Config.m_nTTYParity = m_TTYParity[comboParity->GetCurSel()].value;
	const auto comboStopBits = reinterpret_cast<CComboBox *>(GetDlgItem(IDC_COMBO_IRPSCONF_TTYSTOPBITS));
	g_Config.m_nTTYStopBits = m_TTYStopBits[comboStopBits->GetCurSel()].value;
	CBaseDialog::OnOK();
}


void CIRPSConfDlg::OnCancel()
{
	// TODO: добавьте специализированный код или вызов базового класса
	CBaseDialog::OnCancel();
}
