(function(window, $) {
	if (!$) return;
	
	var activeGrapesEditor = null;
	var activeGrapesConfig = null;
	
	function ensureHiddenInput($form, name, value) {
		var $input = $form.find('input[name="' + name + '"]');
		if (!$input.length) {
			$input = $('<input>').attr({
				type: 'hidden',
				name: name
			}).appendTo($form);
		}
		$input.val(value);
		return $input;
	}
	
	function safeRemoveRules($field) {
		if (!$field.length || !$field.rules) return;
		try {
			$field.rules('remove');
		} catch (err) {}
	}
	
	function exportGrapesHtml(editor) {
		var html = '';
		
		try {
			html = editor.runCommand('gjs-get-inlined-html');
		} catch (err) {}
		
		if (typeof html !== 'string' || html === '') {
			html = editor.getHtml();
			var css = editor.getCss();
			if (css) html = '<style>' + css + '</style>' + html;
		}
		
		if (typeof window.html_beautify === 'function' && html) {
			try {
				html = window.html_beautify(html, {
					indent_size: 2,
					preserve_newlines: true,
					max_preserve_newlines: 2,
					end_with_newline: false
				});
			} catch (err) {}
		}
		
		return html;
	}
	
	function syncGrapesEditor() {
		if (!activeGrapesEditor || !activeGrapesConfig) return;
		$(activeGrapesConfig.textareaSelector).val(exportGrapesHtml(activeGrapesEditor));
		$(activeGrapesConfig.projectInputSelector).val(JSON.stringify(activeGrapesEditor.getProjectData()));
	}

	function getDroppedFiles(e) {
		var files = [];
		var event = e && (e.dataTransfer || e.target || (e.event && (e.event.dataTransfer || e.event.target)));
		
		if (event && event.files) files = event.files;
		else if (e && e.dataTransfer && e.dataTransfer.files) files = e.dataTransfer.files;
		else if (e && e.target && e.target.files) files = e.target.files;
		
		return files;
	}
	
	function normalizeUploadedAssets(response) {
		var data = response && response.data ? response.data : response;
		if (!Array.isArray(data)) data = data ? [data] : [];
		
		return $.map(data, function(asset) {
			if (typeof asset === 'string') return {src: asset};
			if (asset && asset.src) return asset;
			if (asset && asset.url) return {src: asset.url};
			return null;
		});
	}
	
	window.SendyEditorModes = {
		syncActiveEditor: function() {
			if (typeof window.SendySyncPlainHtmlEditor === 'function') {
				window.SendySyncPlainHtmlEditor();
			}
			
			if (typeof window.SendySyncHtmlEditor === 'function') {
				window.SendySyncHtmlEditor();
			} else if (window.CKEDITOR && CKEDITOR.instances && CKEDITOR.instances.html) {
				CKEDITOR.instances.html.updateElement();
			}
			syncGrapesEditor();
		},
		
		initSwitcher: function(config) {
			var $form = $(config.formSelector);
			
			function submitWithMode(targetMode) {
				if (typeof config.beforeSubmit === 'function') config.beforeSubmit(targetMode);
				
				window.SendyEditorModes.syncActiveEditor();
				ensureHiddenInput($form, 'editor_mode', targetMode);
				ensureHiddenInput($form, 'w_clicked', '1');
				
				if (config.requiredFieldSelector) {
					var $requiredField = $(config.requiredFieldSelector);
					if ($requiredField.length && $.trim($requiredField.val()) === '' && config.requiredFieldFallback) {
						$requiredField.val(config.requiredFieldFallback);
					}
					safeRemoveRules($requiredField);
				}
				
				if (config.htmlSelector) safeRemoveRules($(config.htmlSelector));
				$form.submit();
			}
			
			if (config.modeButtonSelector) {
				$form.find(config.modeButtonSelector).click(function(e) {
					e.preventDefault();
					var $button = $(this);
					var targetMode = $button.data('editor-mode');
					var currentMode = $.trim($form.find('input[name="editor_mode"]').val() || '');
					
					if (!targetMode || targetMode === currentMode || $button.hasClass('active')) return;
					submitWithMode(targetMode);
				});
			}
			
			if (config.primaryButtonSelector && config.primaryTargetMode) {
				$(config.primaryButtonSelector).click(function(e) {
					e.preventDefault();
					submitWithMode(config.primaryTargetMode);
				});
			}
			
			if (config.secondaryButtonSelector && config.secondaryTargetMode) {
				$(config.secondaryButtonSelector).click(function(e) {
					e.preventDefault();
					submitWithMode(config.secondaryTargetMode);
				});
			}
		},
		
		initGrapes: function(config) {
			if (!window.grapesjs || !$(config.containerSelector).length) return null;
			
			var pluginModule = window['grapesjs-preset-newsletter'] || window.grapesjsPresetNewsletter || window.grapesjspresetnewsletter;
			var plugin = typeof pluginModule === 'function' ? pluginModule : pluginModule && typeof pluginModule.default === 'function' ? pluginModule.default : null;
			var grapesEditor = null;
			var options = {
				container: config.containerSelector,
				height: config.height || '760px',
				storageManager: false,
				telemetry: false,
				noticeOnUnload: false,
				fromElement: false,
				assetManager: {
					upload: config.assetUploadUrl,
					uploadName: 'files',
					autoAdd: false,
					uploadFile: function(e) {
						var files = getDroppedFiles(e);
						var formData = new FormData();
						
						if (!files || !files.length) return;
						
						$.each(files, function(index, file) {
							formData.append('files[]', file);
						});
						
						$.ajax({
							url: config.assetUploadUrl,
							type: 'POST',
							data: formData,
							processData: false,
							contentType: false,
							dataType: 'json'
						}).done(function(response) {
							var assets = normalizeUploadedAssets(response);
							if (!assets.length) {
								alert(config.assetUploadError || 'Unable to upload image.');
								return;
							}
							
							if (grapesEditor) grapesEditor.AssetManager.add(assets);
						}).fail(function() {
							alert(config.assetUploadError || 'Unable to upload image.');
						});
					}
				}
			};
			
			if (typeof config.projectData === 'string' && config.projectData !== '') {
				try {
					config.projectData = JSON.parse(config.projectData);
				} catch (err) {
					config.projectData = null;
				}
			}
			
			if (plugin) {
				options.plugins = [function(editor) {
					plugin(editor, {
						inlineCss: true,
						showBlocksOnLoad: true,
						importPlaceholder: config.importPlaceholder || ''
					});
				}];
			}
			
			if (config.projectData) options.projectData = config.projectData;
			else options.components = config.initialHtml || '';
			
			grapesEditor = window.grapesjs.init(options);
			activeGrapesEditor = grapesEditor;
			activeGrapesConfig = config;
			
			$(config.formSelector).submit(function() {
				window.SendyEditorModes.syncActiveEditor();
			});
			
			if (config.saveOnlyButtonsSelector) {
				$(config.saveOnlyButtonsSelector).click(function(e) {
					e.preventDefault();
					ensureHiddenInput($(config.formSelector), 'save-only', '1');
					$(config.formSelector).submit();
				});
			}
			
			activeGrapesEditor.on('asset:upload:error', function() {
				alert(config.assetUploadError || 'Unable to upload image.');
			});
			
			return activeGrapesEditor;
		}
	};
})(window, window.jQuery);
