<?php declare(strict_types = 0);
/*
** Copyright (C) 2001-2025 Zabbix SIA
**
** This program is free software: you can redistribute it and/or modify it under the terms of
** the GNU Affero General Public License as published by the Free Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
** See the GNU Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public License along with this program.
** If not, see <https://www.gnu.org/licenses/>.
**/


/**
 * @var CView $this
 */
?>

<script type="text/x-jquery-tmpl" id="macro-row-tmpl-inherited">
	<?= (new CRow([
			(new CCol([
				(new CTextAreaFlexible('macros[#{rowNum}][macro]', '', ['add_post_js' => false]))
					->addClass('macro')
					->setWidth(ZBX_TEXTAREA_MACRO_WIDTH)
					->setAttribute('placeholder', '{$MACRO}')
					->disableSpellcheck(),
				new CInput('hidden', 'macros[#{rowNum}][inherited_type]', ZBX_PROPERTY_OWN),
				new CInput('hidden', 'macros[#{rowNum}][discovery_state]',
					CControllerHostMacrosList::DISCOVERY_STATE_MANUAL
				)
			]))->addClass(ZBX_STYLE_TEXTAREA_FLEXIBLE_PARENT),
			(new CCol(
				new CMacroValue(ZBX_MACRO_TYPE_TEXT, 'macros[#{rowNum}]', '', false)
			))->addClass(ZBX_STYLE_TEXTAREA_FLEXIBLE_PARENT),
			(new CCol(
				(new CButton('macros[#{rowNum}][remove]', _('Remove')))
					->addClass(ZBX_STYLE_BTN_LINK)
					->addClass('element-table-remove')
			))->addClass(ZBX_STYLE_NOWRAP),
			[
				new CCol(
					(new CDiv())
						->addClass(ZBX_STYLE_OVERFLOW_ELLIPSIS)
						->setAdaptiveWidth(ZBX_TEXTAREA_MACRO_VALUE_WIDTH)
				),
				new CCol(),
				new CCol(
					(new CDiv())
						->addClass(ZBX_STYLE_OVERFLOW_ELLIPSIS)
						->setAdaptiveWidth(ZBX_TEXTAREA_MACRO_VALUE_WIDTH)
				)
			]
		]))
			->addClass('form_row')
			->toString().
		(new CRow([
			(new CCol(
				(new CTextAreaFlexible('macros[#{rowNum}][description]', '', ['add_post_js' => false]))
					->setMaxlength(DB::getFieldLength('globalmacro', 'description'))
					->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH)
					->setAttribute('placeholder', _('description'))
			))
				->addClass(ZBX_STYLE_TEXTAREA_FLEXIBLE_PARENT)
				->setColSpan(7)
		]))
			->addClass('form_row')
			->toString()
	?>
</script>

<script type="text/x-jquery-tmpl" id="macro-row-tmpl">
	<?= (new CRow([
			(new CCol([
				(new CTextAreaFlexible('macros[#{rowNum}][macro]', '', ['add_post_js' => false]))
					->addClass('macro')
					->setWidth(ZBX_TEXTAREA_MACRO_WIDTH)
					->setAttribute('placeholder', '{$MACRO}')
					->disableSpellcheck(),
				new CInput('hidden', 'macros[#{rowNum}][discovery_state]',
					CControllerHostMacrosList::DISCOVERY_STATE_MANUAL
				)
			]))->addClass(ZBX_STYLE_TEXTAREA_FLEXIBLE_PARENT),
			(new CCol(
				new CMacroValue(ZBX_MACRO_TYPE_TEXT, 'macros[#{rowNum}]', '', false)
			))->addClass(ZBX_STYLE_TEXTAREA_FLEXIBLE_PARENT),
			(new CCol(
				(new CTextAreaFlexible('macros[#{rowNum}][description]', '', ['add_post_js' => false]))
					->setMaxlength(DB::getFieldLength('globalmacro', 'description'))
					->setWidth(ZBX_TEXTAREA_MACRO_VALUE_WIDTH)
					->setAttribute('placeholder', _('description'))
			))->addClass(ZBX_STYLE_TEXTAREA_FLEXIBLE_PARENT),
			(new CCol(
				new CHorList([
					(new CButtonLink(_('Remove')))->addClass('element-table-remove')
				])
			))->addClass(ZBX_STYLE_NOWRAP)
		]))
			->addClass('form_row')
			->toString()
	?>
</script>

<script type="text/x-jquery-tmpl" id="host-interface-row-tmpl">
	<?= (new CPartial('configuration.host.interface.row'))->getOutput() ?>
</script>

<script>
	'use strict';

	window.host_edit = {
		form_name: null,
		form: null,
		macros_initialized: false,
		macros_templateids: null,

		/**
		 * Host form setup.
		 */
		init({form_name, host_interfaces, proxy_groupid, host_is_discovered}) {
			this.form_name = form_name;
			this.form = document.getElementById(form_name);

			this.initial_proxy_groupid = proxy_groupid;

			this.initHostTab(host_interfaces, host_is_discovered);
			this.initMacrosTab();
			this.initInventoryTab();
			this.initEncryptionTab();
		},

		/**
		 * Sets up visible name placeholder synchronization.
		 */
		initHostTab(host_interfaces, host_is_discovered) {
			const host_field = document.getElementById('host');

			['input', 'paste'].forEach((event_type) => {
				host_field.addEventListener(event_type, (e) => this.setVisibleNamePlaceholder(e.target.value));
			});

			this.setVisibleNamePlaceholder(host_field.value);
			this.initHostInterfaces(host_interfaces, host_is_discovered);

			const $groups_ms = $('#groups_');
			const $template_ms = $('#add_templates_');

			$template_ms.on('change', () => {
				$template_ms.multiSelect('setDisabledEntries', this.getAllTemplates());
			});

			$groups_ms.on('change', () => {
				$groups_ms.multiSelect('setDisabledEntries',
					[... this.form.querySelectorAll('[name^="groups["]')].map((input) => input.value)
				);
			});

			document.getElementById('monitored_by').addEventListener('change', () => this.updateMonitoredBy());
			jQuery('#proxy_groupid').on('change', () => this.updateMonitoredBy());

			this.updateMonitoredBy();
		},

		/**
		 * Updates visible name placeholder.
		 *
		 * @param {string} placeholder  Text to display as default host alias.
		 */
		setVisibleNamePlaceholder(placeholder) {
			document.getElementById('visiblename').placeholder = placeholder;
		},

		initHostInterfaces(host_interfaces, host_is_discovered) {
			const host_interface_row_tmpl = document.getElementById('host-interface-row-tmpl').innerHTML;

			window.hostInterfaceManager = new HostInterfaceManager(host_interfaces, host_interface_row_tmpl);

			hostInterfaceManager.render();

			if (host_is_discovered) {
				hostInterfaceManager.makeReadonly();
			}
		},

		updateMonitoredBy() {
			const monitored_by = this.form.querySelector('[name="monitored_by"]:checked').value;

			for (const field of this.form.querySelectorAll('.js-field-proxy')) {
				field.style.display = monitored_by == <?= ZBX_MONITORED_BY_PROXY ?> ? '' : 'none';
			}

			for (const field of this.form.querySelectorAll('.js-field-proxy-group, .js-field-proxy-group-proxy')) {
				field.style.display = monitored_by == <?= ZBX_MONITORED_BY_PROXY_GROUP ?> ? '' : 'none';
			}

			if (monitored_by == <?= ZBX_MONITORED_BY_PROXY_GROUP ?>) {
				const proxy_group = jQuery('#proxy_groupid').multiSelect('getData');
				const proxy_assigned = this.form.querySelector('.js-proxy-assigned');
				const proxy_not_assigned = this.form.querySelector('.js-proxy-not-assigned');

				for (const element of this.form.querySelectorAll('.js-field-proxy-group-proxy')) {
					element.style.display = proxy_group.length ? '' : 'none';
				}

				if (proxy_group.length && proxy_assigned !== null
						&& proxy_group[0]['id'] === this.initial_proxy_groupid) {
					proxy_assigned.style.display = '';
					proxy_not_assigned.style.display = 'none';
				}
				else {
					if (proxy_assigned !== null) {
						proxy_assigned.style.display = 'none';
					}

					proxy_not_assigned.style.display = '';
				}
			}
		},

		unlinkTemplate(button) {
			const linked_templates = button.closest('table');

			button.closest('tr').remove();
			$('#add_templates_').trigger('change');

			if (linked_templates.querySelector('tbody:empty') !== null) {
				linked_templates.remove();
			}
		},

		unlinkAndClearTemplate(button, templateid) {
			const clear_tmpl = document.createElement('input');
			clear_tmpl.type = 'hidden';
			clear_tmpl.name = 'clear_templates[]';
			clear_tmpl.value = templateid;
			button.form.appendChild(clear_tmpl);

			this.unlinkTemplate(button);
		},

		/**
		 * Helper to get linked template IDs as an array.
		 *
		 * @return {array}  Templateids.
		 */
		getLinkedTemplates() {
			const linked_templateids = [];

			this.form.querySelectorAll('[name^="templates["').forEach((input) => {
				linked_templateids.push(input.value);
			});

			return linked_templateids;
		},

		/**
		 * Helper to get added template IDs as an array.
		 *
		 * @return {array}  Templateids.
		 */
		getNewTemplates() {
			const $template_multiselect = $('#add_templates_'),
				templateids = [];

			// Readonly forms don't have multiselect.
			if ($template_multiselect.length) {
				$template_multiselect.multiSelect('getData').forEach(template => {
					templateids.push(template.id);
				});
			}

			return templateids;
		},

		/**
		 * Collects ids of currently active (linked + new) templates.
		 *
		 * @return {array}  Templateids.
		 */
		getAllTemplates() {
			return this.getLinkedTemplates().concat(this.getNewTemplates());
		},

		/**
		 * Set up of macros functionality.
		 */
		initMacrosTab() {
			const $show_inherited_macros = $('input[name="show_inherited_macros"]');

			this.macros_manager = new HostMacrosManager({
				'container': $('#macros_container .table-forms-td-right')
			});

			$('#host-tabs').on('tabscreate tabsactivate', (e, ui) => {
				const panel = (e.type === 'tabscreate') ? ui.panel : ui.newPanel;
				const show_inherited_macros = ($show_inherited_macros.filter(':checked').val() == 1);

				if (panel.attr('id') === 'macros-tab') {
					// Please note that macro initialization must take place once and only when the tab is visible.
					if (e.type === 'tabsactivate') {
						const templateids = this.getAllTemplates();

						// First time always load inherited macros.
						if (this.macros_templateids === null) {
							this.macros_templateids = templateids;

							if (show_inherited_macros) {
								this.macros_manager.load(show_inherited_macros, templateids);
								this.macros_initialized = true;
							}
						}
						// Other times load inherited macros only if templates changed.
						else if (show_inherited_macros && this.macros_templateids.xor(templateids).length > 0) {
							this.macros_templateids = templateids;
							this.macros_manager.load(show_inherited_macros, templateids);
						}
					}

					if (this.macros_initialized) {
						return;
					}

					// Initialize macros.
					this.macros_manager.initMacroTable(show_inherited_macros);

					this.macros_initialized = true;
				}
			});

			$show_inherited_macros.on('change', function() {
				host_edit.macros_manager.load(this.value == 1, host_edit.getAllTemplates());
				host_edit.updateEncryptionFields();
			});
		},

		/**
		 * Set up of inventory functionality.
		 */
		initInventoryTab() {
			document.querySelectorAll('[name=inventory_mode]').forEach((item) => {
				item.addEventListener('change', function () {
					let inventory_fields = document.querySelectorAll('[name^="host_inventory"]'),
						item_links = document.querySelectorAll('.populating_item');

					switch (this.value) {
						case '<?= HOST_INVENTORY_DISABLED ?>':
							inventory_fields.forEach((field) => field.disabled = true);
							item_links.forEach((link) => link.style.display = 'none');
							break;

						case '<?= HOST_INVENTORY_MANUAL ?>':
							inventory_fields.forEach((field) => field.disabled = false);
							item_links.forEach((link) => link.style.display = 'none');
							break;

						case '<?= HOST_INVENTORY_AUTOMATIC ?>':
							inventory_fields.forEach((field) =>
								field.disabled = field.classList.contains('linked_to_item')
							);
							item_links.forEach((link) => link.style.display = '');
							break;
					}
				})
			});
		},

		/**
		 * Set up of encryption functionality.
		 */
		initEncryptionTab() {
			document.querySelectorAll('[name=tls_connect], [name^=tls_in_]').forEach((field) => {
				field.addEventListener('change', () => this.updateEncryptionFields());
			});

			if (document.querySelector('#change_psk')) {
				document.querySelector('#change_psk').addEventListener('click', () => {
					document.querySelector('#change_psk').closest('div').remove();
					document.querySelector('[for="change_psk"]').remove();
					this.updateEncryptionFields();
				});
			}

			this.updateEncryptionFields();
		},


		/**
		 * Propagate changes of selected encryption type to related inputs.
		 */
		updateEncryptionFields() {
			let selected_connection = document.querySelector('[name="tls_connect"]:checked').value,
				use_psk = (document.querySelector('[name="tls_in_psk"]').checked
					|| selected_connection == <?= HOST_ENCRYPTION_PSK ?>),
				use_cert = (document.querySelector('[name="tls_in_cert"]').checked
					|| selected_connection == <?= HOST_ENCRYPTION_CERTIFICATE ?>);

			// If PSK is selected or checked.
			if (document.querySelector('#change_psk')) {
				document.querySelector('#change_psk').closest('div').style.display = use_psk ? '' : 'none';
				document.querySelector('[for="change_psk"]').style.display = use_psk ? '' : 'none';

				// As long as button is there, other PSK fields must be hidden.
				use_psk = false;
			}
			document.querySelector('#tls_psk_identity').closest('div').style.display = use_psk ? '' : 'none';
			document.querySelector('[for="tls_psk_identity"]').style.display = use_psk ? '' : 'none';
			document.querySelector('#tls_psk').closest('div').style.display = use_psk ? '' : 'none';
			document.querySelector('[for="tls_psk"]').style.display = use_psk ? '' : 'none';

			// If certificate is selected or checked.
			document.querySelector('#tls_issuer').closest('div').style.display = use_cert ? '' : 'none';
			document.querySelector('[for="tls_issuer"]').style.display = use_cert ? '' : 'none';
			document.querySelector('#tls_subject').closest('div').style.display = use_cert ? '' : 'none';
			document.querySelector('[for="tls_subject"]').style.display = use_cert ? '' : 'none';

			// Update tls_accept.
			let tls_accept = 0x00;

			if (document.querySelector('[name="tls_in_none"]').checked) {
				tls_accept |= <?= HOST_ENCRYPTION_NONE ?>;
			}

			if (document.querySelector('[name="tls_in_psk"]').checked) {
				tls_accept |= <?= HOST_ENCRYPTION_PSK ?>;
			}

			if (document.querySelector('[name="tls_in_cert"]').checked) {
				tls_accept |= <?= HOST_ENCRYPTION_CERTIFICATE ?>;
			}

			document.getElementById('tls_accept').value = tls_accept;
		},

		/**
		 * Normalize field values.
		 *
		 * @param {Object}  fields    Fields from host form.
		 * @param {boolean} is_clone  Submit fields for clone instead of update.
		 *
		 * @return {Object}  Processed fields from host form.
		 */
		preprocessFormFields(fields, is_clone) {
			this.trimFields(fields);
			fields.status = fields.status || <?= HOST_STATUS_NOT_MONITORED ?>;

			if (document.querySelector('#change_psk')) {
				delete fields.tls_psk_identity;
				delete fields.tls_psk;
			}

			if ('tags' in fields) {
				for (const key in fields.tags) {
					const tag = fields.tags[key];

					if (tag.automatic == <?= ZBX_TAG_AUTOMATIC ?> && !is_clone) {
						delete fields.tags[key];
					}
					else {
						delete tag.automatic;
					}
				}
			}

			return fields;
		},

		trimFields(fields) {
			const fields_to_trim = ['host', 'visiblename', 'description', 'ipmi_username', 'ipmi_password',
				'tls_subject', 'tls_issuer', 'tls_psk_identity', 'tls_psk'];
			for (const field of fields_to_trim) {
				if (field in fields) {
					fields[field] = fields[field].trim();
				}
			}

			if ('interfaces' in fields) {
				for (const key in fields.interfaces) {
					const host_interface = fields.interfaces[key];
					host_interface.ip = host_interface.ip.trim();
					host_interface.dns = host_interface.dns.trim();
					host_interface.port = host_interface.port.trim();

					if ('details' in host_interface) {
						const details = host_interface.details;
						details.authpassphrase = details.authpassphrase.trim();
						details.community = details.community.trim();
						details.contextname = details.contextname.trim();
						details.privpassphrase = details.privpassphrase.trim();
						details.securityname = details.securityname.trim();
					}
				}
			}

			if ('macros' in fields) {
				for (const key in fields.macros) {
					const macro = fields.macros[key];
					macro.macro = macro.macro.trim();

					if ('value' in macro) {
						macro.value = macro.value.trim();
					}
					if ('description' in macro) {
						macro.description = macro.description.trim();
					}
				}
			}

			if ('host_inventory' in fields) {
				for (const key in fields.host_inventory) {
					fields.host_inventory[key] = fields.host_inventory[key].trim();
				}
			}

			if ('tags' in fields) {
				for (const key in fields.tags) {
					const tag = fields.tags[key];
					tag.tag = tag.tag.trim();
					tag.value = tag.value.trim();
				}
			}
		}
	};
</script>
