let get_set_value_timeout_handle = undefined

class GetSetValue {
	#request_data = []
	#autoupdate = true
	#response_values = []
	#current_request_index = 0
	#on_window = true
	#value_class = ""
	#stop_request = false
	#new_data_wait = false

	
	on_autoupdate_click()
	{
		if (this.#autoupdate)
		{
			this.#autoupdate_off()
		}
		else
		{
			this.#autoupdate_on()
		}
	}

	#autoupdate_off()
	{
		this.#autoupdate = false

		//window.clearTimeout(get_set_value_timeout_handle)
		this.clear_send_query()
		$('.autoupdate').addClass("off")
	}

	#autoupdate_on()
	{
		this.#autoupdate = true

		this.#new_data_wait = false
		this.#set_timeout_handle()
		$('.autoupdate').removeClass("off")
	}

	on_windows_focus()
	{
		this.#on_window = true

		this.#new_data_wait = false
		this.#set_timeout_handle()
	}

	on_windows_blur()
	{
		this.#on_window = false

		this.clear_send_query()
		//window.clearTimeout(get_set_value_timeout_handle)
		//this.#current_request_index = 0
		//this.#stop_request = true
		//this.#new_data_wait = true
	}

	clear_send_query()
	{
		window.clearTimeout(get_set_value_timeout_handle)
		//this.#request_data = []
		
		//console.log('this.#stop_request = true')

		this.#response_values = []

		this.#current_request_index = 0
		this.#stop_request = true
		this.#new_data_wait = true
		//.log('this.#new_data_wait = true')
	}

	set_request_data(data, value)
	{
		this.#new_data_wait = false
		//console.log('this.#new_data_wait = false')

		this.#request_data = data
		this.#value_class = value
	}

	send_query()
	{
		let query
		let j = 0

		window.clearTimeout(get_set_value_timeout_handle)

		if ((this.#request_data.length > 0) && (this.#current_request_index < this.#request_data.length) && (j < configuration.response_lenght()))
		{
			query = '/get_od_data.form?'
			let has_request = false
			for (;;)
			{
				if ((this.#current_request_index >= this.#request_data.length) || (j >= configuration.response_lenght()))
				{
					break;
				}

				//console.log(this.#request_data[this.#current_request_index])
				if (this.#request_data[this.#current_request_index] != null)
				{
					if (this.#request_data[this.#current_request_index].AccessType != null)
					{
						if (this.#request_data[this.#current_request_index].AccessType.includes('r')) //read
						{
							//if (this.#request_data[this.#current_request_index].index != null)
							if ((this.#current_request_index > 0) && (j > 0))
				    		{
				    			query += "&"
				    		}
							has_request = true;
							query += "0x" + this.#request_data[this.#current_request_index].index.replace(":","_")
							j++
						}
					}
				}

				this.#current_request_index++
			}

			if (has_request == false)
			{
				query = ''
			}

			fetch(query)
				.then(response => response.text())
				.then(response_text => {
					//console.log(response_text)
					let responseLines = response_text.split('\n')
					let responseLine = responseLines[0]
					//console.log("responseLine:"+responseLine)
					if ((responseLine.search( />>>ERROR<<</i ) != -1) || (responseLine.search( /!!!ERROR!!!/i ) != -1))
					{
						console.log(`${l100n.localize_string("reload page")}. На запрос: ${query} ответ: ${responseLine}`)
						if (confirm(l100n.localize_string("reload page"))) {
							//window.location.reload()
							this.#autoupdate_off()
						}
			
						//alert(l100n.localize_string("response error"));// + responseLine)
						
					}
			
					
					//console.log('this.#response_values: ' + this.#response_values)
					//console.log('this.#stop_request: ' + this.#stop_request)
			
					if (this.#stop_request || this.#new_data_wait) 
					{			
						this.#current_request_index = 0
			
						if (this.#response_values.length > 0 || this.#new_data_wait) //Испорченные данные (старый запрос)
						{
							//console.log('bad')
			
							this.#response_values = []
							this.#set_timeout_handle()
						}
						else //Новые
						{					
							//console.log('new->')
			
							this.#stop_request = false
							//console.log('this.#stop_request = false')
			
							if (this.#autoupdate && this.#on_window)
							{
								get_set_value_timeout_handle = setTimeout(() => this.send_query(), 500)
							}
						}
					}
					else //Обычные
					{
						//console.log('norm')
						this.#response_values = this.#response_values.concat(responseLine.split('&#&'))
						this.#response_values.pop()
			
						if (this.#current_request_index >= this.#request_data.length)
						{
							//console.log('this.#response_values: ' + this.#response_values)
							//console.log('this.#value_paste')
							this.#value_paste()
			
							this.#current_request_index = 0
							this.#response_values = []
			
							$(document).trigger("get_value_completed")
							//console.log('get_value_completed')
			
							this.#set_timeout_handle()
							//if (this.#autoupdate && this.#on_window)
							//{
							//	this.send_query()
							//}
						}
						else if (this.#request_data != null)
						{
							this.send_query()
						}
					}

				})
				.catch(function(error) {
					console.log(error)
					//this.#current_request_index = 0
					alert(l100n.localize_string("Check device connection..."))
				})
		}
		//console.log(query)
	}

	//if (!response.ok)
		//{
		//	alert('Ошибка загрузки. Статус: ' + response.status)
		//	return
		//}

	#set_timeout_handle()
	{
		if (this.#autoupdate && this.#on_window)
		{
			//console.log(get_set_value_timeout_handle)
			get_set_value_timeout_handle = setTimeout(() => this.send_query(), configuration.queryTimeout())
		}
	}

	get_cell(key, class_type="")
	{
		let form = $('<form>').addClass('apply_form')
		if ((this.#request_data[key] != null) &&
			(this.#request_data[key].DataType != null) &&
			(this.#request_data[key].AccessType != null))
		{
			let index = this.#request_data[key].index.replace(":","_")
			let apply_input = $('<input type="text">')
			let apply_button = $('<div>')//.addClass('empty_div')
			let default_value = $('<div>')

			let template_object
			let template = ""
			let commands

			let label
			let title //hint message
			let without_button = false

			let searchParams = new URLSearchParams(location.search)
			let raw_data = searchParams.get("raw_data")
			if (raw_data === null)
			{
				$.each(configuration.data_type_template().templates, function(template_index_, template_item_)
				{
					if (template_item_.index === index)
					{
						template_object = template_item_
						if (template_item_.template != null)
						{
							template = template_item_.template
							commands = template_item_.commands
						}
						return false //break
					}
				})
			}

			if (template == "")
			{
				apply_input.addClass(this.#request_data[key].DataType);
			}
			else if (template == "password")
			{
				apply_input.attr({'type':'password'})
				label = $('<label style="display:block">')
				label.append($('<input type="checkbox">').addClass('password_checkbox'))
				label.append($('<label>').text(l100n.localize_string("show_password")))
				//form.append(label)
			}
			else if (template == "combobox" || template == "control_mode")
			{
				apply_input = $('<select>')

				if (template_object.add_class == "without_undetermined")
				{
					apply_input.addClass("without_undetermined")
				}
				
				$.each(commands, function(commands_index, command_item)
				{
					var option = $('<option>')
					option.val(command_item.command)
					option.text(command_item.name)
					apply_input.append(option)
				})

				//form.append($('<div>').addClass('combobox_info'));
			}
			else if (template == "one_wire_sensors")
			{
				let selected_input = $('<div>')
				selected_input.addClass('one_wire_selected_input')
				
				form.append(selected_input)
				form.append($('<div>').addClass('empty_block'))

				apply_input = $('<select>')

				$.each(commands, function(commands_index, command_item)
				{					
					var option = $('<option>')
					option.val(command_item.command)
					option.text(command_item.name)
					apply_input.append(option)
				})
				/*sensor_select = $('<select>')
				sensor_select.addClass('sensor_select')
				$.each(commands, function(commands_index, command_item)
				{
					var option = $('<option>')
					option.val(command_item.command)
					option.text(command_item.name)
					apply_input.append(option)
				})
				form.append(sensor_select)

				apply_input.hide()*/
			}
			else if (template == "module_types")
			{
				apply_input = $('<select>')
				apply_input.addClass('need_restart')
				$.each(commands, function(commands_index, command_item)
				{
					if (command_item.command == "13")
					{
						//option.attr('disabled','true')
						return;
					}
					var option = $('<option>')
					option.val(command_item.command)
					option.text(command_item.name);
					apply_input.append(option)
				})
			}
			else if (template == "datetime"  && !class_type.includes("ro"))
			{
				let date_input = $('<input type="text">');
				date_input.attr({"id":"date_input"}).mask('00.00.0000');
				date_input.addClass('datetime');
				date_input.datepicker()
				form.append(date_input);

				apply_input.attr({"id":"time_input"}).mask("99:99:99");
			}
            else if (template == "consumer_heartbeat")
			{
				let hbconsumer_input = $('<input type="text">')
				let node_key = `node_input_${key}`
				let time_key = `hb_time_input_${key}`

				hbconsumer_input.addClass('consumer_heartbeat')
				hbconsumer_input.addClass('consumer_heartbeat_node')
				hbconsumer_input.attr({"id": node_key})
				form.append(hbconsumer_input);

				apply_input.attr({"id": time_key});
			}
			else if (template == "mbtcp_client")
			{
				let table = $('<table>').addClass('mbtcp_client_table')
				/*let header = $(`<tr class="table_header"><td colspan="2">${l100n.localize_string("hl_Line Flags")}</td></tr>`)
				table.append(header)*/

				let close_socket_input = $('<input type="checkbox">').addClass('mbtcp_client')
				table.append(GetSetValue.#get_label_control_tr('mbtcp_client_cs', 'close_socket', close_socket_input))

				let timeout_input = $('<input type="text">').addClass('mbtcp_client')
				table.append(GetSetValue.#get_label_control_tr('mbtcp_client_timeout', 'timeout', timeout_input))

				let port_input = $('<input type="text">').addClass('mbtcp_client').addClass('uint16')
				table.append(GetSetValue.#get_label_control_tr('mbtcp_client_port', 'port', port_input))

				let ip_input = $('<input type="text">').addClass('mbtcp_client')
				table.append(GetSetValue.#get_label_control_tr('mbtcp_client_ip', 'ip', ip_input))

				form.append(table)
				apply_input.hide()
			}
			else if (template == "mbtcp_client_status")
			{
				let table = $('<table>').addClass('mbtcp_client_status_table')

				let connection_status = $('<div>').addClass('mbtcp_client_status').attr('disabled', 'disabled')
				table.append(GetSetValue.#get_label_control_tr('mbtcp_client_status_connection', 'connection_status', connection_status))

				let tls_status = $('<div>').addClass('mbtcp_client_status').attr('disabled', 'disabled')
				table.append(GetSetValue.#get_label_control_tr('mbtcp_client_status_tls', 'tls_status', tls_status))

				//let timeout = $('<input type="checkbox">').addClass('mbtcp_client_status').attr('disabled', 'disabled')
				let timeout = $('<label><span></span></label>').addClass("readonly_cb").addClass('mbtcp_client_status')
				table.append(GetSetValue.#get_label_control_tr('mbtcp_client_status_timeout', 'timeout', timeout))

				let port = $('<div>').addClass('mbtcp_client_status').addClass('uint16').attr('disabled', 'disabled')
				table.append(GetSetValue.#get_label_control_tr('mbtcp_client_status_port', 'port', port))

				let misconfig = $('<div>').addClass('mbtcp_client_status').attr('disabled', 'disabled')
				table.append(GetSetValue.#get_label_control_tr('mbtcp_client_status_misconfig', 'misconfig', misconfig))

				form.append(table)
				apply_input.hide()
			}
            else if (template == "pdo_mapping")
			{
				let index_input = $('<input type="text">')
				let index_key = `index_input_${key}`
				index_input.addClass('pdo_mapping')
				index_input.addClass('pdo_mapping_index')
				
				index_input.attr( {"id": index_key})

				let subi_input = $('<input type="text">')
				let subindex_key = `subindex_input_${key}`
				subi_input.addClass('pdo_mapping')
				subi_input.addClass('pdo_mapping_subindex')
				
				subi_input.attr( {"id": subindex_key})

				form.append(index_input)
				form.append(subi_input)

				let size_key = `size_input_${key}`
				apply_input.attr({"id": size_key})
			}
			else if (template == "pdo_cob_id")
			{
				let enable_input = $('<select>')
				$.each(template_object.enable, function(commands_index_, command_item_)
				{
					let option = $('<option>')
					option.val(command_item_.command)
					option.text(command_item_.name)
					enable_input.append(option)
				})
				let enable_key = `enable_input_${key}`
				enable_input.addClass('pdo_cob_id')
				enable_input.addClass('pdo_cob_id_enable')
				enable_input.attr({"id": enable_key})
				form.append(enable_input)

				let message_input = $('<select>')
				$.each(template_object.messages, function(commands_index_, command_item_)
				{
					let option = $('<option>')
					//console.log(command_item_.command)
					option.val(command_item_.command)
					option.text(command_item_.name)
					if (command_item_.command === "default")
					{
						option.prop( "disabled", true )
					}
					message_input.append(option)					 
				})
				let message_key = `message_input_${key}`
				message_input.addClass('pdo_cob_id')
				message_input.addClass('pdo_cob_id_message')
				message_input.attr( {"id": message_key});			
				form.append(message_input)

				let node_id_key = `node_id_input_${key}`
				apply_input.attr( {"id": node_id_key})
				apply_input.addClass("1-127")

				let error_label = $(`<label>Please enter PDO COB ID message</label>`)
				error_label.attr({"id": `error_label_${key}`})
				error_label.hide()
				form.append(error_label)
			}
			else if (template == "line_flags")
			{
				//let div = $('<div>').append(l100n.localize_string("hl_Line Flags"))
				//form.append(div)
				let table = $('<table>').addClass('line_flags_table')
				
				let header = $(`<tr class="table_header"><td colspan="2">${l100n.localize_string("hl_Line Flags")}</td></tr>`)
				table.append(header)
				let voltage_tr = $('<tr>').addClass('line_flags_voltage_tr')
				let voltage_label = $('<td>').append(l100n.localize_string("hl_voltage_for_line"))
				let voltage_input_td = $('<td>').addClass('line_flags_voltage_td')
				let voltage_input = $('<select>')
				$.each(template_object.voltage, function(commands_index_, command_item_)
				{
					let option = $('<option>')
					option.val(command_item_.command)
					option.text(command_item_.name)
					voltage_input.append(option)
				})
				voltage_input.addClass('line_flags')
				voltage_input.addClass('line_flags_voltage')
				voltage_input_td.append(voltage_input)
				voltage_tr.append(voltage_label).append(voltage_input_td)
				table.append(voltage_tr)

				//form.append(voltage_input)

				let no_nc_tr = $('<tr>').addClass('line_flags_no_nc_tr')
				let no_nc_label = $('<td>').append(l100n.localize_string("hl_no_nc"))
				let no_nc_input_td = $('<td>').addClass('line_flags_no_nc_td')
				//let no_nc_input = $('<input type="checkbox">')
				let no_nc_input = $('<select>')
				$.each(template_object.no_nc, function(commands_index_, command_item_)
				{
					let option = $('<option>')
					option.val(command_item_.command)
					option.text(command_item_.name)
					no_nc_input.append(option)
				})
				no_nc_input.addClass("line_flags_no_nc")
				no_nc_input.addClass('line_flags')
				no_nc_input_td.append(no_nc_input)
				no_nc_tr.append(no_nc_label).append(no_nc_input_td)
				table.append(no_nc_tr)

				let pwm_tr = $('<tr>').addClass('line_flags_pwm_tr')
				let pwm_label = $('<td>').append(l100n.localize_string("hl_pwm"))
				let pwm_input_td = $('<td>').addClass('line_flags_pwm_td')
				//let pwm_input = $('<input type="checkbox">')
				let pwm_input = $('<select>')
				$.each(template_object.pwm, function(commands_index_, command_item_)
				{
					let option = $('<option>')
					option.val(command_item_.command)
					option.text(command_item_.name)
					pwm_input.append(option)
				})
				pwm_input.addClass("line_flags_pwm")
				pwm_input.addClass('line_flags')
				pwm_input_td.append(pwm_input)
				pwm_tr.append(pwm_label).append(pwm_input_td)
				table.append(pwm_tr)
				

				apply_input = $('<input type="checkbox">').hide()
				//apply_input.addClass('line_flags_pwm')
				form.append(table)
			}
			else if (template == "bit_checkboxes")
			{
				//let table = $('<table>').addClass('bit_checkboxes_table')
				//let header = $(`<tr class="table_header"><td colspan="2">${template_object.header}</td></tr>`)
				//table.append(header)

				for (let number = 0; number < template_object.count; number++)
				{
					//let tr = $('<tr>').addClass(`bit_checkboxes_tr`)
					//let label = $('<td>').append(`bit ${number}`)
					//let input_td = $('<td>').addClass(`bit_checkboxes_td`)
					let input = $('<input type="checkbox">')
	
					input.addClass(`bit_checkboxes_ctrl`)
					input.addClass('bit_checkboxes')
					//input_td.append(input)
					//tr.append(label).append(input_td)
					//table.append(tr)
					form.append(input)
					if (template_object.ro)
					{
						input.attr('disabled', 'disabled')
					}
				}
				apply_input = $('<input type="checkbox">').hide()
				
				if (template_object.ro)
				{
					without_button = true
				}
				//form.append(table)
			}
			else if (template == "date")
			{
				apply_input.attr({"id":"date_input"})
			}
			else if (template == "restore_params")
			{
				title = l100n.localize_string("Restore_params_hint")
			}
			else if (template == "mcuf_sensor_select")
			{
				let module_input = $('<select>')
				$.each(template_object.modules, function(commands_index_, command_item_)
				{
					let option = $('<option>')
					option.val(command_item_.command)
					option.text(command_item_.name);
					module_input.append(option)
				})

				apply_input = $('<select>')
				$.each(template_object.sensors, function(commands_index_, command_item_)
				{
					let option = $('<option>')
					option.val(command_item_.command)
					option.text(command_item_.name)
					apply_input.append(option)
				})

				//let module_input = $('<input type="text">')
				module_input.addClass('mcuf_module_select')
				form.append(module_input)
			}
			

			if (class_type.includes("boolean_input"))
			{
				apply_input = $('<label><span></span></label>')
			}
			else if (class_type.includes("boolean_output"))
			{
				apply_input = $('<label><span></span></label>')
			}
			else if (class_type.includes("boolean_alarm"))
			{
				apply_input = $('<label><span></span></label>')
			}
			else if (without_button)
			{
				
			}
			else if (this.#request_data[key].AccessType.includes('ro') || class_type.includes("ro"))//read only
			{
				if (this.#request_data[key].DataType == "bool" || this.#request_data[key].DataType == "boolean_type" || template == "boolean_type")
				{
					apply_input = $('<label><span></span></label>').addClass("readonly_cb")
				}
				else if (template == "datetime")
				{
					template = ""

					let date_input = $('<div>').attr({"tabindex":"0"})
					date_input.attr({"id":"date_show"})
					form.append(date_input)
					form.append('\u00a0\u00a0')
					apply_input = $('<div>').attr({"tabindex":"0"})
					apply_input.attr({"id":"time_show"}).addClass('datetime_show')
				}
				else
				{
					apply_input = $('<div>').attr({"tabindex":"0"});
				}
			}
			else if (this.#request_data[key].AccessType.includes('w')) //write
			{
				if ((this.#request_data[key].DataType == "bool" || this.#request_data[key].DataType == "boolean_type") && (template == ""))
				{
					apply_input = $('<input type="checkbox">').addClass("edit_cb").attr({"index":index})
					apply_button.addClass('empty_div')
				}
				else if (template == "boolean_type")
				{
					apply_input = $('<input type="checkbox">').addClass("edit_cb").attr({"index":index})
					apply_button.addClass('empty_div')
				}
				else
				{
					apply_button = $('<input type="submit">').addClass('item_edit_b')
					apply_button.attr({"index":index})
					apply_button.val(l100n.localize_string("apply_button"))
				}

				apply_input.addClass('item_edit_textbox')
				default_value = $('<label><span></span></label>').addClass("default_value")
				default_value.attr("title", l100n.localize_string('default_value_record_title'))
				default_value.hide()
				if (this.#request_data[key].Save == "Yes")
				{
					default_value.attr({"default_value":this.#request_data[key].DefaultValue})
					default_value.attr({"data_type":this.#request_data[key].DataType})
				}
			}

			if (this.#request_data[key].AccessType.includes('r'))   //read
			{
				apply_input.addClass('value')
			}
		
			if (template_object != null)
			{
				if (template_object.class != null)
				{
					//console.log(template_object.class)
					apply_input.addClass(template_object.class)
				}
			}

			apply_input.addClass(class_type)
			apply_input.addClass(template)
			apply_input.addClass("apply_input")
			apply_input.attr({"tb_index":index})

			form.attr({"index":index})
			//form.attr({"id":index})
			form.append(apply_input)
			form.append(apply_button)
			form.append(default_value)


			if (label !== null)
			{
				form.append(label)
			}
			if (title !== null)
			{
				apply_input.attr('title', title)
			}

			form.validate()
		}
		else
		{
			form.addClass('empty')
		}

		return form
	}

	static checkbox_click(checkbox)
	{
		if ($(checkbox).valid())
		{
			let index_number = $(checkbox).attr('index')
			let new_value = utils.checked2string($(checkbox))

			let query = '/set_od_data.form?'
			query += utils.get_set_od_data_query_unit(index_number, new_value)

			return GetSetValue.#send_set_query(query)
		}
	}

	static combobox_click(combobox)
	{
		$(combobox).find("option[data-category='undefined']:not(:selected)").remove()
	}

	static item_edit_click(button)
	{
		$(button).removeClass('button_edited')
		if ($(button).valid())
		{
			let index_number = $(button).attr('index')
			let form = $(button).parent()
			//let apply_input = $(`[tb_index='${index_number}']`)
			let apply_input = form.children('.apply_input').first();
			let new_value = apply_input.val()
			let additional_query = ''

			if (apply_input.hasClass('pdo_mapping'))
			{
				//let form = apply_input.parent()
				let index_ctrl = form.children(".pdo_mapping_index")
				let subindex_ctrl = form.children(".pdo_mapping_subindex")
				let size_ctrl = apply_input

				let index_input = index_ctrl.val()
				let subindex_input = subindex_ctrl.val()
				let size_input = size_ctrl.val()
				
				let index_raw_val = (parseInt(index_input) & 0xFFFF) * 0x10000
				let subi_raw_val = (parseInt(subindex_input) & 0xFF) * 0x100
				let size_raw_val = (parseInt(size_input) & 0xFF)

				let pdo_mapping = index_raw_val + subi_raw_val + size_raw_val
				new_value = `${pdo_mapping}`

				index_ctrl.removeClass('changed')
				subindex_ctrl.removeClass('changed')
				size_ctrl.removeClass('changed')
			}
			else if (apply_input.hasClass('pdo_cob_id'))
			{
				//let form = apply_input.parent()
				let enable_ctrl = form.children(".pdo_cob_id_enable")
				let message_ctrl = form.children(".pdo_cob_id_message")
				let node_id_ctr = apply_input

				let enable_input = enable_ctrl.val()
				let message_input = message_ctrl.val()
				let node_id_input = node_id_ctr.val()

				let enable_val = parseInt(enable_input << 31)
				let message_val = parseInt(message_input) & 0x780
				let node_id_val = parseInt(node_id_input) & 0x7F

				if (message_val === 0 && node_id_val !== 0)
				{
					$(`#error_label_${apply_input.attr('id').slice(-1)}`).show()
					return
				}

				let pdo_cob_id = (enable_val + message_val + node_id_val) >>> 0
				new_value = `${pdo_cob_id}`

				enable_ctrl.removeClass('changed')
				message_ctrl.removeClass('changed')
				node_id_ctr.removeClass('changed')
			}
			else if (apply_input.hasClass('line_flags'))
			{
				//let form = apply_input.parent()
				let voltage_ctrl = form.children(".line_flags_table")
					.children(".line_flags_voltage_tr")
					.children(".line_flags_voltage_td")
					.children(".line_flags_voltage")
				let voltage_input = voltage_ctrl.val()
				let voltage_val = parseInt(voltage_input << 2)
				

				let no_nc_ctrl = form.children(".line_flags_table")
					.children(".line_flags_no_nc_tr")
					.children(".line_flags_no_nc_td")
					.children(".line_flags_no_nc")
				let no_nc_input = no_nc_ctrl.val()
				let no_nc_val = parseInt(no_nc_input << 1)
				

				let pwm_ctrl = form.children(".line_flags_table")
					.children(".line_flags_pwm_tr")
					.children(".line_flags_pwm_td")
					.children(".line_flags_pwm")
				let pwm_input = pwm_ctrl.val()
				let pwm_val = parseInt(pwm_input << 0)

				new_value = voltage_val + no_nc_val + pwm_val

				voltage_ctrl.removeClass('changed')
				no_nc_ctrl.removeClass('changed')
				pwm_ctrl.removeClass('changed')
			}
			else if (apply_input.hasClass('bit_checkboxes'))
			{
				//let form = apply_input.parent()
				//let table = form.children(".bit_checkboxes_table")
				new_value = 0		
				$.each(form.children('.bit_checkboxes_ctrl'), function(number, ctrl)
				//$($(form.children('.bit_checkboxes_ctrl')).get().reverse()).each(function(number, ctrl)
				{
					let input = utils.checked2string($(ctrl))
					let val = parseInt(input) << number
					new_value += val 
					$(ctrl).removeClass('changed')
				})
				//console.log(new_value)
			}
    		else if (apply_input.hasClass('consumer_heartbeat'))
			{
				//let form = apply_input.parent()
				let node_input_ctrl = form.children(".consumer_heartbeat_node")
				let time_input_ctrl = apply_input
				/*var time_input_ctrl = button.previousElementSibling
                var node_input_ctrl = time_input_ctrl.previousElementSibling*/

                let node_input = node_input_ctrl.val()
				let time_input = apply_input.val()
                //TODO Add check of value
                // heartbeat consumer = node (7 bit from 16 bit) + time (0..15 bit)
                let node_raw_val = (parseInt(node_input) & 0x7F) * 0x10000
                let time_raw_val = parseInt(time_input) & 0xFFFF
                let hb_consumer = node_raw_val + time_raw_val

				new_value = `${hb_consumer}`

				node_input_ctrl.removeClass('changed')
				time_input_ctrl.removeClass('changed')
			}
			else if (apply_input.hasClass('mbtcp_client'))
			{
				//let form = apply_input.parent()
				let mbtcp_client_cs_ctrl = GetSetValue.#get_control_by_name_from_table(form,  "mbtcp_client_table", "mbtcp_client_cs")
                let mbtcp_client_cs_str = utils.checked2string(mbtcp_client_cs_ctrl)
				let mbtcp_client_cs_value = BigInt(mbtcp_client_cs_str) << 60n
				mbtcp_client_cs_ctrl.removeClass('changed')

				let mbtcp_client_timeout_ctrl = GetSetValue.#get_control_by_name_from_table(form,  "mbtcp_client_table", "mbtcp_client_timeout")
				let mbtcp_client_timeout_str = mbtcp_client_timeout_ctrl.val()
				let mbtcp_client_timeout_value = BigInt(mbtcp_client_timeout_str) << 50n
				mbtcp_client_timeout_ctrl.removeClass('changed')
				//console.log(mbtcp_client_timeout_value)

				let mbtcp_client_port_ctrl = GetSetValue.#get_control_by_name_from_table(form,  "mbtcp_client_table", "mbtcp_client_port")
				let mbtcp_client_port_str = mbtcp_client_port_ctrl.val()
				let mbtcp_client_port_value = BigInt(mbtcp_client_port_str) << 32n
				mbtcp_client_port_ctrl.removeClass('changed')
				//console.log(mbtcp_client_port_value)

				let mbtcp_client_ip_ctrl = GetSetValue.#get_control_by_name_from_table(form,  "mbtcp_client_table", "mbtcp_client_ip")
				let mbtcp_client_ip_str = mbtcp_client_ip_ctrl.val()
				let mbtcp_client_ip_value = BigInt(utils.string2int_ip(mbtcp_client_ip_str))
				mbtcp_client_ip_ctrl.removeClass('changed')
				
                let mbtcp_client_value = mbtcp_client_cs_value + mbtcp_client_timeout_value + mbtcp_client_port_value + mbtcp_client_ip_value
				new_value = `${mbtcp_client_value}`
			}
			else if (apply_input.hasClass('mbtcp_client_status'))
			{
				let sum_value = 0

				//let form = apply_input.parent()
				let connection_status_ctrl = GetSetValue.#get_control_by_name_from_table(form,  "mbtcp_client_status_table", "mbtcp_client_status_connection")
				let connection_status_ctrl_value = BigInt(utils.checked2string(connection_status_ctrl)) << 28n
				connection_status_ctrl.removeClass('changed')
				sum_value += connection_status_ctrl_value

				let tls_status_ctrl = GetSetValue.#get_control_by_name_from_table(form,  "mbtcp_client_status_table", "mbtcp_client_status_tls")
				let tls_status_ctrl_value = BigInt(utils.checked2string(tls_status_ctrl)) << 24n
				tls_status_ctrl.removeClass('changed')
				sum_value += tls_status_ctrl_value

				let timeout_ctrl = GetSetValue.#get_control_by_name_from_table(form,  "mbtcp_client_status_table", "mbtcp_client_status_timeout")
				let timeout_ctrl_value = BigInt(utils.checked2string(timeout_ctrl)) << 23n
				timeout_ctrl.removeClass('changed')
				sum_value += timeout_ctrl_value

				let misconfig_ctrl = GetSetValue.#get_control_by_name_from_table(form,  "mbtcp_client_status_table", "mbtcp_client_status_misconfig")
				let misconfig_ctrl_value = BigInt(utils.checked2string(misconfig_ctrl)) << 16n
				misconfig_ctrl.removeClass('changed')
				sum_value += misconfig_ctrl_value

				let port_ctrl = GetSetValue.#get_control_by_name_from_table(form,  "mbtcp_client_status_table", "mbtcp_client_status_port")
				let port_ctrl_value = BigInt(utils.checked2string(port_ctrl))
				port_ctrl.removeClass('changed')
				sum_value += port_ctrl_value

				new_value = `${sum_value}`
			}
			else if (apply_input.hasClass('datetime'))
			{
				let date_input = $("#date_input")
				let time_input = $("#time_input")

				// Конвертируем DD.MM.YYYY → YYYY-MM-DD
				let date_parts = date_input.val().split(".")
				let iso_date = date_parts[2] + "-" + date_parts[1] + "-" + date_parts[0]
				
				let date_time_string = iso_date + "T" + time_input.val() + ".000Z"
				new_value = Date.parse(date_time_string)/1000
				date_input.removeClass('changed')
			}
			else if (apply_input.hasClass('date'))
			{
				let date_input = $("#date_input");

				// Конвертируем DD.MM.YYYY → YYYY-MM-DD
				let date_parts = date_input.val().split(".")
				let iso_date = date_parts[2] + "-" + date_parts[1] + "-" + date_parts[0]

				let date_time_string = iso_date + "T00:00:00.000Z"
				new_value = Date.parse(date_time_string)/1000
				date_input.removeClass('changed')
			}
			else if (apply_input.hasClass('deadband'))
			{
				new_value = apply_input.val()*1000;
			}
			else if (apply_input.hasClass('ip_addr'))
			{
				new_value = utils.string2int_ip(apply_input.val())
			}
			else if (apply_input.hasClass('password'))
			{
				new_value = utils.pass2ascii(new_value)
				apply_input.val('')
			}
			else if (apply_input.hasClass('restore_params')
				|| apply_input.hasClass('string_command'))
			{
				var new_value_buffer = "0x";
				for (var i = (new_value.length - 1); i >= 0; i--)
				{
				 	new_value_buffer += new_value.charCodeAt(i).toString(16);
				}
				new_value = new_value_buffer;
				apply_input.val('');
			}
			else if (index_number.includes('1027')) //Module Types
			{
				if (new_value == common.board_types.f_lcd || new_value == common.board_types.f_io)
				{
					var sub_index = parseInt(index_number.slice(5))
					var modul_number = sub_index - 1
					//console.log(modul_number)
					if (modul_number % 2 == 1)
					{
						new_value = common.board_types.f_lcd
						var index_number_2 = `${index_number.slice(0, 5)}${sub_index + 1}`
						additional_query += `&0x${index_number_2}=${common.board_types.f_io}`
					}
					else
					{
						new_value = common.board_types.f_io
						var index_number_2 = `${index_number.slice(0, 5)}${sub_index - 1}`
						additional_query += `&0x${index_number_2}=${common.board_types.f_lcd}`
					}
					//console.log(additional_query)
				}
			}
			else if (apply_input.hasClass('mcuf_sensor_select'))
			{
				//let form = apply_input.parent()
				let module = form.children(".mcuf_module_select")
				let module_number = module.val() //module number
				let sensor_number = apply_input.val() //sensor number
				let sensor_number_int = parseInt(sensor_number)

				if (sensor_number_int == 0)
				{
					new_value = 0
				}
				else
				{
					new_value = parseInt(module_number)*16 + sensor_number_int
				}
				
			}

			if (apply_input.hasClass('need_restart'))
			{
				//let form = $(`div [index='${index_number}']`)
				//console.log(form.children('.restart'))
				//if (!form.children('.restart') || 
				if (form.children('.restart').length  == 0)
				{
					let div= $('<div class="restart">').attr({"style":"display: blocks;"}).text(l100n.localize_string('Restart and reload'))
					form.append(div)
				}
			}

			GetSetValue.#apply_value(index_number, new_value, apply_input, additional_query)
		}
	}

	static async #apply_value(index_number, new_value, apply_input, additional_query) {
		if (index_number == '2002_1') {
			let query = '/get_od_data.form?'
			query += `0x2001_9` //access_control
			const response = await fetch(query)
			const response_text = await response.text()
			const access_level = response_text.replace('&#&', '')

			if (access_level == '2') { // admin
				if (new_value == '0x00040000') { // change pass
					$("#pass_change_dialog").dialog('open')
				}
			} 
			else if (new_value == '0x00020000' || new_value == '0x00030000' || new_value == '0x00040000') 
			{
				$("#login_dialog").dialog('open')
				console.warn("ACCESS DENIED")
				return
			}
		}

		// Общая часть: проверка и отправка запроса
		if ((new_value == null) || (new_value.toString() == 'NaN') || (apply_input.hasClass('error')))
		{
			alert(l100n.localize_string("Invalid data format."))
		}
		else
		{
			let query = '/set_od_data.form?'
			query += utils.get_set_od_data_query_unit(index_number, new_value)
			query += additional_query

			apply_input.removeClass('changed')
			apply_input.blur()
			
			return GetSetValue.#send_set_query(query)
		}
	}

	#value_paste()
	{
		let new_value = 'empty'
		//console.log(this.#response_values)
		let response_values = this.#response_values

		//$(".value").each(function(index, item)
		$(this.#value_class).each(function(index, item)
		{
			if (index in response_values)
			{
				new_value = response_values[index].replace(/\u0000/g, '')

				let default_value = $(item).parent().children('.default_value')[0]
				
				if (default_value && $(default_value).attr('default_value') != undefined)
				{
					let buf_new_value = new_value
					let buf_default_value = $(default_value).attr('default_value')
					//console.log($(item).attr('tb_index'))
					
					if ($(default_value).attr('data_type') == 'real32')
					{
						buf_new_value = parseFloat(buf_new_value).toString()
						buf_default_value = parseFloat(buf_default_value).toString()
					}
					else if (buf_new_value.includes('0x'))
					{
						buf_new_value = parseInt(new_value).toString()
					}

					if (buf_new_value != buf_default_value)
					{
						$(default_value).show()
					}
					else
					{
						$(default_value).hide()
					}
				}
				

				//console.log($(item).attr('class'))
				if ($(item).hasClass('edit_cb'))
				{
					utils.change_checked($(item), new_value)
				}
				else if ($(item).hasClass('readonly_cb')
					|| $(item).hasClass('boolean_input')
					|| $(item).hasClass('boolean_output')
					|| $(item).hasClass('boolean_alarm'))
				{
					if (new_value == "1")
					{
						$(item).addClass('on')
					}
					else
					{
						$(item).removeClass('on')
					}
				}

				//Change new value
				if ($(item).hasClass('ro') && ($(item).hasClass('combobox') || $(item).hasClass("control_mode")))
				{
					$.each(configuration.data_type_template().templates, function(template_index, template_item)
					{
						if (template_item.index == $(item).attr('tb_index'))
						{
							var find = false
							$.each(template_item.commands, function(command_index, command_item)
							{
								if (command_item.command == new_value)
								{
									find = true
									new_value = command_item.name
									return false //break
								}
							})
							if (!find) {
								$.each(template_item.commands, function(command_index, command_item)
								{
									if (command_item.command == "default")
									{
										new_value = command_item.name
									}
								})
							}
							return false //break
						}
					})
				}
				if ($(item).hasClass('change_value')) 
				{
					$(item).attr({'raw': new_value})
					$.each(configuration.data_type_template().templates, function(template_index, template_item)
					{
						if (template_item.index == $(item).attr('tb_index'))
						{
							var find = false
							$.each(template_item.commands, function(command_index, command_item)
							{
								if (command_item.raw_value == new_value)
								{
									find = true
									new_value = command_item.new_value
									return false //break
								}
							})
							if (!find) {
								$.each(template_item.commands, function(command_index, command_item)
								{
									if (command_item.raw_value == "default")
									{
										new_value = command_item.new_value
									}
								})
							}
							return false //break
						}
					})
				}
                else if ($(item).hasClass('datetime') || $(item).hasClass('datetime_show'))
				{
					const datetime_int = parseInt(new_value)
					const subseconds = parseInt(datetime_int / Math.pow(2,32))
					const datetime = new Date((datetime_int - subseconds*Math.pow(2,32))*1000)
					
					//let date = utils.dateYYYYMMDD(datetime)
					//let loc = l100n.locale || l100n.default_locale;
					let loc = 'ru'
					let date = datetime.toLocaleDateString(loc)
					let time = utils.timeHHmmss(datetime)

					if ($(item).hasClass('datetime'))
					{
						let date_input = $("#date_input")
						let time_input = $("#time_input")

						if (!date_input.hasClass('changed'))
						{
							date_input.val(date);
							//date_input.datepicker('setDate', date)
						}
						if (!time_input.hasClass('changed'))
						{
							time_input.val(time);
						}
					}
					else if ($(item).hasClass('datetime_show'))
					{
						$("#date_show").text(date);
						$("#time_show").text(time);
					}
				}
				else if ($(item).hasClass('pdo_mapping'))
				{
					// read value of hex
					let pdo_mapping_int = parseInt(new_value)

					let index_int = (pdo_mapping_int >> 16) & 0xFFFF
					let subindex_int = (pdo_mapping_int >> 8) & 0xFF
					let size_int = (pdo_mapping_int >> 0) & 0xFF

					let index_value = `0x${index_int.toString(16).toUpperCase()}`
					let subindex_value = `${subindex_int}`
					let size_value = `${size_int}`
					/*console.log(new_value1)
					console.log(new_value2)
					console.log(new_value3)*/
					let form = $(item).parent()
					let index_ctrl = form.children(".pdo_mapping_index")
					let subindex_ctrl = form.children(".pdo_mapping_subindex")

					if (!index_ctrl.hasClass('changed'))
					{
						index_ctrl.val(index_value)
					}
					if (!subindex_ctrl.hasClass('changed'))
					{
						subindex_ctrl.val(subindex_value)
					}
					new_value = size_value
				}
				else if ($(item).hasClass('pdo_cob_id'))
				{
					let pdo_cob_id_int = parseInt(new_value) // read value of hex
					let message_value

					let enable_int = pdo_cob_id_int >>> 31
					let message_int = pdo_cob_id_int & 0x780
					let node_id_int = pdo_cob_id_int & 0x7F

					$.each(configuration.data_type_template().templates, function(template_index, template_item)
					{
						if (template_item.index == $(item).attr('tb_index'))
						{
							var find = false
							$.each(template_item.messages, function(command_index, command_item)
							{
								if (command_item.command == message_int)
								{
									message_value = message_int
									find = true
									return false //break
								}
							})
							if (!find) {
								message_value = "default"
							}
							return false //break
						}
					})
					/*console.log(enable_int)
					console.log(message_value)
					console.log(node_id_int)*/
					let form = $(item).parent()
					let enable_ctrl = form.children(".pdo_cob_id_enable")
					let message_ctrl = form.children(".pdo_cob_id_message")

					if (!enable_ctrl.hasClass('changed'))
					{
						enable_ctrl.val(enable_int)
					}
					if (!message_ctrl.hasClass('changed'))
					{
						message_ctrl.val(message_value)
					}
					new_value = node_id_int
				}
				else if  ($(item).hasClass('line_flags'))
				{
					let line_flags_int = parseInt(new_value) // read value of hex

					//console.log(line_flags_int)
					let voltage_int = (line_flags_int >>> 2) & 0x3
					let no_nc_int = (line_flags_int >>> 1) & 0x1
					let pwm_int = line_flags_int & 0x1
					/*console.log(voltage_int)
					console.log(no_nc_int)
					console.log(pwm_int)*/
					let form = $(item).parent()
					let voltage_ctrl = form.children(".line_flags_table")
						.children(".line_flags_voltage_tr")
						.children(".line_flags_voltage_td")
						.children(".line_flags_voltage")
					let no_nc_ctrl = form.children(".line_flags_table")
						.children(".line_flags_no_nc_tr")
						.children(".line_flags_no_nc_td")
						.children(".line_flags_no_nc")
					let pwm_ctrl = form.children(".line_flags_table")
						.children(".line_flags_pwm_tr")
						.children(".line_flags_pwm_td")
						.children(".line_flags_pwm")

					if (!voltage_ctrl.hasClass('changed'))
					{
						voltage_ctrl.val(voltage_int)
					}
					if (!no_nc_ctrl.hasClass('changed'))
					{
						no_nc_ctrl.val(no_nc_int)
					}
					if (!pwm_ctrl.hasClass('changed'))
					{
						pwm_ctrl.val(pwm_int)
					}
				}
				else if  ($(item).hasClass('bit_checkboxes'))
				{
					let bit_checkboxes_int = parseInt(new_value) // read value of hex
					//console.log(bit_checkboxes_int)
					let form = $(item).parent()
					//let table = form.children(".bit_checkboxes_table")

					$.each(form.children('.bit_checkboxes_ctrl'), function(number, ctrl)
					//$($(form.children('.bit_checkboxes_ctrl')).get().reverse()).each(function(number, ctrl)
					{
						//console.log(number)
						let item_int = GetSetValue.#get_bit(bit_checkboxes_int, number + 1)
						//let ctrl = $(tr).children('.bit_checkboxes_td').children(`.bit_checkboxes_ctrl`)

						if (!$(ctrl).hasClass('changed'))
						{
							utils.change_checked($(ctrl), item_int)
						}
						//console.log(item_int)
					})
				}
				else if ($(item).hasClass('one_wire_sensors'))
				{
					let form = $(item).parent()
					let selected_input = form.children(".one_wire_selected_input")
					if (new_value.length > 8)
					{
						selected_input.text(new_value.substring(new_value.length - 8))
					}
					else
					{
						selected_input.text(new_value)
					}
					

					//let sensor_select = form.children(".one_wire_sensor_select")
					new_value = '0x0'
				}
                else if ($(item).hasClass('consumer_heartbeat'))
				{
					let hb_consumer_int = parseInt(new_value)
					
                    // heartbeat consumer = node (7 bit from 16 bit) + time (0..15 bit)
					let node_int = ((hb_consumer_int >> 16) & 0x7F)
					let time_int = hb_consumer_int & 0xFFFF
					let node_value = `0x${node_int.toString(16).toUpperCase()}`
					let time_value = `${time_int}`

					let form = $(item).parent()
					let node_ctrl = form.children(".consumer_heartbeat_node")
					if (!node_ctrl.hasClass('changed')) {
						node_ctrl.val(node_value)
					}
					new_value = time_value
				}
				else if ($(item).hasClass('mbtcp_client'))
				{
					let form = $(item).parent()
					let mbtcp_client_bigint = BigInt(new_value)

					let cs_int = (mbtcp_client_bigint >> 60n) & 0x1n // 60
					let cs_ctrl = GetSetValue.#get_control_by_name_from_table(form,  "mbtcp_client_table", "mbtcp_client_cs")
					if (!cs_ctrl.hasClass('changed')) 
					{
						utils.change_checked(cs_ctrl, cs_int)
					}

					let timeout_int = (mbtcp_client_bigint >> 50n) & 0x3FFn // 50-59
					let timeout_ctrl = GetSetValue.#get_control_by_name_from_table(form,  "mbtcp_client_table", "mbtcp_client_timeout")
					if (!timeout_ctrl.hasClass('changed')) {
						timeout_ctrl.val(`${timeout_int}`)
					}

					let port_int = (mbtcp_client_bigint >> 32n) & 0xFFFFn // 32-47
					let port_ctrl = GetSetValue.#get_control_by_name_from_table(form,  "mbtcp_client_table", "mbtcp_client_port")
					if (!port_ctrl.hasClass('changed')) {
						port_ctrl.val(`${port_int}`)
					}

					let ip_int = (mbtcp_client_bigint) & 0xFFFFFFFFn
					let ip_ctrl = GetSetValue.#get_control_by_name_from_table(form,  "mbtcp_client_table", "mbtcp_client_ip")
					if (!ip_ctrl.hasClass('changed')) {
						ip_ctrl.val(utils.ip2string(ip_int))
					}
				}
				else if ($(item).hasClass('mbtcp_client_status'))
				{
					let form = $(item).parent()
					let response_bigint = BigInt(new_value)

					let connection_ctrl = GetSetValue.#get_control_by_name_from_table(form,  "mbtcp_client_status_table", "mbtcp_client_status_connection")
					if (!connection_ctrl.hasClass('changed')) 
					{
						let connection_status_raw = (response_bigint >> 28n) & 0xFn
						let status_string = "undefined" 
						$.each(configuration.data_type_template().templates, function(template_index, template_item)
						{
							if (template_item.index == $(item).attr('tb_index'))
							{
								var find = false
								$.each(template_item.connection_status, function(command_index, status_item)
								{
									if (status_item.raw_value == connection_status_raw)
									{
										status_string = status_item.new_value
										find = true
										return false //break
									}
								})
								if (!find) {
									status_string = connection_status_raw.toString()
								}
								return false //break
							}
						})
						//connection_status
						connection_ctrl.text(status_string)
					}

					let tls_ctrl = GetSetValue.#get_control_by_name_from_table(form,  "mbtcp_client_status_table", "mbtcp_client_status_tls")
					if (!tls_ctrl.hasClass('changed')) 
					{
						tls_ctrl.text((response_bigint >> 24n) & 0xFn)
					}

					let timeout_ctrl = GetSetValue.#get_control_by_name_from_table(form,  "mbtcp_client_status_table", "mbtcp_client_status_timeout")
					if (!timeout_ctrl.hasClass('changed')) 
					{
						//utils.change_checked(timeout_ctrl, (response_bigint >> 23n) & 0x1n)
						let mbtcp_client_status_timeout_raw = (response_bigint >> 23n) & 0x1n
						//console.log(mbtcp_client_status_timeout_raw)
						if (mbtcp_client_status_timeout_raw == 1)
						{
							$(timeout_ctrl).addClass('on')
						}
						else
						{
							$(timeout_ctrl).removeClass('on')
						}
					}

					let misconfig_ctrl = GetSetValue.#get_control_by_name_from_table(form,  "mbtcp_client_status_table", "mbtcp_client_status_misconfig")
					if (!misconfig_ctrl.hasClass('changed')) 
					{
						misconfig_ctrl.text((response_bigint >> 16n) & 0xFn)
					}

					let port_ctrl = GetSetValue.#get_control_by_name_from_table(form,  "mbtcp_client_status_table", "mbtcp_client_status_port")
					if (!port_ctrl.hasClass('changed')) 
					{
						port_ctrl.text((response_bigint) & 0xFFFFn)
					}
				}
				else if ($(item).hasClass('time'))
				{
                    if (new_value == 0) {
                        new_value = 'No time'
                    } else {
					    var datetime_int = parseInt(new_value);
					    var subseconds = parseInt(datetime_int / Math.pow(2,32));
					    var datetime = new Date((datetime_int - subseconds*Math.pow(2,32))*1000 + subseconds);
					    new_value = utils.timeHHmm(datetime)
                    }
				}
				else if ($(item).hasClass('date'))
				{
                    if (new_value == 0) {
                        new_value = 'No date'
                    } else {
					    var datetime_int = parseInt(new_value);
					    var subseconds = parseInt(datetime_int / Math.pow(2,32));
					    var datetime = new Date((datetime_int - subseconds*Math.pow(2,32))*1000 + subseconds);
						new_value = datetime.toLocaleDateString('ru')
                    }
				}
				else if($(item).hasClass('datetime_simple'))
				{
                    if (new_value == 0) {
                        new_value = 'No date'
                    } else {
					    var datetime_int = parseInt(new_value)
					    var subseconds = parseInt(datetime_int / Math.pow(2,32))
					    var datetime = new Date((datetime_int - subseconds*Math.pow(2,32))*1000 + subseconds)
					    new_value = `${datetime.toLocaleDateString('ru')} ${utils.timeHHmmss(datetime)}`
                    }
				}
				else if($(item).hasClass('datetime_with_nanosec_simple'))
				{
                    if (new_value == 0) {
                        new_value = 'No date'
                    } else {
					    let datetime_bigint = BigInt(new_value);
                        let seconds = datetime_bigint & ((1n << 32n) - 1n);
                        let microseconds = parseInt(Number((datetime_bigint >> 32n)/1000000n));
                        let timestampMs = Number(seconds) * 1000 + microseconds;
                        let datetime = new Date(timestampMs);
                        let nanosec = Number(datetime_bigint >> 32n).toString().padStart(9, '0');
                        new_value = `${datetime.toLocaleDateString('ru')} ${utils.timeHHmmss(datetime)}.${nanosec}`;
                    }
				}
				else if ($(item).hasClass('deadband'))
				{
					new_value = new_value/1000;
				}
				else if ($(item).hasClass('ip_addr'))
				{
					new_value = utils.ip2string(new_value)
				}
				else if ($(item).hasClass('mac_addr'))
				{
					new_value = utils.mac_from_string(new_value)
				}
				else if ($(item).hasClass('hex'))
				{
					new_value = "0x"+parseInt(new_value).toString(16);
				}
				else if ($(item).hasClass('error_field'))
				{
					new_value = GetSetValue.#error_field_parser(new_value);
				}
				else if ($(item).hasClass('battery'))
				{
					var value_int = parseFloat(new_value)
					new_value = value_int.toFixed(2)
				}
				/*else if ($(item).hasClass('checkbox_value'))
				{
					$.each(templates_commands.default_checkbox_values(), function(command_index, command_item)
					{
						if (command_item.raw_value == new_value)
						{
							new_value = command_item.new_value
							return false //break
						}
					});
				}*/
				else if ($(item).hasClass('restore_params')
					|| $(item).hasClass('string_command'))
				{
					if (new_value == "0")
					{
						new_value = ""
					}
				}
				else if ($(item).hasClass("bit_value"))
				{
					let bit_value = new_value

					let parsed_value = GetSetValue.get_bit_value($(item).attr('tb_index'), new_value)
					if (new_value == 0)
					{
						$(item).addClass("no_error")
					}
					else
					{
						$(item).removeClass("no_error")
					}

					new_value = `${parsed_value} (${bit_value})`
				}
				else if ($(item).hasClass("control_mode"))
				{
					if (!$(item).hasClass('changed'))
					{
						heat_line_common.mark_control_mode_tab(item, new_value)
					}
				}
				else if ($(item).hasClass("module_types"))
				{
					/*if (new_value == common.board_types.f_lcd)
					{
						//$(item).attr({"disabled":"true"})
						var index_number_1 = $(item).attr('tb_index')
						var sub_index = parseInt(index_number_1.slice(5))
						var index_number_2 = `${index_number_1.slice(0, 5)}${sub_index + 1}`
						var input_2 = $(`[tb_index='${index_number_2}']`)
						input_2.attr({"disabled":"true"})
					}*/
					if (new_value == common.board_types.f_io)
					{
						//$(item).attr({"disabled":"true"})
						var index_number_1 = $(item).attr('tb_index')
						var sub_index = parseInt(index_number_1.slice(5))
						var index_number_2 = `${index_number_1.slice(0, 5)}${sub_index - 1}`
						var input_2 = $(`[tb_index='${index_number_2}']`)
						input_2.attr({"disabled": true})
					}
					else
					{
						var index_number_1 = $(item).attr('tb_index')
						var sub_index = parseInt(index_number_1.slice(5))
						var index_number_2 = `${index_number_1.slice(0, 5)}${sub_index - 1}`
						var input_2 = $(`[tb_index='${index_number_2}']`)
						input_2.attr({"disabled": false})
					}
				}
				else if ($(item).hasClass("mcuf_sensor_select"))
				{
					let form = $(item).parent()
					let module = form.children(".mcuf_module_select")
					let module_number = parseInt(new_value/16) //module number
					let sensor_number = new_value % 16 //sensor number

					new_value = sensor_number
					if (!module.hasClass('changed'))
					{
						module.val(module_number)
					}
				}



				if ($(item).hasClass('datetime') || $(item).hasClass('datetime_show'))
				{
					//pass
				}
				else if ($(item).hasClass("bit_value"))
				{
					$(item).html(new_value)
				}
				// default
				else if (!$(item).hasClass('changed'))//!$(item).is(":focus") ||
				{
					if ($(item).is("div"))
					{
						$(item).text(new_value)
					}
					else if ($(item).hasClass('combobox'))
					{
						//let info = $(item).parent().children('.combobox_info')
						if (!$(item).hasClass('without_undetermined') && $(item).find(`option[value="${new_value}"]`).length === 0)
						{
							let option = $("<option>")
								.text(`${new_value} - ${l100n.localize_string("unknown_value")}`)
								.val(new_value)
								.attr("data-category", "undefined")
							
							$(item).append(option)

							//info.show()
							//info.html(`${new_value} - ${l100n.localize_string("unknown_value")}`)
						}
						else
						{
							//info.hide()
						}
						$(item).val(new_value)
					}
					else
					{
						$(item).val(new_value)
					}
				}

				$(item).trigger('value_loaded')
			}
		})
	}

	static get_bit_value(index, new_value)
	{	
		$.each(configuration.data_type_template().templates, function(template_index, template_item)
		{
			if (template_item.index == index)
			{
				if (new_value == 0)
				{
					$.each(template_item.commands, function(command_index, command_item)
					{
						var bit_position = template_item.commands[command_index].bit_position
						if (bit_position == 0)
						{
							new_value = command_item.new_value
							return false //break
						}
					})
				}
				else
				{
					var  buf = "";
					$.each(template_item.commands, function(command_index, command_item)
					{
						if (command_index != 0)
						{
							var bit_position = template_item.commands[command_index].bit_position
							if (GetSetValue.#get_bit(new_value, bit_position)) { buf += `${command_item.new_value}<br>`}//(${bit_position})
						}
					})
					new_value = buf
				}
				return false //break
			}
		})
		return new_value
	}

	static #send_set_query(query)
	{
		return fetch(query)
			.then(response => {
				response.text()
				.then(response_text => {
					let responseLines = response_text.split('\n')
					let responseLine = responseLines[0]
	
					let url = new URL(response.url)
					let urlSearch = url.search.slice(1)
					let params = new URLSearchParams(urlSearch)

					/*if (params.has('0x2002_1')) //access command
					{
						if (responseLine.includes('!!!ERROR!!!'))
						{
							alert(l100n.localize_string('ACCESS DENIED'))
							console.warn(`${l100n.localize_string("ACCESS DENIED")}. На запрос: ${query} ответ: ${responseLine}`)
						}
					}
					else*/
					if (params.has('0x2002_2')) //password
					{
						//console.log(responseLine)
						if (responseLine.includes('!!!ERROR!!!'))
						{
							alert(l100n.localize_string('ACCESS DENIED'))
							console.warn(`${l100n.localize_string("ACCESS DENIED")}. На запрос: ${query} ответ: ${responseLine}`)
						}
						else
						{
							alert(l100n.localize_string('ACCESS CONFIRMED'))
							$("#login_dialog").dialog('close')
						}
					}
					else
					{
						//console.log("responseLine:"+responseLine)
						if ((responseLine.search( />>>ERROR<<</i ) != -1) || (responseLines[0].search( /!!!ERROR!!!/i ) != -1))
						{
							console.error(`${l100n.localize_string("response error")}. На запрос: ${query} ответ: ${responseLine}`)
							alert(l100n.localize_string("response error"))//: ' + responseLine)
						}
					}
				})
			})
			.catch(function(error) {
				//console.log(query)
				console.log(`${l100n.localize_string('Request failed')}: ${error} "${query}"`)
			})
	}

	
	static #get_bit(value, bit_position)
	{
		return (value & (1 << (bit_position-1))) >>> (bit_position-1)
	}

	
	static #get_control_by_name_from_table(form, table_name, name)
	{
		let control = form.children(`.${table_name}`)
					.children(`.${name}_tr`)
					.children(`.${name}_td`)
					.children(`.${name}`)
		return control
	}

	
	static #get_label_control_tr(name, label, control)
	{
		control.addClass('mbtcp_client').addClass(name)

		let tr = $('<tr>').addClass(`${name}_tr`)
		let label_td = $('<td>').append(label)
		let control_td = $('<td>').append(control).addClass(`${name}_td`)

		tr.append(label_td).append(control_td)
		return tr
	}

	// Parse index 1003 Error fields
	static #error_field_parser(error_code)
	{
		if (error_code == 0) {
			return l100n.localize_string("error_field_None")
		}
		else if((error_code & 0x0000F000) == 0x00007000) {
			let number = (error_code & 0x0000000F) + 1
			let sub_code = (error_code & 0xFFFF0000) >> 16
			return `${l100n.localize_string("error_field_Module")} ${number}. ${l100n.localize_string("error_field_Code")} 0x${sub_code.toString(16).toUpperCase()}. (${error_code})`
		}
		else if((error_code & 0x0000FFFF) == 0x00006240) {
			let index = (error_code >> 16) & 0xFFFF
			return `${l100n.localize_string("error_field_AppSW. Access to index")} 0x${index.toString(16).toUpperCase()}. (${error_code})`
		} else if((error_code & 0x0000FFFF) == 0x00006241) {
			let index = (error_code >> 16) & 0xFFFF
			return `${l100n.localize_string("error_field_AppSW. Access to subindex of index")} 0x${index.toString(16).toUpperCase()}. (${error_code})`
		} else if((error_code & 0x0000FFFF) == 0x00006242) {
			let index = (error_code >> 16) & 0xFFFF
			return `${l100n.localize_string("error_field_AppSW. Access (read) to index")} 0x${index.toString(16).toUpperCase()}. (${error_code})`
		} else if((error_code & 0x0000FFFF) == 0x00006243) {
			let index = (error_code >> 16) & 0xFFFF
			return `${l100n.localize_string("error_field_AppSW. Access (write) to index")} 0x${index.toString(16).toUpperCase()}. (${error_code})`
		} else if((error_code & 0x0000FFFF) == 0x00006220) {
			return `${l100n.localize_string("error_field_AppSW. Internal error.")} (${error_code})`
		} else if((error_code & 0x0000FFFF) == 0x00006221) {
			return `${l100n.localize_string("error_field_AppSW. Firmware CRC.")} (${error_code})`
		}
		else if((error_code & 0x0000FFFF) == 0x00006222) {
			return `${l100n.localize_string("error_field_AppSW. Firmware size.")} (${error_code})`
		}
		else if((error_code & 0x0000FFFF) == 0x00006223) {
			return `${l100n.localize_string("error_field_AppSW. Device signature.")} (${error_code})`
		}
		else if((error_code & 0x0000FFFF) == 0x00006224) {
			return `${l100n.localize_string("error_field_AppSW. Memory map.")} (${error_code})`
		}
		else if((error_code & 0x0000FFFF) == 0x00003101) {
			return `${l100n.localize_string("error_field_Main power supply is missing.")} (${error_code})`
		}
		else if((error_code & 0x00003203) == 0x00003203) {
			return `${l100n.localize_string("error_field_Battery.")} (${error_code})`
		}
		else if((error_code & 0x0000500A) == 0x0000500A) {
			return `${l100n.localize_string("error_field_Real Time Clock.")} (${error_code})`
		}
		else if (error_code == 0x31013101) {
			return `${l100n.localize_string("error_field_No main power supply")} (${error_code})`
		}
		else if((error_code & 0x0000FFFF) == 0x0000FF31) {
			let ignore_map = ((error_code >> 16) & 0x0000FFFF)
			return `${l100n.localize_string("error_field_ModbusMappings. Ignoring last")} ${ignore_map} ${l100n.localize_string("error_field_mappings")} (${error_code})`
		}
		else if((error_code & 0x0000FFFF) == 0x0000FF30) {
			return `${l100n.localize_string("error_field_protocol selection")} (${error_code})`
		}
		return error_code
	}
}

	$(document).ready(function()
	{
		$(document).on('click', '.item_edit_b', function()
		{
		    GetSetValue.item_edit_click(this);
		})
		$(document).on('click', '.edit_cb', function()
		{
		    GetSetValue.checkbox_click(this);
		})
		/*$(document).on('change', '.combobox', function()
		{
		    GetSetValue.combobox_change(this)
		})*/
		$(document).on('click', '.combobox', function()
		{
		    GetSetValue.combobox_click(this)
		})

		$(document).on('submit', '.apply_form', the_event =>
		{
			the_event.preventDefault();
			the_event.stopImmediatePropagation();
		})
		$(document).on('focus', '.value', function()
		{
			$(this).addClass("changed")
		})
		$(document).on('blur', 'div.value', function()//only readonly elements
		{
			$(this).removeClass("changed")
		})
		$(document).on('focus', '.datetime', function()
		{
			$(this).addClass("changed")
		})
		$(document).on('focus', '.consumer_heartbeat', function()
		{
			$(this).addClass("changed")
		})
		$(document).on('focus', '.mbtcp_client', function()
		{
			$(this).addClass("changed")
		})
		$(document).on('focus', '.pdo_mapping', function()
		{
			$(this).addClass("changed")
		})
		$(document).on('focus', '.pdo_cob_id', function()
		{
			$(this).addClass("changed")
			$(`#error_label_${this.id.slice(-1)}`).hide()
		})
		$(document).on('focus', '.mcuf_module_select', function()
		{
			$(this).addClass("changed")
		})
		$(document).on('focus', '.line_flags', function()
		{
			$(this).addClass("changed")
		})
		$(document).on('focus', '.bit_checkboxes', function()
		{
			$(this).addClass("changed")
		})

		function input_change(input)
		{
			input.addClass("changed")
			let form = input.parent()
			let button = form.children('.item_edit_b')
			button.addClass("button_edited")
		}

		$(document).on('change', '.value', function()
		{
			input_change($(this))
		})
		$(document).on('change', '.datetime', function()
		{
			input_change($(this))
		})
		$(document).on('change', '.consumer_heartbeat', function()
		{
			input_change($(this))
		})
		$(document).on('change', '.mbtcp_client', function()
		{
			input_change($(this))
		})
		$(document).on('change', '.pdo_mapping', function()
		{
			input_change($(this))
		})
		$(document).on('change', '.pdo_cob_id', function()
		{
			input_change($(this))
		})
		$(document).on('change', '.mcuf_module_select', function()
		{
			input_change($(this))
		})
		$(document).on('change', '.line_flags', function()
		{
			let form = $(this).parent().parent().parent().parent()
			let button = form.children('.item_edit_b')
			button.addClass("button_edited")
		})
		$(document).on('change', '.bit_checkboxes', function()
		{
			input_change($(this))
		})
		
		/*$(document).on('blur', '.datetime', function()//only readonly elements
		{
			$(this).removeClass("changed")
		})*/
			
	})
