'use strict'

// New Class for Settings Section.
class ShortPixelSettings {

	tab_elements = {};
	menu_elements = [];
	current_tab; // string, the name of the tab.
	current_mode = 'simple';
	root; // top of settings page.
	strings;
	dashboard_status = {};
	save_in_progress = false;

	Init() {
		this.root = document.querySelector('.wrap.is-shortpixel-settings-page');

		this.InitActions();
		this.InitAjaxForm();
		this.SaveOnKey();

		var ev = new CustomEvent('shortpixel.settings.loaded', { detail: { 'root': this.root, 'settings': this } });
		document.dispatchEvent(ev);
	}

	InitActions() {
		var self = this;
		this.strings = settings_strings;

		this.InitToggle(); // data- toggles 
		this.InitExclusions(); // Exclusions 
		this.InitWarnings(); // Settings warnings 
		this.InitMenu(); // The menu 
		this.InitModeSwitcher(); // Simple / Advanced mode 
		this.InitActionEvents(); // Action events.
		this.InitAiEvents(); 

		// Modals
		var modals = this.root.querySelectorAll('[data-action="open-modal"]');
		modals.forEach(function (modal, index) {
			modal.addEventListener('click', self.OpenModalEvent.bind(self));
		});
	}

	InitToggle() {
		var toggles = this.root.querySelectorAll('[data-toggle]');
		var self = this;

		toggles.forEach(function (toggle, index) {
			toggle.addEventListener('change', self.DoToggleActionEvent.bind(self));

			let evInit = new CustomEvent('change', { detail: { init: true } });
			toggle.dispatchEvent(evInit);
		});

		// This is all super unflexible, and would probably need to be changed with a new warning system, which could take multiple inputs.
		toggles = this.root.querySelectorAll('[data-exclude]');
		toggles.forEach(function (toggle, index) {
			toggle.addEventListener('change', self.DoToggleExcludeEvent.bind(self));
		});

		toggles = this.root.querySelectorAll('[data-disable]');
		toggles.forEach(function (toggle, index) {
			toggle.addEventListener('change', self.DoToggleDisableEvent.bind(self));

			let evInit = new CustomEvent('change', { detail: { init: true } });
			toggle.dispatchEvent(evInit);
		});


		let hideWarnings = this.root.querySelectorAll('[data-hidewarnings]');
		hideWarnings.forEach(function (hide, index) {
			hide.addEventListener('change', self.DoToggleHideWarningEvent.bind(self));
		});


		// ApiKeyField toggle
		var keyField = this.root.querySelector('.apifield i.eye');
		keyField.addEventListener('click', self.ToggleApiFieldEvent.bind(self));

	}

	InitAjaxForm() {
		var forms = this.root.querySelectorAll('form');
		for (var i = 0; i < forms.length; i++) {
			forms[i].addEventListener('submit', this.FormSendEvent.bind(this));
		}

	}

	InitExclusions() {
		var self = this;
		// Events for the New Exclusion dialog
		var newExclusionInputs = this.root.querySelectorAll('.new-exclusion select, .new-exclusion input, .new-exclusion button, button[name="cancelEditExclusion"]');

		newExclusionInputs.forEach(function (input) {
			switch (input.name) {
				case 'addExclusion':
				case 'removeExclusion':
				case 'cancelEditExclusion':
				case 'updateExclusion':
					var eventType = 'click';
					break;
				default:
					var eventType = 'change';
					break;
			}

			input.addEventListener(eventType, self.NewExclusionUpdateEvent.bind(self));
		});

		var exclusionItems = this.root.querySelectorAll('.exclude-list li i.edit, .exclude-list li');
		exclusionItems.forEach(function (input) {
			if (false == input.classList.contains('no-exclusion-item')) {
				input.addEventListener('click', self.NewExclusionShowInterfaceEvent.bind(self));
			}
		});

		var exclusionItems = this.root.querySelectorAll('.exclude-list li i.remove');
		exclusionItems.forEach(function (input) {
			if (false == input.classList.contains('no-exclusion-item')) {
				input.addEventListener('click', self.RemoveExclusion.bind(self));
			}
		});

		var addNewExclusionButton = this.root.querySelector('.new-exclusion-button');
		if (addNewExclusionButton !== null) {
			addNewExclusionButton.addEventListener('click', this.NewExclusionShowInterfaceEvent.bind(this));
		}

		var size_select = new ShiftSelect('input[name^="excludeSizes[]"]');

		var compressionRadios = this.root.querySelectorAll('.shortpixel-compression-options input[type="radio"]');
		for (var i = 0; i < compressionRadios.length; i++) {
			compressionRadios[i].addEventListener('change', this.CompressionTypeChangeEvent.bind(this));
		}
	}

	InitWarnings() {
		var self = this;

		var checkMatches = (elements, checks) => {
			var allMatches = true;
			var someMatch = false;
			var matches = [];

			for (var i = 0; i < elements.length; i++) {
				if (elements[i].matches(checks[i])) {
					someMatch = true;
					matches.push(elements[i]);
				}
				else {
					allMatches = false;
				}
			}

			return { allMatches: allMatches, someMatch: someMatch, matches: matches }
		}

		var showHideFunctions = {
			'onTrue': this.ShowElement,
			'onFalse': this.HideElement
		};

		var updateShowWarning = (args) => {

			var defaults = {
				functions: showHideFunctions,
				//		checkFunction: ifAllChecked,
			}

			args = { ...defaults, ...args };

			if (typeof args.elements === 'undefined') {
				console.error('No elements in updateShowWarning', args);
				return false;
			}

			if (typeof args.warnings === 'undefined') {
				console.error('Function needs one or more warning elements', args);
				return false;
			}

			if (typeof args.checks === 'undefined' || args.elements.length !== args.checks.length) {
				console.error('Checks must be provided and same length as elements', args);
				return false;
			}

			for (var i = 0; i < args.elements.length; i++) {
				args.elements[i].addEventListener('change', function (event) {
					event.preventDefault();
					var matches = checkMatches(args.elements, args.checks);

					if (true === matches.allMatches) {
						args.functions.onTrue.call(this, args.warnings, matches, args.elements);
					}
					else if (false === matches.someMatch) {
						args.functions.onFalse.call(this, args.warnings, matches, args.elements);
					}
					else {
						if (typeof args.functions.onAny !== 'undefined') {
							args.functions.onAny.call(this, args.warnings, matches, args.elements);
						}
						else {
							args.functions.onFalse.call(this, args.warnings, matches, args.elements);
						}
					}
				}.bind(this));
			} // set the eventlisteners

			var matches = checkMatches(args.elements, args.checks);
			if (true == matches.allMatches) {
				args.functions.onTrue.call(this, args.warnings, matches, args.elements);
			}
			else if (typeof args.functions.onAny !== 'undefined') {
				args.functions.onAny.call(this, args.warnings, matches, args.elements);
			}

		}

		var root = this.root;

		var el = root.querySelector('input[name="exif"]');
		var remove_elements = root.querySelectorAll('input[name="exif"], input[name="png2jpg"]');
		var checks = [':checked', ':not(:checked)'];


		// General checks //
		var warning = root.querySelectorAll('.exif-warning');
		updateShowWarning({ elements: remove_elements, warnings: warning, checks: checks });

		var elements = root.querySelectorAll('input[name="backupImages"]');
		var warning = root.querySelectorAll('#backup-warning');
		var checks = [':not(:checked)'];
		updateShowWarning({ elements: elements, warnings: warning, checks: checks });

		var elements = root.querySelectorAll('input[name="offload-active"], input[name="useSmartcrop"]');
		var warning = root.querySelectorAll('#smartcrop-warning');
		var checks = [':checked', ':checked'];
		updateShowWarning({ elements: elements, warnings: warning, checks: checks });

		var elements = root.querySelectorAll('input[name="heavy_features"], input[name="optimizeUnlisted"]');
		var warning = root.querySelectorAll('.heavy-feature-virtual.unlisted');
		var checks = [':checked', ':checked'];
		updateShowWarning({ elements: elements, warnings: warning, checks: checks });

		var elements = root.querySelectorAll('input[name="heavy_features"], input[name="optimizeRetina"]');
		var warning = root.querySelectorAll('.heavy-feature-virtual.retina');
		var checks = [':checked', ':checked'];
		updateShowWarning({ elements: elements, warnings: warning, checks: checks });

		// This warning takes the same element twice, with different checks.
		var element = root.querySelector('input[name="useCDN"]');
		var elements = [element, element];
		var warning = root.querySelectorAll('.cdn-offload');
		var checks = [':checked', '.is-wpoffload'];
		updateShowWarning({ elements: elements, warnings: warning, checks: checks });


		// Checks for the dashboard boxes
		// What can be send back match wise, can be 'allmatches' for red and 'anymatches' for yellow warning and let the dashboard function figure it out how to display that ( and which text? )
		var dashboardFunctions = {
			'onTrue': this.DashBoardWarningEvent,
			'onFalse': this.DashBoardWarningEvent,
			'onAny': this.DashBoardWarningEvent,
		}

		// First box (optimize) dashboard warning
		var elements = root.querySelectorAll('input[name="autoMediaLibrary"], input[name="backupImages"], input[name="doBackgroundProcess"]');
		var warnings = root.querySelectorAll('.panel.dashboard-optimize');
		var checks = [':not(:checked)', ':not(:checked)', ':not(:checked)'];
		updateShowWarning({ elements: elements, warnings: warnings, checks: checks, functions: dashboardFunctions });

		var elements = root.querySelectorAll('input[name="createWebp"],input[name="createAvif"],input[name="deliverWebp"],input[name="useCDN"]');
		var warnings = root.querySelectorAll('.panel.dashboard-webp');
		var checks = [':checked', ':checked', ':checked', ':checked'];

		var CDNFunctions = {
			'onTrue': this.CDNCheckWarningEvent,
			'onFalse': this.CDNCheckWarningEvent,
			'onAny': this.CDNCheckWarningEvent,
		};

		updateShowWarning({ elements: elements, warnings: warnings, checks: checks, functions: CDNFunctions });

	}

	InitMenu() {
		//var menu_elements = this.root.querySelectorAll('menu ul li a');
		var menu_elements = this.root.querySelectorAll('[data-menu-link]');
		this.menu_elements = menu_elements;

		// Bind change event to all menu items.
		for (var i = 0; i < menu_elements.length; i++) {
			var element = menu_elements[i];
			element.addEventListener('click', this.SwitchMenuTabEvent.bind(this));

		}

		// Load all menu tabs
		var tab_elements = this.root.querySelectorAll('[data-part]');
		for (var i = 0; i < tab_elements.length; i++) {
			var name = tab_elements[i].dataset.part;
			this.tab_elements[name] = tab_elements[i];
		}

		// Discover current tab
		var displayPartEl = this.root.querySelector('input[name="display_part"]');
		this.current_tab = displayPartEl.value;

		// responsive menu
		var mobileToggle = this.root.querySelector('.mobile-menu input');
		mobileToggle.addEventListener('change', this.ShowMobileMenuEvent.bind(this));
	}

	InitModeSwitcher() {
		var switcher = document.getElementById('viewmode-toggles');
		var checkbox = switcher.querySelector('input[type="checkbox"]');

		if (null == switcher) {
			return;
		}
		if (this.root.classList.contains('advanced') || checkbox.checked) {
			checkbox.checked = true;
			this.current_mode = 'advanced';
		}
		else {
			checkbox.checked = false;
			this.current_mode = 'simple';
		}
		switcher.addEventListener('change', this.SwitchViewModeEvent.bind(this));
	}

	InitActionEvents() {
		var actions = document.querySelectorAll('[setting-action]');
		for (var i = 0; i < actions.length; i++) {
			var actionElement = actions[i];
			/*if (false === actionElement.hasAttribute('data-function'))
			{
				console.warn('Action without function', actionElement); 
				continue; 
			} */

			var method = actionElement.getAttribute('setting-action');
			if ('undefined' === typeof this[method]) {
				console.error('Method ' + method + ' event is undefined!');
			}
			else {
				actions[i].addEventListener('click', this[method].bind(this));
			}


		}

	}

	InitAiEvents()
	{
			window.addEventListener('shortpixel.ui.settingsTabLoad', this.UpdateAiExample);
			var self = this;

			var triggerEvent = new CustomEvent('shortpixel.ui.settingsTabLoad', { detail: { 
				'tabName' : 'ai', 
			}});

			if (this.current_tab == 'ai')
			{
				window.dispatchEvent(triggerEvent);
		
			}

			var button = document.querySelector('button[name="refresh_ai_preview"]'); 
			button.addEventListener('click', function () {
				 //window.dispatchEvent(triggerEvent);
				 var attach_id = document.querySelector('input[name="ai_preview_image_id"]').value; 
				 var inputs = document.querySelectorAll('#tab-ai input, #tab-ai select, #tab-ai textarea'); 

				 var previewResult = document.querySelector('.preview_wrapper .preview_result'); 

				if (null !== previewResult)
				{
					 previewResult.innerText = self.strings.ai_strings.preview_requested; 
				} 

				 var settingsData = {}; 
				 for (let i = 0; i < inputs.length; i++)
				 {
					let input = inputs[i]; 
					let name = input.name; 
					if ('checkbox' == input.type)
					{
						 if (input.checked)
						 {
							 settingsData[name] = 1
						 }
						 else
						 {
							settingsData[name] = 0; 
						 }
					}
					else
					{
						settingsData[name] = input.value;
					}
					
				 }

				 var data = {
					id: attach_id,
					type: 'media',
					screen_action: 'settings/getNewAiImagePreview',
					settingsData : JSON.stringify(settingsData),
					callback : 'shortpixelSettings.AiImageSet',
					
				}
				window.ShortPixelProcessor.AjaxRequest(data); 

				window.addEventListener('shortpixelSettings.AiImageSet', function (response) {

					var json = response.detail; 
					if (typeof json.aiData == 'undefined')
					{
						if (typeof json.message !== 'undefined')
						{
							previewResult.innerText = json.message;
						}
					}
					else
					{
						window.dispatchEvent(triggerEvent); 
					}
					
				}, {once: true});

			})

			var button = document.querySelector('button[name="open_change_photo"]');
			button.addEventListener('click', function () {

				var mediaFrame = wp.media({
					title: self.strings.ai_strings.imagemodaltitle,
					button: {
						text: self.strings.ai_strings.selectimage, 
					},
					multiple: false // Set to true to allow multiple image selection
				});
		
				// When an image is selected, run a callback
				mediaFrame.on('select', function() {
					var attachment = mediaFrame.state().get('selection').first().toJSON();
					//alert('Selected Image ID: ' + attachment.id); // Show the image ID in an alert
					var data = {
						id: attachment.id,
						type: 'media',
						screen_action: 'settings/setAiImageId',
						callback : 'shortpixelSettings.AiImageSet',
						
					}

					window.ShortPixelProcessor.AjaxRequest(data); 

					window.addEventListener('shortpixelSettings.AiImageSet', function (response) {
						
						window.dispatchEvent(triggerEvent); 
					}, {once: true});



				});
		
				// Open the media library
				mediaFrame.open();
			});

	}

	UpdateAiExample(event)
	{

		if (event.detail.tabName !== 'ai')
		{
			return;
		}

		var data = {
			screen_action: 'settings/getAiExample', 
			type: 'settings', 
			callback: 'shortpixelSettings.getAiExample',
		};


		window.addEventListener('shortpixelSettings.getAiExample', function (response)
		{
			var json = response.detail; 
			
			var elements = ['generated', 'original'];
			var fields = ['filename', 'alt', 'caption', 'description'];
			var currentData = document.querySelector('.current.result_info');
			var generatedData = document.querySelector('.result.result_info');

			var idInput = document.querySelector('input[name="ai_preview_image_id"]'); 
			idInput.value = json.item_id;

			let previewResult = document.querySelector('.preview_wrapper .preview_result'); 
			if (null !== previewResult)
			{
				 previewResult.innerText = ''; 
			} 

			if (json.preview_image)
			{
				var img = document.querySelector('.preview_wrapper img.image_preview'); 
				img.src = json.preview_image;
			}

			for (let i = 0; i < elements.length; i++)
			{
				let name = elements[i]; 
				var dataObject = (name ==  'generated') ? generatedData : currentData;
				
				if (typeof json[name] !== 'undefined')
				{
					let data = json[name];

					for (let j = 0; j < fields.length; j++)
					{
						let field = fields[j]; 
						let element = dataObject.querySelector('.' + field); 
						if (element !== null)
						{
							if (typeof data[field] === 'undefined' || null === data[field] || data[field].length === 0)
							{
								var val = '&nbsp;'; 
							}
							else
							{
								var val = data[field];
							}
							element.innerHTML = val;
						}

					}
						
				}
			}

		}, {once: true});


		// Processor / Screen might not be loaded if the current screen is AI.
		if (null === window.ShortPixelProcessor.screen)
		{
			 addEventListener('shortpixel.screen.loaded', function () {
					window.ShortPixelProcessor.AjaxRequest(data);
			 } );
		}
		else
		{
			window.ShortPixelProcessor.AjaxRequest(data);
		}

	}

	PurgeCacheEvent(event) {
		event.preventDefault();
		var target = event.target;

		var data = {};

		var data = { screen_action: 'settings/purgecdncache' }; //
		data.callback = 'shortpixelSettings.purgeCDNCache';
		data.purge = target.dataset.purge;
		data.type = 'settings';

		window.addEventListener(data.callback, function (response) {
			var json = response.detail;

			let results = json.settings.results;
			//let anchor = document.querySelector('.wp-header-end');
			//let screen = window.ShortPixelProcessor.GetScreen();

			//screen.AppendNotices(json.display_notices, anchor);
			var messageBox = document.getElementById('settings-purge-message');

			messageBox.innerHTML = results.message;
			messageBox.classList.add('opened');

			setTimeout(function () {
				messageBox.innerHTML = '';
				messageBox.classList.remove('opened');

			}, 3000);


		}, { 'once': true });

		window.ShortPixelProcessor.AjaxRequest(data);

	}

	ImportSettingsEvent(event) {
		var data = {};
		var data = { screen_action: 'settings/importexport' }; //
		data.callback = 'shortpixelSettings.importSettings';
		data.type = 'settings';
		data.actionType = 'import';

		var messageBox = document.getElementById('settings-importexport-message');
		messageBox.innerHTML = ''; // wipe previous

		var value = document.getElementById('spio-tools-import').value;
		value = value.trim();

		try {
			var json = JSON.parse(value);
		}
		catch (e) {
			console.error(e);
			var messageNode = document.createElement('p');
			messageNode.classList.add('error');
			messageNode.innerText = e.message;

			messageBox.append(messageNode);
			messageBox.classList.add('opened');
			return;
		}


		data.importData = JSON.stringify(json);

		window.addEventListener(data.callback, function (response) {
			var data = response.detail;

			//	var messageBox = document.getElementById('settings-importexport-message'); 
			//	messageBox.innerHTML = ''; // wipe previous

			let results = (data.settings.results) ? data.settings.results : null;
			if (results) {
				if (true == results.is_error) {
					var messageNode = document.createElement('p');
					messageNode.classList.add('error');
					messageNode.innerText = results.message;

					messageBox.append(messageNode);
					messageBox.classList.add('opened');

				}
				else {
					if (results.messages) {
						messageBox.classList.add('opened');
						for (let i = 0; i < results.messages.length; i++) {
							var messageNode = document.createElement('p');
							messageNode.innerText = results.messages[i];
							messageBox.append(messageNode);
						}
					}
				}


			}

		}, { once: true });

		window.ShortPixelProcessor.AjaxRequest(data);

	}

	ExportSettingsEvent(event) {
		var data = {};
		var data = { screen_action: 'settings/importexport' }; //
		data.callback = 'shortpixelSettings.exportSettings';
		data.type = 'settings';
		data.actionType = 'export';

		window.addEventListener(data.callback, function (response) {
			let data = response.detail;
			if (data.settings && data.settings.exportData) {
				var messageBox = document.getElementById('settings-importexport-message');
				messageBox.innerHTML = ''; // wipe previous

				var messageNode = document.createElement('p');
				messageNode.innerText = data.settings.message;


				var textNode = document.createElement('textarea');
				textNode.classList.add('exportjson');
				textNode.innerText = data.settings.exportData;

				messageBox.append(messageNode);
				messageBox.append(textNode);
				messageBox.classList.add('opened');
				textNode.addEventListener('focus', function () {
					this.select();
				});
			}

		}, { once: true });

		window.ShortPixelProcessor.AjaxRequest(data);


	}

	SwitchViewModeEvent(event) {
		var new_mode = (this.current_mode == 'simple') ? 'advanced' : 'simple';
		var data = {};
		data.type = 'settings';
		data.screen_action = 'settings/changemode';
		data.new_mode = new_mode;

		window.ShortPixelProcessor.AjaxRequest(data);

		this.root.classList.remove('simple', 'advanced');
		this.root.classList.add(new_mode);

		this.current_mode = new_mode;
	}

	SwitchMenuTabEvent(event) {
		event.preventDefault();

		var targetLink = event.target;
		if (typeof targetLink.href === 'undefined');
		{
			targetLink = targetLink.closest('a');
		}
		var uri = targetLink.href;

		// If nothing is provided here.
		if (typeof uri === 'undefined') {
			return;
		}

		var current_tab = this.current_tab;
		var params = new URLSearchParams(uri);
		var new_tab = params.get('part');

		var mobileToggle = this.root.querySelector('.mobile-menu input');
		mobileToggle.checked = false;
		var changeEv = new CustomEvent('change');
		mobileToggle.dispatchEvent(changeEv);

		// If same, do nothing.
		if (current_tab == new_tab) {
			return;
		}

		var newTabEl = this.tab_elements[new_tab];
		if (typeof newTabEl !== 'undefined') {
			newTabEl.classList.add('active');
		}

		var currentTabEl = this.tab_elements[current_tab];
		// Happens when no active tab ( ie just started )
		if (typeof currentTabEl !== 'undefined') {
			currentTabEl.classList.remove('active');
		}

		for (var i = 0; i < this.menu_elements.length; i++) {
			if (this.menu_elements[i].classList.contains('active')) {
				this.menu_elements[i].classList.remove('active');
			}

			if (this.menu_elements[i].dataset.menuLink == new_tab) {
				this.menu_elements[i].classList.add('active');
			}

		}
		// Add active to the new tab.
		// targetLink.classList.add('active');

		this.current_tab = new_tab;
		var displayPartEl = this.root.querySelector('input[name="display_part"]');
		displayPartEl.value = new_tab;

		// Update Uri
		if (uri.indexOf("?") > 0) {
			window.history.replaceState({}, document.title, uri);
		}

		var section = ''; // #todo figure out what the idea of section was
		var event = new CustomEvent('shortpixel.ui.settingsTabLoad', { detail: { tabName: new_tab, section: section } });
		window.dispatchEvent(event);

	}

	ShowMobileMenuEvent(event) {
		event.preventDefault(); // target is checkbox.

		var mobileMenu = this.root.querySelector('label.mobile-menu');
		if (event.target.checked) {
			mobileMenu.classList.add('opened');
			mobileMenu.classList.remove('closed')
		}
		else {
			mobileMenu.classList.add('closed');
			mobileMenu.classList.remove('opened')
		}
	}

	// Elements with data-toggle active
	DoToggleActionEvent(event) {
		event.preventDefault();

		var checkbox = event.target;
		var checkboxes = [];

		checkboxes.push(checkbox);
		var targets = [];

		if (target === null) {
			console.error('Target element ID not found', checkbox, field_id);
			return false;
		}

		// If radio, add all to the event.
		if (checkbox.type === 'radio') {
			var checkboxes = this.root.querySelectorAll('input[name="' + checkbox.name + '"]');
		}

		for (var i = 0; i < checkboxes.length; i++) {
			var checkbox = checkboxes[i];

			var field_id = checkbox.getAttribute('data-toggle');
			var target = document.getElementById(field_id);

			// Allow multiple elements to be toggled, which will not work with id. In due time all should be transferred to use class-based toggle
			// This can return null, in case of radio buttons where only one has a data-toggle set.
			var targetClasses = this.root.querySelectorAll('.' + field_id);

			if (typeof checkbox.dataset.toggleReverse !== 'undefined') {
				var checked = !checkbox.checked;
			}
			else {
				var checked = checkbox.checked;
			}

			var show = false;
			if (checked) {
				show = true;
			}

			if (target !== null) {
				if (show) {
					this.ShowElement([target]);
				}
				else {
					this.HideElement([target]);
				}
			}

			for (var j = 0; j < targetClasses.length; j++) {
				if (show) {
					this.ShowElement([targetClasses[j]]);
				}
				else {
					this.HideElement([targetClasses[j]]);
				}
			}
		} // for

	}

	DoToggleExcludeEvent(event) {
		var checkbox = event.target;

		if (true == checkbox.checked) {
			var excludeInput = this.root.querySelector('input[name="' + checkbox.dataset.exclude + '"]');
			var ev = new CustomEvent('change');
			excludeInput.checked = false;
			excludeInput.dispatchEvent(ev);
		}
	}

	DoToggleDisableEvent(event) {
		let checkbox = event.target;
		let disableTarget = this.root.querySelector('input[name="' + checkbox.dataset.disable + '"]');


		if (null !== disableTarget) {
			let settingParent = disableTarget.closest('setting');

			//disableTarget.classList.add('disabled');
			if (false == checkbox.checked) {
				disableTarget.disabled = true;
				settingParent.classList.add('disabled');
			}
			else {
				disableTarget.disabled = false;
				settingParent.classList.remove('disabled');
			}

		}

	}

	DoToggleHideWarningEvent(event) {
		var checkbox = event.target;
		var setting = checkbox.closest('setting');

		if (false == checkbox.checked) {
			var warnings = setting.querySelectorAll('warning');
			if (null !== warnings) {
				this.HideElement(warnings);
			}
		}
	}

	ShowElement(elems) {

		for (var i = 0; i < elems.length; i++) {
			var element = elems[i];
			element.classList.add('is-visible'); // Make the element visible

			// Once the transition is complete, remove the inline max-height so the content can scale responsively
			window.setTimeout(function () {
				element.style.opacity = 1;
			}, 150);

		}

	};

	// Hide an element
	HideElement(elems) {

		for (var i = 0; i < elems.length; i++) {
			var element = elems[i];

			element.style.opacity = 0;
			// When the transition is complete, hide it
			window.setTimeout(function (el) {
				el.classList.remove('is-visible');

			}, 300, element);
		}

	};

	FormSendEvent(event) {
		event.preventDefault();

		var form = event.target;
		var formData = new FormData(event.target, event.submitter);

		if (this.save_in_progress) {
			return false;
		}

		this.save_in_progress = true;

		var saveButtons = this.root.querySelector('.setting-tab.active .save-buttons');
		if (saveButtons !== null) {
			saveButtons.classList.add('saving');
		}

		formData.append('screen_action', 'form_submit');
		formData.append('form-nonce', formData.get('nonce'));

		// Special Actions
		let formaction_parsed = URL.parse(form.action);
		if (formaction_parsed.searchParams && formaction_parsed.searchParams.has('sp-action')) {
			formData.set('screen_action', formaction_parsed.searchParams.get('sp-action'));
		}

		this.DoAjaxRequest(formData, this.FormResponseEvent).then((json) => {
			this.FormResponseEvent(json);
		});
	}


	async DoAjaxRequest(formData, responseOkCallBack, responseErrorCallback) {

		formData.append('action', 'shortpixel_settingsRequest');
		formData.append('ajaxSave', 'true');

		formData.append('request_url', window.location.toString());

		if (false === formData.has('nonce')) {
			formData.append('nonce', ShortPixelProcessorData.nonce_settingsrequest);
		}

		const url = ShortPixel.AJAX_URL;

		if (typeof responseOkCallBack !== 'function') {
			responseOkCallBack = (response) => { console.log(response); };
		}
		if (typeof responseErrorCallback !== 'function') {
			responseErrorCallback = (response) => { console.error(response) };
		}


		var response = await fetch(url, {
			method: 'POST',
			body: formData
		});


		json = null;
		var json;
		if (response.ok) {
			json = await response.json();
			return json;

		}


	}

	FormResponseEvent(json) {
		let saveDialog = document.querySelector('.ajax-save-done');
		var noticeLine = saveDialog.querySelector('.after-save-notices');
		this.save_in_progress = false;

		var saveButtons = this.root.querySelector('.setting-tab.active .save-buttons');
		if (saveButtons !== null) {
			saveButtons.classList.remove('saving');
		}


		if (json.redirect) {
			if (json.redirect == 'reload') {
				window.location.reload();
			}
			else {
				window.location.href = json.redirect;
			}
		}

		if (json.notices && json.notices.length > 0) {
			var notice_count = saveDialog.querySelector('.notice_count');
			notice_count.textContent = json.notices.length;
			noticeLine.classList.remove('shortpixel-hide');
		}
		else {
			noticeLine.classList.add('shortpixel-hide');
		}
		if (json.display_notices) {

			let anchor = document.querySelector('.wp-header-end');
			let screen = window.ShortPixelProcessor.GetScreen();

			screen.AppendNotices(json.display_notices, anchor);
			/*					for (let i = 0; i < json.display_notices.length; i++)
								{
									anchor.insertAdjacentHTML('afterend', json.display_notices[i]);
								} */
		}

		// Remove old messages 
		var fieldMessages = document.querySelectorAll(['.fieldmessage']).forEach(e => e.remove());
		/*for(let i = 0; i < fieldMessages.length; i++)
		{

		} */

		if (json.returnFormData) {
			for (let i = 0; i < json.returnFormData.length; i++) {
				var fieldData = json.returnFormData[i];
				var fieldName = fieldData.field;

				var fieldObj = document.querySelector('input[name="' + fieldName + '"]');
				fieldObj.value = fieldData.new_value;

				var newEl = document.createElement('info');
				newEl.classList.add('fieldmessage', 'updated');
				newEl.innerHTML = fieldData.message;

				if (fieldData.hook_query) {
					var hookElement = document.querySelector(fieldData.hook_query);
					hookElement.after(newEl);
				}
				else {
					fieldObj.after(newEl);
				}


			}
		}

		saveDialog.classList.add('show');

		window.setTimeout(function () {
			saveDialog.classList.remove('show')
		}, 2000);
	}



	DashBoardWarningEvent(warning, matches) {

		var dashBox = warning[0];
		var status = (true === matches.allMatches) ? 'alert' : (true === matches.someMatch) ? 'warning' : 'ok';

		let panelName;
		if (dashBox.classList.contains('dashboard-optimize')) {
			panelName = 'optimize';
		}
		else
			panelName = 'webp';

		this.dashboard_status[panelName] = status;

		dashBox.classList.remove('ok', 'alert', 'warning');
		dashBox.classList.add(status)

		// Remove all status-lines ( rebuild )
		var statusWrapper = dashBox.querySelector('.status-wrapper');
		if (null === statusWrapper) {
			console.error('issue with statuswrapper');
			return;
		}
		Array.from(statusWrapper.children).forEach(e => e.remove());


		var statusIcon = document.createElement('i');
		var linesAdded = [];

		statusIcon.classList.add('shortpixel-icon', 'static-icon', status);


		if (matches.matches.length > 0) {
			for (var i = 0; i < matches.matches.length; i++) {
				var input = matches.matches[i];
				var statusLine = document.createElement('span');
				var duplicate = false;
				statusLine.classList.add('status-line');

				if (input.dataset.dashboard) {
					let line = input.dataset.dashboard;
					if (linesAdded.indexOf(line) == -1) {
						statusLine.textContent = line;
						linesAdded.push(line);
					}
					else {
						continue; // skip this one.
					}
				}
				else {
					var linestring = this.strings.dashboard_strings[status];
					statusLine.textContent = linestring;
				}

				statusWrapper.appendChild(statusLine).appendChild(statusIcon.cloneNode());

			}
			// Add Not ok status.
		}
		else {
			// Add OK status
			var statusLine = document.createElement('span');
			statusLine.classList.add('status-line');
			var linestring = this.strings.dashboard_strings[status];
			statusLine.textContent = linestring;

			statusWrapper.appendChild(statusLine).appendChild(statusIcon);
		}

		// Button display
		var button = dashBox.querySelector('button,.dashboard-button');
		if (null === button) {
			console.error('dash button not found');
			return;
		}

		if ('ok' === status) {
			if (false === button.classList.contains('not-visible')) {
				button.classList.add('not-visible');
			}
		}
		else if (true === button.classList.contains('not-visible')) {
			button.classList.remove('not-visible');
		}

		this.UpdateDashBoardMainBlock();
	}

	CDNCheckWarningEvent(warning, matches, elements) {
		// If useCDN, or the other one is selected, pass this off as ok.
		// Matches are the ones, who are -NOT- selected, ie not-preferable status.
		var matchinputs = matches.matches;

		var hasCreate = false;
		var hasDelivery = false;

		for (var i = 0; i < matchinputs.length; i++) {
			switch (matchinputs[i].name) {
				case 'createWebp':
				case 'createAvif':
					hasCreate = true;
					break;
				case 'useCDN':
				case 'deliverWebp':
					hasDelivery = true;
					break;
			}
		}

		// All fine, but dashboardevent expects a 'negative', so any, all match should be false.
		if (true == hasCreate && true == hasDelivery) {
			matches.someMatch = false;
			matches.allMatches = false;
			matches.matches;
			matchinputs = Array.from(elements); // equal matchinput to elements, not to trigger too much texts
		}
		else if (false == hasCreate && false == hasDelivery) // Boo alert, allMatch should true.
		{
			matches.allMatches = true;
		}
		else { // one of the other is true.
			matches.someMatch = true;
		}

		// Now we have to go through all the elements, to find the ones unselected, because they rule the message being send on the dashboard. So those are the matches we must put to dashboard event.
		var elements = Array.from(elements);
		var to_splice = [];
		for (var i = 0; i < elements.length; i++) {
			var el = elements[i];
			var res = matchinputs.find(node => node.isEqualNode(el));
			var name = elements[i].name;

			// Dirty exceptions
			if (typeof res !== 'undefined' ||
				(true == hasCreate && (name == 'createAvif' || name == 'createWebp')) ||
				(true == hasDelivery && (name == 'useCDN' || name == 'deliverWebp'))
			) {
				to_splice.push(i); // no live splicing, because it messed the indexes
			}
		}

		// Funky function I found online to filter the splicers from the elements.
		elements = elements.filter((value, index) => to_splice.indexOf(index) == -1);

		matches.matches = elements;

		this.DashBoardWarningEvent(warning, matches);
	}

	UpdateDashBoardMainBlock() {
		var ok = true;

		for (const [key, value] of Object.entries(this.dashboard_status)) {
			if (value !== 'ok') {
				ok = false;
			}
		}

		var mainBlock = this.root.querySelector('.panel.first-panel .first-line');


		if (ok && false == mainBlock.classList.contains('ok')) {
			mainBlock.classList.remove('warning');
			mainBlock.classList.add('ok');
		}
		else if (false == ok && false == mainBlock.classList.contains('warning')) {
			mainBlock.classList.add('warning');
			mainBlock.classList.remove('ok');
		}

	}

	OpenModalEvent(elem) {
		var target = elem.target;
		var targetElem = document.getElementById(target.dataset.target);
		if (!targetElem)
			return;

		var shade = document.getElementById('spioSettingsModalShade');
		var modal = document.getElementById('spioSettingsModal');

		shade.style.display = 'block';
		modal.classList.remove('spio-hide');

		var body = modal.querySelector('.spio-modal-body');
		body.innerHTML = ('afterbegin', targetElem.innerHTML); //.cloneNode()
		body.style.background = '#fff';
		shade.addEventListener('click', this.CloseModal.bind(this), { 'once': true });

		modal.querySelector('.spio-close-help-button').addEventListener('click', this.CloseModal.bind(this), { 'once': true });

		if (body.querySelector('[data-action="ajaxrequest"]') !== null) {
			body.querySelector('[data-action="ajaxrequest"]').addEventListener('click', this.SendModal.bind(this));
		}

	}

	CloseModal(elem) {
		var shade = document.getElementById('spioSettingsModalShade');
		var modal = document.getElementById('spioSettingsModal');

		shade.style.display = 'none';
		modal.classList.add('spio-hide');

	}

	SendModal(elem) {
		var modal = document.getElementById('spioSettingsModal');
		var body = modal.querySelector('.spio-modal-body');
		var inputs = body.querySelectorAll('input');

		var data = {};
		var validated = true;

		for (var i = 0; i < inputs.length; i++) {
			data[inputs[i].name] = inputs[i].value;
			if (typeof inputs[i].dataset.required !== 'undefined') {
				if (inputs[i].value !== inputs[i].dataset.required) {
					inputs[i].style.border = '1px solid #ff0000';
					validated = false;
					return false;
				}
			}
		}

		if (!validated)
			return false;

		data.callback = 'shortpixelSettings.receiveModal'
		data.type = 'settings';

		window.addEventListener('shortpixelSettings.receiveModal', this.ReceiveModal.bind(this), { 'once': true });

		window.ShortPixelProcessor.AjaxRequest(data);

	}

	ReceiveModal(elem) {
		if (typeof elem.detail.settings.results !== 'undefined') {
			var modal = document.getElementById('spioSettingsModal');
			var body = modal.querySelector('.spio-modal-body');

			body.innerHTML = elem.detail.settings.results;
		}

		if (typeof elem.detail.settings.redirect !== 'undefined') {
			window.location.href = elem.detail.settings.redirect;
		}

	}

	SaveOnKey() {

		var saveForm = document.getElementById('wp_shortpixel_options');
		if (saveForm === null)
			return false; // no form no save.


		window.addEventListener('keydown', function (event) {

			if (!(event.key == 's' || event.key == 'S') || !event.ctrlKey) {
				return true;
			}

			let submitButton = document.getElementById('save');
			saveForm.requestSubmit(submitButton);
			event.preventDefault();
			return false;
		}.bind(this));
	}

	NewExclusionShowInterfaceEvent(event) {
		this.ResetExclusionInputs();
		event.preventDefault();

		var element = this.root.querySelector('.new-exclusion');
		element.classList.remove('not-visible', 'hidden');

		var cancelButton = this.root.querySelector('.new-exclusion .button-actions button[name="cancelEditExclusion"]');
		cancelButton.classList.remove('not-visible', 'hidden');

		var updateButton = this.root.querySelector('.new-exclusion .button-actions button[name="updateExclusion"]');

		if (event.target.name == 'addNewExclusion') {
			var mode = 'new';
			var id = 'new';
			var title = this.root.querySelector('.new-exclusion h3.new-title');
			var button = this.root.querySelector('.new-exclusion .button-actions button[name="addExclusion"]');
			button.classList.remove('hidden', 'not-visible');
		}
		else {
			var mode = 'edit';

			let mainEl = event.target.closest('li');
			var id = mainEl.id;


			var exclusionModal = this.root.querySelector('.new-exclusion');
			//	event.target.closest('li').after(exclusionModal);
			//exclusionModal.parentElement = event.target.closest('li').after(exclusionModal);

			var title = this.root.querySelector('.new-exclusion h3.edit-title');
			//var button = this.root.querySelector('.new-exclusion .button-actions button[name="removeExclusion"]');
			var input = this.root.querySelector('.new-exclusion input[name="edit-exclusion"]')

			updateButton.classList.remove('not-visible', 'hidden');

			input.value = id;
			var dataElement = event.target.closest('li').querySelector('input').value;
			var data = JSON.parse(dataElement);
			this.ReadWriteExclusionForm(data)

		}

		title.classList.remove('not-visible', 'hidden');
		//button.classList.remove('not-visible', 'hidden');

	}

	//** When compressiontype changes, also update the information
	CompressionTypeChangeEvent(event) {
		var target = event.target;
		var className = target.className;

		var elements = this.root.querySelectorAll('.shortpixel-compression .settings-info');
		for (var i = 0; i < elements.length; i++) {
			var element = elements[i];
			element.style.display = 'none';
			if (element.classList.contains(className)) {
				element.style.display = 'inline-block';
			}
		}

	}

	HideExclusionInterface() {
		let element = this.root.querySelector('.new-exclusion');
		element.classList.add('not-visible');

		let notValidated = element.querySelectorAll('.not-validated');
		for (let i = 0; i < notValidated.length; i++) {
			notValidated[i].classList.remove('not-validated');
		}

		if (notValidated.length > 0) {
			let message = element.querySelector('.validation-message');
			message.classList.add('not-visible');
		}

	}

	// EXCLUSIONS - this is not conclusive, some elements have direct events .  This needs some brushing up to make more consistent.
	NewExclusionUpdateEvent(event) {
		var target = event.target;
		if (typeof target.name === 'undefined') {
			var target = target.parentElement;
		}
		var inputName = target.name;


		switch (inputName) {
			case 'exclusion-type':
				this.NewExclusionUpdateType(target);
				break;
			case 'apply-select':
				this.NewExclusionUpdateThumbType(target);
				break;
			case 'addExclusion':
				this.NewExclusionButtonAdd(target);
				break;
			case 'exclusion-exactsize':
				this.NewExclusionToggleSizeOption(target);
				break;
			case 'removeExclusion':
				this.RemoveExclusion(target);
				break;
			case 'cancelEditExclusion':
				this.HideExclusionInterface();
				break;
			case 'updateExclusion':
				this.UpdateExclusion();
				break;

		}
	}

	NewExclusionUpdateType(element) {
		var value = element.value;
		var selected = element.options[element.selectedIndex];
		var example = selected.dataset.example;
		if (typeof example == 'undefined') {
			example = '';
		}

		var valueOption = this.root.querySelector('.new-exclusion .value-option');
		var sizeOption = this.root.querySelector('.new-exclusion .size-option');
		var regexOption = this.root.querySelector('.regex-option');
		var switchExactOption = this.root.querySelector('.exact-option');


		if (value == 'size') {
			valueOption.classList.add('not-visible');
			sizeOption.classList.remove('not-visible');
			switchExactOption.classList.remove('not-visible');
			regexOption.classList.add('not-visible');
		}
		else {
			valueOption.classList.remove('not-visible');
			sizeOption.classList.add('not-visible');
			switchExactOption.classList.add('not-visible');
			regexOption.classList.remove('not-visible');
		}

		var valueInput = this.root.querySelector('input[name="exclusion-value"]');
		if (null !== valueInput) {
			valueInput.placeholder = example;
		}
	}

	NewExclusionUpdateThumbType(element) {
		var value = element.value;

		var thumbSelect = this.root.querySelector('div.thumbnail-select');
		if (null === thumbSelect) {
			console.error('Something wrong with the thumbnails selector');
			return false;
		}

		if (value == 'selected-thumbs') {
			thumbSelect.classList.remove('not-visible');
		}
		else {
			thumbSelect.classList.add('not-visible');
		}
	}


	ReadWriteExclusionForm(setting) {
		// compile all inputs to a json encoded string to add to UX
		if (null === setting || typeof setting === 'undefined') {
			var setting = {
				'type': '',
				'value': '',
				'apply': '',
			};

			var mode = 'read';
		}
		else {
			var mode = 'write';
		}

		var strings = {};

		var typeOption = this.root.querySelector('.new-exclusion select[name="exclusion-type"]');
		var valueOption = this.root.querySelector('.new-exclusion input[name="exclusion-value"]');
		var applyOption = this.root.querySelector('.new-exclusion select[name="apply-select"]');
		var regexOption = this.root.querySelector('.new-exclusion input[name="exclusion-regex"]');

		if ('read' === mode) {
			setting.type = typeOption.value;
			setting.value = valueOption.value;
			setting.apply = applyOption.value;
			setting.validated = true;

			strings.type = typeOption.options[typeOption.selectedIndex].innerText;
			strings.apply = applyOption.options[applyOption.selectedIndex].innerText;
		}
		else {
			if (setting.type && setting.type.indexOf('regex') != -1) {
				typeOption.value = setting.type.replace('regex-', '');
			}
			else {
				typeOption.value = setting.type;
			}
			valueOption.value = setting.value;
			applyOption.value = setting.apply;
		}

		// When selected thumbnails option is selected, add the thumbnails to the list.
		if ('selected-thumbs' == applyOption.value) {
			var thumbOptions = this.root.querySelectorAll('.new-exclusion input[name="thumbnail-select[]"]');
			var thumblist = [];
			if ('read' === mode) {
				for (var i = 0; i < thumbOptions.length; i++) {
					if (thumbOptions[i].checked == true) {
						thumblist.push(thumbOptions[i].value);
					}
				}
				setting.thumblist = thumblist;
			}
			else if ('write' === mode) {
				for (var i = 0; i < thumbOptions.length; i++) {
					if (setting.thumblist.indexOf(thumbOptions[i].value) != -1) {
						thumbOptions[i].checked = true;
					}
				}

				this.NewExclusionUpdateThumbType(applyOption);
			}
		}

		// Check for regular expression active on certain types
		if ('read' === mode && true === regexOption.checked && (typeOption.value == 'name' || typeOption.value == 'path')) {
			setting.type = 'regex-' + setting.type;
		}
		else if ('write' === mode) {
			if (setting.type && setting.type.indexOf('regex') != -1) {
				regexOption.checked = true;
			}
		}

		var validateInput = [];

		// Options for size setting
		if ('size' === setting.type) {
			var exactOption = this.root.querySelector('.new-exclusion input[name="exclusion-exactsize"]');

			var width = this.root.querySelector('.new-exclusion input[name="exclusion-width"]');
			var height = this.root.querySelector('.new-exclusion input[name="exclusion-height"]');

			var minwidth = this.root.querySelector('.new-exclusion input[name="exclusion-minwidth"]');
			var maxwidth = this.root.querySelector('.new-exclusion input[name="exclusion-maxwidth"]');
			var minheight = this.root.querySelector('.new-exclusion input[name="exclusion-minheight"]');
			var maxheight = this.root.querySelector('.new-exclusion input[name="exclusion-maxheight"]');

			if ('read' === mode) {
				if (true === exactOption.checked) {
					setting.value = width.value + 'x' + height.value;

					validateInput.push(width, height);
				}
				else {
					setting.value = minwidth.value + '-' + maxwidth.value + 'x' + minheight.value + '-' + maxheight.value;
					validateInput.push(minwidth, maxwidth, minheight, maxheight);

				}
			}
			else if ('write' === mode) {
				var value = setting.value;
				var split = value.split(/(x|×|X)/);

				if (value.indexOf('-') === -1) {
					exactOption.checked = true;
					width.value = split[0]; // in this split 1 is the X symbol
					height.value = split[2];
				}
				else {
					var widths = split[0].split('-'); // split the split for widths
					var heights = split[2].split('-');

					minwidth.value = widths[0];
					maxwidth.value = widths[1];

					minheight.value = heights[0];
					maxheight.value = heights[1];
				}

				this.NewExclusionUpdateType(typeOption)
				//		this.NewExclusionToggleSizeOption(exactOption);
			}
			this.NewExclusionToggleSizeOption(exactOption);

		}
		else {
			validateInput.push(valueOption);
		}


		// // Problem - with validatation, must note which field is not validated (1) and secondly value must be valited as string, while the sizes should be numbers.
		setting.validated = this.DoValidateInputs(validateInput);

		if ('read' === mode) {
			return [setting, strings];
		}
	}

	DoValidateInputs(inputs) {
		var validated = true;
		for (let i = 0; i < inputs.length; i++) {
			let item = inputs[i];
			let type = item.type;
			let value = item.value;

			if (type == 'number' && (value.length <= 0 || isNaN(value))) {
				item.classList.add('not-validated');
				validated = false;
				// break;
			}
			else if (value.length <= 0) {
				item.classList.add('not-validated');

				validated = false;
				//	break;
			}
			else if (item.classList.contains('not-validated')) {
				item.classList.remove('not-validated');
			}
		};

		// Validate.

		let validationMessage = this.root.querySelector('.validation-message');
		if (false === validated) {
			validationMessage.classList.remove('not-visible');
		}
		else {
			validationMessage.classList.add('not-visible');
		}

		return validated;
	}


	// Function to add an exclusion to the interface.
	NewExclusionButtonAdd(target, update) {
		var result = this.ReadWriteExclusionForm(null);

		var setting = result[0];
		var strings = result[1];

		if (false == setting.validated) {
			return false;
		}

		var listElement = this.root.querySelector('.exclude-list');

		if (typeof update === 'undefined') {
			var newIndexInput = document.getElementById('new-exclusion-index');
			var newIndex = parseInt(newIndexInput.value) + 1;
			newIndexInput.value = newIndex;
			var newIndexString = 'id="exclude-' + newIndex + '"';
		}
		else {
			var newIndexString = 'id="' + update + '"';
		}

		var input_value = JSON.stringify(setting);

		var noItemsItem = this.root.querySelector('.exclude-list .no-exclusion-item');
		var itemClass = '';
		var title = '';
		/*if (noItemsItem !== null)
		  {
				itemClass = 'not-visible';
		} */

		if (setting.type && setting.type.indexOf('regex') != -1) {
			itemClass += ' is-regex';
		}

		var format = document.getElementById('exclusion-format').innerHTML;

		var sprintf = (str, ...argv) => !argv.length ? str :
			sprintf(str = str.replace(sprintf.token || "$", argv.shift()), ...argv);
		sprintf.token = '%s';

		//  $class, $title, $exclude_id, $option_code, $field_name, $value, $apply_name, '', 'Yesno'
		var newHTML = sprintf(format, 'class="' + itemClass + '"', title, newIndexString, input_value, strings.type, setting.value, strings.apply, '', '');

		var newHTML = this.DecodeHtmlEntities(newHTML);

		if (typeof update !== 'undefined') {
			let updateEl = listElement.querySelector('#' + update);
			updateEl.outerHTML = newHTML;
		}
		else {
			listElement.insertAdjacentHTML('beforeend', newHTML);
		}

		if (typeof update === 'undefined') {
			var newElement = listElement.querySelector('#exclude-' + newIndex);
		}
		else {
			var newElement = listElement.querySelector('#' + update);
		}

		var editButton = newElement.querySelector('i.edit');
		editButton.addEventListener('click', this.NewExclusionShowInterfaceEvent.bind(this));

		newElement.addEventListener('click', this.NewExclusionShowInterfaceEvent.bind(this));

		var removeButton = newElement.querySelector('i.remove');
		removeButton.addEventListener('click', this.RemoveExclusion.bind(this));


		this.ResetExclusionInputs();
		this.HideExclusionInterface();
		this.ShowExclusionSaveWarning();
	}

	DecodeHtmlEntities(str) {
		const entities = {
			'&lt;': '<',
			'&gt;': '>',
			'&amp;': '&',
			'&quot;': '"',
			'&apos;': "'"
		};

		return str.replace(/&[a-zA-Z0-9#]+;/g, (match) => entities[match] || match);
	}



	NewExclusionToggleSizeOption(target) {
		var sizeOptionRange = this.root.querySelector('.new-exclusion .size-option-range');
		var sizeOptionExact = this.root.querySelector('.new-exclusion .size-option-exact');

		if (true === target.checked) {
			sizeOptionRange.classList.add('not-visible');
			sizeOptionExact.classList.remove('not-visible');
		}
		else {
			sizeOptionRange.classList.remove('not-visible');
			sizeOptionExact.classList.add('not-visible');
		}
	}

	ResetExclusionInputs() {
		var typeOption = this.root.querySelector('.new-exclusion select[name="exclusion-type"]');
		var valueOption = this.root.querySelector('.new-exclusion input[name="exclusion-value"]');
		var applyOption = this.root.querySelector('.new-exclusion select[name="apply-select"]');

		var inputs = this.root.querySelectorAll('.new-exclusion input, .new-exclusion select');
		for (var i = 0; i < inputs.length; i++) {
			var input = inputs[i];
			if (input.tagName == 'SELECT') {
				input.selectedIndex = 0;
			}
			else if (input.type == 'checkbox') {
				input.checked = false;
			}
			else {
				input.value = '';
			}
		}

		var ev = new CustomEvent('change');
		typeOption.dispatchEvent(ev);
		applyOption.dispatchEvent(ev);

		// reset title and buttons.
		var titles = this.root.querySelectorAll('.new-exclusion h3');
		var buttons = this.root.querySelectorAll('.new-exclusion .button-actions button');

		for (var i = 0; i < titles.length; i++) {
			titles[i].classList.add('not-visible', 'hidden');
		}

		for (var i = 0; i < buttons.length; i++) {
			buttons[i].classList.add('not-visible', 'hidden');
		}

		var exactOption = this.root.querySelector('.new-exclusion input[name="exclusion-exactsize"]');
		exactOption.checked = false

		this.NewExclusionToggleSizeOption(exactOption);

	}

	UpdateExclusion() {
		var id = this.root.querySelector('.new-exclusion input[name="edit-exclusion"]');

		this.NewExclusionButtonAdd(null, id.value);

	}

	ShowExclusionSaveWarning() {
		var reminder = this.root.querySelector('.exclusion-save-reminder');
		if (reminder) {
			reminder.classList.remove('hidden');
		}
	}

	RemoveExclusion(event) {
		event.preventDefault();
		var target = event.target;
		var element = target.closest('li');
		element.remove();

		this.ShowExclusionSaveWarning();
	}

	ToggleApiFieldEvent(event) {
		event.preventDefault();

		var apiKeyField = this.root.querySelector('input[name="apiKey"]');
		if (apiKeyField.type == 'password') {
			apiKeyField.type = 'text';
		}
		else {
			apiKeyField.type = 'password';
		}

	}


} // SPSettings  class


document.addEventListener("DOMContentLoaded", function () {
	var s = new ShortPixelSettings();
	s.Init();
});
