/**
 * Create XML document to request 'staff' report from the 'PERCo_S20_SDK::IExchangeMain'.
 *
 * Parameters:
 * None.
 *
 * Returns:
 * XML document instance.
 */
ATL::CComPtr<IXMLDOMDocument2> perco_exchange::getStaffRequest() const
{
    ATL::CComPtr<IXMLDOMDocument2> document;
    if (SUCCEEDED(document.CoCreateInstance(CLSID_DOMDocument60, nullptr, CLSCTX_INPROC_SERVER)))
    {
        ATL::CComPtr<IXMLDOMProcessingInstruction> processingInstruction;
        if (SUCCEEDED(document->createProcessingInstruction(
            TEXT("xml"), TEXT("version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\""), &processingInstruction)))
        {
            document->appendChild(processingInstruction, nullptr);
            // Create root <documentrequest> element.
            ATL::CComPtr<IXMLDOMElement> documentRequest;
            if (SUCCEEDED(document->createElement(TEXT("documentrequest"), &documentRequest)))
            {
                ATL::CComPtr<IXMLDOMAttribute> attribute;
                if (SUCCEEDED(document->createAttribute(TEXT("type"), &attribute)))
                {
                    ATL::CComVariant value(TEXT("staff"));
                    if (SUCCEEDED(attribute->put_value(value)) &&
                        SUCCEEDED(documentRequest->setAttributeNode(attribute, nullptr)))
                    {
                        attribute.Release();
                        if (SUCCEEDED(document->createAttribute(TEXT("mode_display"), &attribute)))
                        {
                            value = TEXT("employ_and_dismiss");
                            if (SUCCEEDED(attribute->put_value(value)) &&
                                SUCCEEDED(documentRequest->setAttributeNode(attribute, nullptr)))
                            {
                                if (FAILED(document->appendChild(documentRequest, nullptr)))
                                {
                                    document.Release();
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return document;
}
//-------------------------------------------------------------------------------------------------
ALVR_RESULT Terminate()
{
    g_MouseInput.Terminate();

    g_pFenceD3D11.Release();


    g_pLvrDevice.Release();

    ::DestroyWindow(g_hWindow);

    g_D3DHelper.Terminate();

#if defined(AFFINITY_WORK_AROUND)
    m_pLvrAffinity.Release();
#endif

    g_pFactory = NULL;

    ::FreeLibrary(g_hLiquidVRDLL);

    return ALVR_OK;
}
void CTortoiseProcApp::DoInitializeJumpList(const CString& appid)
{
	ATL::CComPtr<ICustomDestinationList> pcdl;
	HRESULT hr = pcdl.CoCreateInstance(CLSID_DestinationList, NULL, CLSCTX_INPROC_SERVER);
	if (FAILED(hr))
		return;

	hr = pcdl->SetAppID(appid);
	if (FAILED(hr))
		return;

	UINT uMaxSlots;
	ATL::CComPtr<IObjectArray> poaRemoved;
	hr = pcdl->BeginList(&uMaxSlots, IID_PPV_ARGS(&poaRemoved));
	if (FAILED(hr))
		return;

	ATL::CComPtr<IObjectCollection> poc;
	hr = poc.CoCreateInstance(CLSID_EnumerableObjectCollection, NULL, CLSCTX_INPROC_SERVER);
	if (FAILED(hr))
		return;

	CString sTemp = CString(MAKEINTRESOURCE(IDS_MENUSETTINGS));
	CStringUtils::RemoveAccelerators(sTemp);

	ATL::CComPtr<IShellLink> psl;
	hr = CreateShellLink(_T("/command:settings"), (LPCTSTR)sTemp, 20, &psl);
	if (SUCCEEDED(hr)) {
		poc->AddObject(psl);
	}
	sTemp = CString(MAKEINTRESOURCE(IDS_MENUHELP));
	CStringUtils::RemoveAccelerators(sTemp);
	psl.Release(); // Need to release the object before calling operator&()
	hr = CreateShellLink(_T("/command:help"), (LPCTSTR)sTemp, 19, &psl);
	if (SUCCEEDED(hr)) {
		poc->AddObject(psl);
	}

	ATL::CComPtr<IObjectArray> poa;
	hr = poc.QueryInterface(&poa);
	if (SUCCEEDED(hr)) {
		pcdl->AppendCategory((LPCTSTR)CString(MAKEINTRESOURCE(IDS_PROC_TASKS)), poa);
		pcdl->CommitList();
	}
}
/**
* Create XML document to send 'sendcommands' request via the 'PERCo_S20_SDK::IExchangeMain'.
*
* Parameters:
 * >szDoor
 * Path to lock device for the door.
*
* Returns:
* XML document instance.
*/
ATL::CComPtr<IXMLDOMDocument2> perco_exchange::getSendCommandsRequest(_In_ STLADD string_unique_ptr_t&& szDoor) const
{
    ATL::CComPtr<IXMLDOMDocument2> document;
    if (SUCCEEDED(document.CoCreateInstance(CLSID_DOMDocument60, nullptr, CLSCTX_INPROC_SERVER)))
    {
        ATL::CComPtr<IXMLDOMProcessingInstruction> processingInstruction;
        if (SUCCEEDED(document->createProcessingInstruction(
            TEXT("xml"), TEXT("version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\""), &processingInstruction)))
        {
            document->appendChild(processingInstruction, nullptr);
            // Create root <documentrequest> element.
            ATL::CComPtr<IXMLDOMElement> documentRequest;
            if (SUCCEEDED(document->createElement(TEXT("documentrequest"), &documentRequest)))
            {
                ATL::CComPtr<IXMLDOMAttribute> attribute;
                if (SUCCEEDED(document->createAttribute(TEXT("type"), &attribute)))
                {
                    ATL::CComVariant value(TEXT("sendcommands"));
                    if (SUCCEEDED(attribute->put_value(value)) &&
                        SUCCEEDED(documentRequest->setAttributeNode(attribute, nullptr)) &&
                        SUCCEEDED(document->appendChild(documentRequest, nullptr)))
                    {
                        attribute.Release();
                        ATL::CComPtr<IXMLDOMElement> login;
                        if (SUCCEEDED(document->createElement(TEXT("login"), &login)) &&
                            SUCCEEDED(document->createAttribute(TEXT("loginname"), &attribute)))
                        {
                            value = TEXT("login name");
                            if (SUCCEEDED(attribute->put_value(value)) &&
                                SUCCEEDED(login->setAttributeNode(attribute, nullptr)) &&
                                SUCCEEDED(documentRequest->appendChild(login, nullptr)))
                            {
                                ATL::CComPtr<IXMLDOMElement> command;
                                if (SUCCEEDED(document->createElement(TEXT("command"), &command)))
                                {
                                    attribute.Release();
                                    if (SUCCEEDED(document->createAttribute(TEXT("commandnumber"), &attribute)))
                                    {
                                        // cmd #120 is "unlock device reader".
                                        value = "120";
                                        if (SUCCEEDED(attribute->put_value(value)))
                                        {
                                            command->setAttributeNode(attribute, nullptr);
                                        }
                                    }
                                    attribute.Release();
                                    if (SUCCEEDED(document->createAttribute(TEXT("commandname"), &attribute)))
                                    {
//                                        value = L"Открыть (разблокировать) ИУ";
                                        value = L"";
                                        if (SUCCEEDED(attribute->put_value(value)))
                                        {
                                            command->setAttributeNode(attribute, nullptr);
                                        }
                                    }
                                    attribute.Release();
                                    if (SUCCEEDED(document->createAttribute(TEXT("commandpath"), &attribute)))
                                    {
                                        value = szDoor->c_str();
                                        if (SUCCEEDED(attribute->put_value(value)))
                                        {
                                            command->setAttributeNode(attribute, nullptr);
                                        }
                                    }
                                    attribute.Release();
                                    if (SUCCEEDED(document->createAttribute(TEXT("devicename"), &attribute)))
                                    {
//                                        value = L"Считыватель №2";
                                        value = L"";
                                        if (SUCCEEDED(attribute->put_value(value)))
                                        {
                                            command->setAttributeNode(attribute, nullptr);
                                        }
                                    }
                                    attribute.Release();
                                    if (SUCCEEDED(document->createAttribute(TEXT("typename"), &attribute)))
                                    {
//                                        value = L"ReaderTI1_";
                                        value = L"";
                                        if (SUCCEEDED(attribute->put_value(value)))
                                        {
                                            command->setAttributeNode(attribute, nullptr);
                                        }
                                    }
                                    if (SUCCEEDED(login->appendChild(command, nullptr)))
                                    {
                                        ATL::CComPtr<IXMLDOMElement> commandAttributes;
                                        if (SUCCEEDED(
                                            document->createElement(TEXT("command_attributes"), &commandAttributes)) &&
                                            SUCCEEDED(command->appendChild(commandAttributes, nullptr)))
                                        {
                                            ATL::CComPtr<IXMLDOMElement> commandAttribute;
                                            if (SUCCEEDED(
                                                document->createElement(TEXT("command_attribute"), &commandAttribute)))
                                            {
                                                attribute.Release();
                                                if (SUCCEEDED(
                                                    document->createAttribute(TEXT("displayname"), &attribute)))
                                                {
//                                                    value = L"Время разблокировки";
                                                    value = L"";
                                                    if (SUCCEEDED(attribute->put_value(value)))
                                                    {
                                                        commandAttribute->setAttributeNode(attribute, nullptr);
                                                    }
                                                }
                                                attribute.Release();
                                                if (SUCCEEDED(document->createAttribute(TEXT("value"), &attribute)))
                                                {
                                                    value = L"5";
                                                    if (SUCCEEDED(attribute->put_value(value)))
                                                    {
                                                        commandAttribute->setAttributeNode(attribute, nullptr);
                                                    }
                                                }
                                                attribute.Release();
                                                if (SUCCEEDED(
                                                    document->createAttribute(TEXT("rangeindex"), &attribute)))
                                                {
                                                    value = L"1";
                                                    if (SUCCEEDED(attribute->put_value(value)))
                                                    {
                                                        commandAttribute->setAttributeNode(attribute, nullptr);
                                                    }
                                                }
                                                if (FAILED(commandAttributes->appendChild(commandAttribute, nullptr)))
                                                {
                                                    document.Release();
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    szDoor.reset();
    return document;
}
/**
 * Parses XML PERCo response from 'staff' request.
 *
 * Parameters:
 * >pResponse
 * XML response.
 *
 * Returns:
 * Identifiers map.
 */
perco_exchange::ids_t perco_exchange::parseStaffResponse(_In_ IXMLDOMDocument2* pResponse)
{
    ids_t ids;
    ATL::CComVariant value(TEXT("XPath"));
    if (SUCCEEDED(pResponse->setProperty(TEXT("SelectionLanguage"), value)))
    {
        ATL::CComPtr<IXMLDOMElement> documentRequest;
        if (SUCCEEDED(pResponse->get_documentElement(&documentRequest)))
        {
            ATL::CComPtr<IXMLDOMNodeList> staffNodes;
            if (SUCCEEDED(documentRequest->selectNodes(TEXT("staff/staffnode"), &staffNodes)))
            {
                ATL::CComPtr<IXMLDOMNode> staffNode;
                ATL::CComPtr<IXMLDOMNode> identifierNode;
                ATL::CComPtr<IXMLDOMNamedNodeMap> attributeMap;
                while (SUCCEEDED(staffNodes->nextNode(&staffNode)) && staffNode)
                {
                    if (SUCCEEDED(staffNode->selectSingleNode(
                        TEXT("identifiers/identifier/@identifier"), &identifierNode)) &&
                        identifierNode &&
                        SUCCEEDED(identifierNode->get_nodeValue(&value)) &&
                        (VT_BSTR == value.vt))
                    {
                        attributeMap.Release();
                        if (SUCCEEDED(staffNode->get_attributes(&attributeMap)))
                        {
                            ids_t::key_type szKey(value.bstrVal, SysStringLen(value.bstrVal));
                            ids_t::mapped_type data(std::make_unique<data_t>());
                            staffNode.Release();
                            if (SUCCEEDED(attributeMap->getNamedItem(TEXT("last_name"), &staffNode)) &&
                                SUCCEEDED(staffNode->get_nodeValue(&value)) &&
                                (VT_BSTR == value.vt))
                            {
                                data->szLastName =
                                    std::make_unique<STLADD string_type>(value.bstrVal, SysStringLen(value.bstrVal));
                            }
                            staffNode.Release();
                            if (SUCCEEDED(attributeMap->getNamedItem(TEXT("first_name"), &staffNode)) &&
                                SUCCEEDED(staffNode->get_nodeValue(&value)) &&
                                (VT_BSTR == value.vt))
                            {
                                data->szFirstName =
                                    std::make_unique<STLADD string_type>(value.bstrVal, SysStringLen(value.bstrVal));
                            }
                            staffNode.Release();
                            if (SUCCEEDED(attributeMap->getNamedItem(TEXT("middle_name"), &staffNode)) &&
                                SUCCEEDED(staffNode->get_nodeValue(&value)) &&
                                (VT_BSTR == value.vt))
                            {
                                data->szMiddleName =
                                    std::make_unique<STLADD string_type>(value.bstrVal, SysStringLen(value.bstrVal));
                            }
                            staffNode.Release();
                            if (SUCCEEDED(attributeMap->getNamedItem(TEXT("id_internal"), &staffNode)) &&
                                SUCCEEDED(staffNode->get_nodeValue(&value)) &&
                                (VT_BSTR == value.vt))
                            {
                                data->szPERCoId =
                                    std::make_unique<STLADD string_type>(value.bstrVal, SysStringLen(value.bstrVal));
                            }
                            staffNode.Release();
                            if (SUCCEEDED(attributeMap->getNamedItem(TEXT("tabel_id"), &staffNode)) &&
                                SUCCEEDED(staffNode->get_nodeValue(&value)) &&
                                (VT_BSTR == value.vt))
                            {
                                const STLADD regex_type regex(TEXT("[[:blank:]]*([[:graph:]]+)[[:blank:]]*"));
                                STLADD cmatch_results match;
                                if (std::regex_search(
                                    static_cast<const wchar_t*> (value.bstrVal),
                                    static_cast<const wchar_t*> (value.bstrVal + SysStringLen(value.bstrVal)),
                                    match,
                                    regex))
                                {
                                    data->szClockNumber =
                                        std::make_unique<STLADD string_type>(match[1].first, match[1].second);
                                }
                                else
                                {
                                    data->szClockNumber = std::make_unique<STLADD string_type>(0, TEXT('\x00'));
                                }
                            }
                            ids.insert(std::make_pair(szKey, std::move(data)));
                        }
                        identifierNode.Release();
                    }
                    staffNode.Release();
                }
            }
        }
    }
    return ids;
}