(function (window, document) {
	'use strict';

	var ACTIVE_KEY = 'ep_notation_active';
	var ITEM_SETTING_KEYS = [
		'ep_notation_select_type',
		'ep_notation_custom_selector',
		'ep_notation_type',
		'ep_notation_bracket_on',
		'ep_notation_color',
		'ep_notation_stroke_width',
		'ep_notation_infinity_loop',
		'ep_notation_anim_duration',
		'ep_notation_loop_delay',
		'ep_notation_waypoint_offset'
	];

	var editorChangeBound = false;
	var editorBindRetryTimer = null;
	var elementUpdateTimers = {};
	var rerunTimer = null;
	var previewHooksBound = false;

	function getPreviewDocument() {
		var iframe = document.querySelector('#elementor-preview-iframe');

		if (iframe && iframe.contentDocument) {
			return iframe.contentDocument;
		}

		if (window.elementor && window.elementor.$preview && window.elementor.$preview[0]) {
			iframe = window.elementor.$preview[0];
			return iframe.contentDocument || null;
		}

		return null;
	}

	function getPreviewWindow() {
		var previewDocument = getPreviewDocument();

		return previewDocument && previewDocument.defaultView ? previewDocument.defaultView : null;
	}

	function unwrapAtomicValue(value) {
		if (value && 'object' === typeof value && Object.prototype.hasOwnProperty.call(value, 'value')) {
			return unwrapAtomicValue(value.value);
		}

		return value;
	}

	function isTruthy(value) {
		value = unwrapAtomicValue(value);

		return true === value || 'yes' === value || 1 === value || '1' === value;
	}

	function normalizeSettings(settings) {
		if (!settings) {
			return {};
		}

		if ('function' === typeof settings.toJSON) {
			return settings.toJSON();
		}

		if (settings.attributes && 'object' === typeof settings.attributes) {
			return settings.attributes;
		}

		return settings;
	}

	function getSettingValue(settings, key) {
		if (!settings) {
			return null;
		}

		if ('function' === typeof settings.get) {
			return settings.get(key);
		}

		settings = normalizeSettings(settings);

		return settings ? settings[key] : null;
	}

	function getElementContainer(elementId) {
		if (!window.elementor || !elementId) {
			return null;
		}

		if ('function' === typeof window.elementor.getContainer) {
			return window.elementor.getContainer(elementId);
		}

		if (window.elementor.elements && 'function' === typeof window.elementor.elements.find) {
			return window.elementor.elements.find(function (model) {
				return model && model.get && model.get('id') === elementId;
			}) || null;
		}

		return null;
	}

	function getElementSettings(elementId) {
		var container = getElementContainer(elementId);
		var settings;

		if (!container) {
			return null;
		}

		if (container.model && 'function' === typeof container.model.get) {
			settings = container.model.get('settings') || {};
			return normalizeSettings(settings);
		}

		if ('function' === typeof container.get) {
			settings = container.get('settings') || {};
			return normalizeSettings(settings);
		}

		return null;
	}

	function getElementId(element) {
		if (!element || !element.closest) {
			return null;
		}

		var closestElement = element.closest('.elementor-element[data-id]');

		return closestElement ? closestElement.getAttribute('data-id') : null;
	}

	function escapeAttributeValue(value) {
		if (window.CSS && window.CSS.escape) {
			return window.CSS.escape(value);
		}

		return String(value).replace(/"/g, '\\"');
	}

	function getPreviewElement(elementId) {
		var previewDocument = getPreviewDocument();
		var safeId;

		if (!previewDocument || !elementId) {
			return null;
		}

		safeId = escapeAttributeValue(elementId);

		return previewDocument.querySelector('.elementor-element[data-id="' + safeId + '"]');
	}

	function normalizeSliderField(value, defaultSize) {
		var unwrapped = unwrapAtomicValue(value);

		if (unwrapped && 'object' === typeof unwrapped && Object.prototype.hasOwnProperty.call(unwrapped, 'size')) {
			var size = parseFloat(unwrapped.size);

			return {
				size: isNaN(size) ? defaultSize : size,
				unit: 'string' === typeof unwrapped.unit ? unwrapped.unit : 'px'
			};
		}

		var numeric = parseFloat(unwrapped);

		return {
			size: isNaN(numeric) ? defaultSize : numeric,
			unit: 'px'
		};
	}

	function getString(value, fallback) {
		var unwrapped = unwrapAtomicValue(value);

		return 'string' === typeof unwrapped && '' !== unwrapped ? unwrapped : fallback;
	}

	function finalizeListItem(item) {
		item = Object.assign({
			ep_notation_select_type: 'widget',
			ep_notation_custom_selector: '',
			ep_notation_type: 'underline',
			ep_notation_bracket_on: 'left,right',
			ep_notation_color: '#f23427',
			ep_notation_infinity_loop: ''
		}, item || {});

		item.ep_notation_stroke_width = normalizeSliderField(item.ep_notation_stroke_width, 1);
		item.ep_notation_anim_duration = normalizeSliderField(item.ep_notation_anim_duration, 800);
		item.ep_notation_loop_delay = normalizeSliderField(item.ep_notation_loop_delay, 5000);
		item.ep_notation_infinity_loop = isTruthy(item.ep_notation_infinity_loop) ? 'yes' : '';
		item.ep_notation_select_type = getString(item.ep_notation_select_type, 'widget') || 'widget';
		item.ep_notation_type = getString(item.ep_notation_type, 'underline') || 'underline';
		item.ep_notation_color = getString(item.ep_notation_color, '#f23427') || '#f23427';
		item.ep_notation_bracket_on = getString(item.ep_notation_bracket_on, 'left,right') || 'left,right';
		item.ep_notation_custom_selector = getString(item.ep_notation_custom_selector, '') || '';
		item.ep_notation_waypoint_offset = getString(item.ep_notation_waypoint_offset, '') || '';

		return item;
	}

	function buildSingleItemFromSettings(settings) {
		var item = {};
		var index;

		settings = normalizeSettings(settings);

		for (index = 0; index < ITEM_SETTING_KEYS.length; index++) {
			item[ITEM_SETTING_KEYS[index]] = getSettingValue(settings, ITEM_SETTING_KEYS[index]);
		}

		return finalizeListItem(item);
	}

	function isNotationEnabled(settings) {
		settings = normalizeSettings(settings);

		if (!settings) {
			return false;
		}

		if (isTruthy(getSettingValue(settings, ACTIVE_KEY))) {
			return true;
		}

		return isTruthy(settings.ep_notation_active) &&
			Array.isArray(settings.ep_notation_list) &&
			settings.ep_notation_list.length > 0;
	}

	function hasNotationControl(settings) {
		settings = normalizeSettings(settings);

		if (!settings) {
			return false;
		}

		if (Object.prototype.hasOwnProperty.call(settings, ACTIVE_KEY) || Object.prototype.hasOwnProperty.call(settings, 'ep_notation_list')) {
			return true;
		}

		return ITEM_SETTING_KEYS.some(function (key) {
			return Object.prototype.hasOwnProperty.call(settings, key);
		});
	}

	function normalizeNotationPayload(settings) {
		var normalizedSettings = normalizeSettings(settings);

		if (!normalizedSettings || !isTruthy(getSettingValue(normalizedSettings, ACTIVE_KEY))) {
			return null;
		}

		return {
			active: 'yes',
			list: Array.isArray(normalizedSettings.ep_notation_list) && normalizedSettings.ep_notation_list.length
				? normalizedSettings.ep_notation_list.map(function (item) {
					return finalizeListItem(item);
				})
				: [buildSingleItemFromSettings(normalizedSettings)]
		};
	}

	function rerunPreviewNotation(attempt) {
		attempt = attempt || 0;

		if (rerunTimer) {
			window.clearTimeout(rerunTimer);
		}

		rerunTimer = window.setTimeout(function () {
			rerunTimer = null;

			var previewWindow = getPreviewWindow();

			if (previewWindow && 'function' === typeof previewWindow.epRunAtomicNotationFallback) {
				previewWindow.epRunAtomicNotationFallback();
				return;
			}

			if (attempt < 12) {
				rerunPreviewNotation(attempt + 1);
			}
		}, attempt === 0 ? 120 : 250);
	}

	function syncElementNotationData(elementId, settings) {
		var elementWrapper = getPreviewElement(elementId);
		var payload;
		var encodedPayload;
		var currentPayload;

		if (!elementId || !elementWrapper) {
			return;
		}

		payload = normalizeNotationPayload(settings || getElementSettings(elementId));

		if (payload) {
			encodedPayload = JSON.stringify(payload);
			currentPayload = elementWrapper.getAttribute('data-ep-notation');

			if (currentPayload !== encodedPayload) {
				elementWrapper.setAttribute('data-ep-notation', encodedPayload);
			}

			rerunPreviewNotation();
			return;
		}

		if (elementWrapper.hasAttribute('data-ep-notation')) {
			elementWrapper.removeAttribute('data-ep-notation');
			elementWrapper.querySelectorAll('.rough-annotation').forEach(function (node) {
				node.remove();
			});
			rerunPreviewNotation();
		}
	}

	function scheduleElementUpdate(elementId, settings) {
		if (!elementId) {
			return;
		}

		if (elementUpdateTimers[elementId]) {
			window.clearTimeout(elementUpdateTimers[elementId]);
		}

		elementUpdateTimers[elementId] = window.setTimeout(function () {
			syncElementNotationData(elementId, settings);
			delete elementUpdateTimers[elementId];
		}, 200);
	}

	function syncExistingElements() {
		var previewDocument = getPreviewDocument();
		var containers;
		var index;
		var elementId;
		var settings;

		if (!previewDocument) {
			return;
		}

		containers = previewDocument.querySelectorAll('.elementor-element[data-id]');

		for (index = 0; index < containers.length; index++) {
			elementId = containers[index].getAttribute('data-id');
			settings = getElementSettings(elementId);

			if (isNotationEnabled(settings) || hasNotationControl(settings)) {
				scheduleElementUpdate(elementId, settings);
			}
		}
	}

	function scheduleInitialSync() {
		var previewDocument = getPreviewDocument();

		if (!previewDocument || !previewDocument.body) {
			window.setTimeout(scheduleInitialSync, 400);
			return;
		}

		window.requestAnimationFrame(function () {
			syncExistingElements();
		});
	}

	function getChangedModel(view) {
		if (view && view.container && view.container.model) {
			return view.container.model;
		}

		if (view && view.model) {
			return view.model;
		}

		return null;
	}

	function bindEditorChange() {
		if (editorChangeBound) {
			return;
		}

		if (!window.elementor || !window.elementor.channels || !window.elementor.channels.editor) {
			editorBindRetryTimer = window.setTimeout(function () {
				editorBindRetryTimer = null;
				bindEditorChange();
			}, 300);
			return;
		}

		editorChangeBound = true;

		window.elementor.channels.editor.on('change', function (view) {
			var model = getChangedModel(view);
			var settings;
			var elementId;

			if (!model || 'function' !== typeof model.get) {
				return;
			}

			settings = normalizeSettings(model.get('settings') || {});
			elementId = model.get('id');

			if (!elementId || !hasNotationControl(settings)) {
				return;
			}

			scheduleElementUpdate(elementId, settings);
		});
	}

	function bindPreviewFrontendHooks() {
		var previewWindow = getPreviewWindow();
		var frontend = previewWindow && previewWindow.elementorFrontend;

		function handleElementReady($scope) {
			var element = $scope && $scope[0];
			var elementId = element ? getElementId(element) : null;
			var settings;

			if (!elementId) {
				return;
			}

			settings = getElementSettings(elementId);

			if (isNotationEnabled(settings)) {
				scheduleElementUpdate(elementId, settings);
			}
		}

		if (!frontend || !frontend.hooks || previewHooksBound) {
			return;
		}

		previewHooksBound = true;

		frontend.hooks.addAction('frontend/element_ready/widget', handleElementReady);
		frontend.hooks.addAction('frontend/element_ready/e-heading.default', handleElementReady);
		frontend.hooks.addAction('frontend/element_ready/e-paragraph.default', handleElementReady);
		frontend.hooks.addAction('frontend/element_ready/global', handleElementReady);
	}

	function onPreviewReady() {
		previewHooksBound = false;
		bindPreviewFrontendHooks();
		scheduleInitialSync();
	}

	function init() {
		var iframe = document.querySelector('#elementor-preview-iframe');

		bindEditorChange();

		if (iframe) {
			iframe.addEventListener('load', onPreviewReady);
		}

		if (window.elementor) {
			window.elementor.on('preview:loaded', onPreviewReady);
		}

		onPreviewReady();
	}

	if ('loading' === document.readyState) {
		document.addEventListener('DOMContentLoaded', init);
	} else {
		init();
	}
}(window, document));
