/* 
 * Plugin to integrate ALB in Gutenberg page
 * 
 * To stay backwards compatible Gutenberg addon creates a similar structure to classic editor.
 * TinyMCE is placed after Gutenberg section and outside the ALB metabox which includes a hidden switch layout button 
 * and we trigger the "old" hidden switch editor style button.
 * 
 * In this way we reduce the changes to some CSS and we add some trigger events for callback.
 * 
 * 
 * @since 4.5.1
 * @added_by Günter
 */

'use strict';


(function($)
{
	$.AviaBuilderGutenberg = function()
	{
		//	Flag to check if we can use the object
		this.init = false;
		
		//	Instance of builder attached to
		this.aviaBuilder = null;
		
		//	Body container
		this.body_container = $('body').eq( 0 );
		this.body_container.addClass('avia-gutenberg-not-init');
		
		//	Metabox container
		this.metabox = $('#avia_alb_actions');
		
		//	Layout switch button, copied to header (remains hidden in metabox to be able to restore if gutenberg removes it dynamically from header)
		this.gutenberg_switch_button_source = this.metabox.find('.avia-builder-button');
		
		this.permalink_container = null;
		
		//	Monitor autosave so we can save changes to ALB content (metboxes are not sent to server on autosave WP 5.0)
		this.auto_save_observer = null;
		
		//	We save the last autosave time to reduce calls to server
		this.last_autosave = 0;
		this.minimum_no_autosave = 60;		//	in seconds
		
		if( $.avia_builder == typeof 'undefined' )
		{
			this.body_container.on( 'AviaBuilder_after_set_up', $.proxy( this.set_up, this ));
		}
		else
		{
			this.set_up();
		}
		
	};
	
	$.AviaBuilderGutenberg.prototype = {
		
		/**
		 * 
		 * @returns {undefined}
		 */
		set_up: function()
		{
			this.aviaBuilder = $.avia_builder;
			this.aviaBuilder.disable_autoswitch_editor_style = true;
			
			//	overwrite, because HTML structure has changed (we moved editor outside meta box)
			if( 'undefined' != typeof( this.aviaBuilder.switch_button.length ) && this.aviaBuilder.switch_button.length > 0 )
			{
				this.aviaBuilder.switch_button.off('click');
			}
			this.aviaBuilder.switch_button = $('#postdivrich_wrap_builder_meta').find('.avia-builder-button');
			
			this.permalink_container = $('#avia_builder #titlediv #edit-slug-box');
			
			this.wait_for_gutenberg_init();
			this.attach_handlers();
		},
		
		wait_for_gutenberg_init: function()
		{
			var header_container = this.get_gutenberg_header_settings_container();
			var self = this;
			
			if( header_container.length == 0 )
			{
				//	DOM is not ready
				setTimeout(function(){
						self.wait_for_gutenberg_init();
					}, 100 );
					
				return;
			}
			
			this.copy_layout_switch_button();
			this.monitor_save_infos();
			
			/**
			 * FF fix:	When post is saved in ALB, switch to normal and an immediate pagereload leaves hidden input field on "normal" -> breaks output
			 *			Also the other way round.
			 */
			if( navigator.userAgent.indexOf("Firefox") != -1 )
			{
				var fix = false;
				var html = this.aviaBuilder.switch_button.html();
				
				if( this.aviaBuilder.activeStatus.val() == 'active')
				{
					fix = this.aviaBuilder.switch_button.data('active-button') != html;
				}
				else
				{
					fix = this.aviaBuilder.switch_button.data('inactive-button') != html;
				}
				
				if( fix )
				{
					console.log('FF fix executed');
					
					this.aviaBuilder.switch_button.trigger('click');
				}
			}
			
			this.aviaBuilder.builder_drag_drop_container = $('body.block-editor-page .block-editor #avia_builder').closest('.edit-post-layout__metaboxes');
			
			/**
			 * Make sure we have only a single shortcode block when an ALB page
			 * (When opening existing non block pages we get a broken tinyMCE)
			 */
			if( this.aviaBuilder.activeStatus.val() == 'active' )
			{
				var content = this.aviaBuilder.secureContent.val();
				this.set_gutenberg_post_content( content );
				
				for( var i = 0; i < tinymce.editors.length; i++ ) 
				{
					var editorInstance = tinymce.editors[i];
					var id = editorInstance.id.toLowerCase().trim();
					tinymce.remove( '#' + id );
				}
				
				this.select_document_tab();
			}
			
			this.attach_metabox_toggle_fix();
			
			this.init = true;
			this.body_container.removeClass( 'avia-gutenberg-not-init' );
		},
		
		copy_layout_switch_button: function()
		{
			var btn = this.get_layout_switch_button();
			if( false !== btn )
			{
				return btn;
			}
			
			this.gutenberg_switch_button_source.hide();
			var new_button = this.gutenberg_switch_button_source.clone();
			
			var container = this.get_gutenberg_header_settings_container();
			container.prepend( new_button );
			
			new_button.show().attr( 'id', '' );
			new_button.on( 'click', $.proxy( this.switch_layout_mode_gutenberg_btn, this ));
			
			return new_button;
		},
		
		/**
		 * Is changed dynamically during publishing a new post - we need to query DOM
		 */
		get_gutenberg_header_settings_container: function()
		{
			var container = $( '.edit-post-header__settings' ).first();
			return container;
		},
		
		get_layout_switch_button: function()
		{
			var btn = this.get_gutenberg_header_settings_container().find( '.avia-builder-button' ).first();
			return btn.length > 0 ? btn : false;
		},
		
		get_gutenberg_save_draft_button: function()
		{	
			var btn = this.get_gutenberg_header_settings_container().find( '.editor-post-save-draft' ).first();
			return btn.length > 0 ? btn : false;
		},
		
		get_gutenberg_publish_button: function()
		{
			var btn = this.get_gutenberg_header_settings_container().find( '.editor-post-publish-button' ).first();
			return btn.length > 0 ? btn : false;
		},
		
		get_gutenberg_switch_to_draft_button: function()
		{
			var btn = this.get_gutenberg_header_settings_container().find( '.editor-post-switch-to-draft' ).first();
			return btn.length > 0 ? btn : false;
		},
		
		get_gutenberg_publish_new_post_button: function()
		{
			var btn = this.get_gutenberg_header_settings_container().find( '.editor-post-publish-panel__toggle' ).first();
			return btn.length > 0 ? btn : false;
		},
		
		get_gutenberg_title: function()
		{
			var title = wp.data.select( 'core/editor' ).getEditedPostAttribute( 'title' );
			return title;
		},
		
		set_gutenberg_title: function( value )
		{
			var value = 'string' == typeof value ? value.trim() : '';
			wp.data.dispatch( 'core/editor' ).editPost( {
								title: value
							} );
		},
		
		get_alb_title: function()
		{
			var title = this.body_container.find( '.avia_meta_box_visual_editor #titlewrap input' ).first();
			return title.length > 0 ? title.val() : false;
		},
		
		set_alb_title: function( value, focus )
		{
			var title = this.body_container.find( '.avia_meta_box_visual_editor #titlewrap input' ).first();
			var label = this.body_container.find( '.avia_meta_box_visual_editor #titlewrap #title-prompt-text' );
			var value = 'string' == typeof value ? value.trim() : '';
			title.val( value );
			
			//	remove placeholder
			if( label.length > 0 )
			{
				if( value.trim() == '' )
				{
					label.removeClass( 'screen-reader-text' );
				}
				else
				{
					label.addClass( 'screen-reader-text' );
				}
			}
			else
			{
				//	this is a fallback to the beginning of block editor - no idea when label was added
				if( ( value != '' ) && ( 'undefined' != typeof focus ) && ( focus == 'focus' ) )
				{
					setTimeout(function(){
							title.focus();
						}, 300 );
				}
			}
		},
		
		can_publish: function()
		{
			if( ! this.init )
			{
				return false;
			}
			
			var publish = this.get_gutenberg_publish_button();
			if( false !== publish )
			{
				return true;
			}
			
			var new_post = this.get_gutenberg_publish_new_post_button();
			if( false !== new_post )
			{
				if( 'undefined' == typeof new_post.attr( 'disabled' ) )
				{
					return true;
				}
			}
			
			return false;
		},
		
		is_new_post: function()
		{
			var draft = this.get_gutenberg_save_draft_button();
			if( false === draft )
			{
				return true;
			}
			
			if( 'undefined' == typeof draft.attr( 'disabled' ) )
			{
				return true;
			}
			
			var new_post = this.get_gutenberg_publish_new_post_button();
			return false !== new_post;
		},
		
		attach_gutenberg_title_event_handler: function()
		{
			var title = $( '.gutenberg__editor .edit-post-visual-editor .editor-post-title__block textarea.editor-post-title__input' ).first();
			var self = this;
			
			if( title.length == 0 )
			{
				setTimeout(function(){
						self.attach_gutenberg_title_event_handler();
					}, 100 );
					
				return;
			}
			
			title.on( 'keyup', $.proxy( this.gutenberg_title_keyup, this ) );
		},
		
		attach_edit_permalink_event_handler: function()
		{
			this.body_container.find( '.av-edit-alb-permalink' ).on( 'click', $.proxy( this.alb_edit_permalink, this ) );
		},
		
		attach_alb_permalink_href_handler: function()
		{
			this.body_container.find( '.avia_meta_box_visual_editor #edit-slug-box #sample-permalink > a' ).on( 'click', $.proxy( this.alb_permalink_href_handler, this ) );
		},
		
		attach_metabox_toggle_fix: function()
		{
			if( this.body_container.hasClass( 'block-editor-page' ) && this.body_container.hasClass( 'avia-advanced-editor-enabled' ) )
			{
				this.body_container.find( '.postbox-header .handlediv' ).on( 'click', this.metabox_toggle_fix );
			}
		},
		
		attach_handlers: function()
		{
			this.body_container.on( 'AviaBuilder_after_switch_layout_mode', $.proxy( this.layout_mode_changed, this ));
			this.body_container.find( '.avia_meta_box_visual_editor #titlewrap input' ).on( 'keyup', $.proxy( this.alb_title_key_up, this ) );
			this.attach_gutenberg_title_event_handler();
			this.aviaBuilder.secureContent.on( 'av_secureContent_update change', $.proxy( this.alb_secureContent_changed, this ) );
			
			//	Needs to be overwritten because we moved the editor 
			var obj = this.aviaBuilder;
			obj.switch_button.on( 'click', function(e){
												e.preventDefault();
												obj.switch_layout_mode(e);
										});
										
			this.attach_edit_permalink_event_handler();
			this.attach_alb_permalink_href_handler();
		},
		
		/**
		 * Triggers a clickevent on the standard ALB switch button
		 */
		switch_layout_mode_gutenberg_btn: function(e)
		{
			e.preventDefault();
			
			if( this.aviaBuilder.activeStatus.val() != 'active' )
			{
				if( ! this.set_alb_secure_content() )
				{
					return;
				}
				
				/**
				 * Problem with tinyMCE: We need to remove our content editor if not the last one
				 * otherwise toolbar of visual editor and selectors get broken.
				 */
				for( var i = 0; i < tinymce.editors.length; i++ ) 
				{
					var editorInstance = tinymce.editors[i];
					var id = editorInstance.id.toLowerCase().trim();

					if( ( 'content' == id ) && ( i != tinymce.editors.length - 1 ) )
					{
						tinymce.remove( '#' + id );
					}
				}

				this.set_alb_title( this.get_gutenberg_title(), 'focus' );
				
				
				//	this class is set when editing the pretty permalink, which needs a switchback to Gutenberg editor
				this.body_container.removeClass('avia-edit-permalink');
				this.alb_sync_permalink();
				this.select_document_tab();
			}
			else
			{
				this.set_gutenberg_title( this.get_alb_title() );
				var content = this.aviaBuilder.secureContent.val();
				this.set_gutenberg_post_content( content );
			}
			
			this.aviaBuilder.switch_button.trigger( 'click' );
		},
		
		select_document_tab: function()
		{
			//	Make sure we have Document tab selected
			var doc_button = this.body_container.find( '.edit-post-sidebar .components-panel__header button.edit-post-sidebar__panel-tab' ).eq( 0 );
			if( ! doc_button.hasClass( 'is-active' ) )
			{
				doc_button.trigger( 'click' );
			}
		},
		
		alb_edit_permalink: function(e)
		{
			e.preventDefault();
			
			this.body_container.addClass( 'avia-edit-permalink' );
			this.get_layout_switch_button().trigger( 'click' );
		},
		
		alb_sync_permalink: function()
		{
					//	Update the pretty permalink below post title
			var permalink = wp.data.select( 'core/editor' ).getPermalink();
			var post = wp.data.select( 'core/editor' ).getCurrentPost(); 
			var safelink = post.link;
			safelink += ( safelink.indexOf('?') == -1 ) ? '?preview=true' : '&preview=true';
			var id = 'wp-preview-' + post.id;

			var link = this.permalink_container.find( '#sample-permalink > a' ).first();
			if( link.length > 0 )
			{
				link.attr( 'href', safelink).attr( 'target', id );
				link.html( permalink );
			}
			else		//	new posts have no permalink
			{
				var html =		'<strong>Permalink:</strong>';
				html +=			'<span id="sample-permalink">';
				html +=				'<a href="' + safelink + '" target="' + id + '">' + permalink + '</a>';
				html +=			'</span>';
				html +=			'<span id="av-edit-alb-permalink-buttons">';
				html +=				'<button type="button" class="av-edit-alb-permalink button button-small hide-if-no-js" aria-label="Edit permalink">Edit</button>';
				html +=			'</span>';

				this.permalink_container.html( html );
				this.attach_edit_permalink_event_handler();
				this.attach_alb_permalink_href_handler();
			}
		},
		
		alb_permalink_href_handler: function( target )
		{
			this.alb_sync_permalink();
		},
		
		metabox_toggle_fix: function( e )
		{
			/**
			 * Fixes a problem, that WP attaches event handler twice. Closes and opens the metabox again.
			 * 
			 * See wp-admin\js\postbox.js
			 */
			var btn = $( this ),
				p = btn.closest( '.postbox' ),
				ariaExpandedValue;
			
			p.toggleClass( 'closed' );
			ariaExpandedValue = ! p.hasClass( 'closed' );
			
			btn.attr( 'aria-expanded', ariaExpandedValue );
		},
		
		/**
		 * Callback when layout mode change is finished or when we need to sync buttons e.g. after saving a new post
		 * 
		 * @param {event} e				standard ALB switch editor button click
		 * @param (jQuery) button
		 * @param {string} state		'active' | ''
		 */
		layout_mode_changed: function(e, button, state )
		{
			e.preventDefault();
			
			var btn = this.get_layout_switch_button();
			if( false !== btn )
			{
				btn.text( button.text );
			}
			
			this.gutenberg_switch_button_source.text( button.text );
		},
		
		alb_secureContent_changed: function( context )
		{
			var content = this.aviaBuilder.secureContent.val();
			
			//	Fix WP 5.5: if empty content and title is edited in chrome title field looses focus
			if( ! ( typeof context == 'string' && context == 'title' && content.trim() == '' ) )
			{
				this.set_gutenberg_post_content( content );
			}
			
			//	Blockeditor sometimes switches to block tab - reset
			this.select_document_tab();
		},
		
		gutenberg_title_keyup: function(e)
		{
			var title = this.get_gutenberg_title();
			this.set_alb_title( title );
		},
		
		alb_title_key_up: function( e )
		{
			var element = e.target;
			
			var title = $(element).val();
			this.set_gutenberg_title( title );
			this.alb_secureContent_changed( 'title' );
		},
		
		set_gutenberg_post_content: function( content )
		{
			content = content.trim();
			
			var editor = wp.data.dispatch( 'core/block-editor' );
			var blocks = wp.data.select( 'core/block-editor' ).getBlocks();
			var shortcode = null;
			
			if( blocks.length > 0 )
			{
				$.each( blocks, function( index, block ){
							if( ( block.name == 'core/shortcode' ) && ( content.length > 0 ) )
							{
								if( shortcode == null )
								{
									shortcode = block;
									return;
								}
							}
							
							editor.removeBlock( block.clientId );
					});
			}
			
			if( shortcode == null )
			{
//				var new_block = wp.blocks.createBlock( 'core/freeform', { content: content } );
//				var sav = editor.savePost();

				var new_block = wp.blocks.createBlock( 'core/shortcode', { text: content } );
				editor.insertBlocks( new_block );
			}
			else
			{
				editor.updateBlockAttributes( shortcode.clientId, { text: content } );
			}
		},
		
		set_alb_secure_content: function()
		{
			var alb = this.aviaBuilder.secureContent.val();
			
			this.aviaBuilder.canvas.children().remove();
			
			/**
			 * If we have already an existing ALB content we ignore any modifications from user via Gutenberg
			 */
			if( alb.trim() != '' )
			{
				return true;
			}
			
			var blocks = wp.data.select( 'core/block-editor' ).getBlocks();
			var content = [];
			var skipped_blocks = 0;
			
			$.each( blocks, function( index, block ){
				
								var new_c = '';
								if( 'undefined' != typeof block.attributes.content )
								{
									new_c = block.attributes.content;
								}
								else if( 'undefined' != typeof block.attributes.text )
								{
									new_c = block.attributes.text;
								}
								else
								{
									skipped_blocks++;
								}
								
								if( new_c != '' )
								{
									content.push( new_c );
								}
						});
						
			if( ( skipped_blocks == 0 ) && ( content.length == 0 ) )
			{
				return true;
			}
			
			if( skipped_blocks > 0 )
			{
				var confirm = window.confirm( avia_gutenberg_i18.switch_block_msg );
				if( ! confirm )
				{
					return false;
				}
			}
			
			var text = content.join( '\n\n' );
			
			var editor = this.aviaBuilder.tiny_active ? window.tinyMCE.get('content') : false;
			if(editor) 
			{
				var text_html = content.join( '<br /><br />' );
				editor.setContent(text_html, {format:'html'});
			}
			
			this.aviaBuilder.secureContent.val(text);
			this.aviaBuilder.classic_textarea.val(text);
			
			return true;
		},
		
		monitor_save_infos: function()
		{
			if( null == this.auto_save_observer )
			{
				var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
				var container = this.get_gutenberg_header_settings_container()[0];
				
				this.auto_save_observer = new MutationObserver( $.proxy( this.check_for_is_saving, this ) );
				this.auto_save_observer.observe(container, { childList: true, subtree: true } );
			}
		},
		
		check_for_is_saving: function( mutations )
		{
			var self = this;

			$.each( mutations, function(key, mutation) {
				
						if( 'undefined' == typeof( mutation.type ) )
						{
							return;
						}

						if( ('childList' != mutation.type ) && ('subtree' != mutation.type ) )
						{
							return;
						}

						for( var i = 0; i < mutation.addedNodes.length; i++) 
						{
							var node = $(mutation.addedNodes[i]);
							
							if( node.hasClass( 'editor-post-saved-state') && node.hasClass( 'is-saving') )
							{
								/**
								 * For portfolio we have to trigger tinyMCE switch to copy content to textarea
								 */
								if( self.body_container.hasClass('post-type-portfolio') )
								{
									var editor_container = self.body_container.find('#wp-_preview_text-wrap').first();
									if( ( editor_container.length > 0 ) && editor_container.hasClass('tmce-active') )
									{
										var textarea = editor_container.find('#_preview_text');
										var the_value = textarea.val();
										if( window.tinyMCE.get('_preview_text') )
										{	
											/*fixes the problem with galleries and more tag that got an image representation of the shortcode*/
											the_value = window.tinyMCE.get('_preview_text').getContent();
										}
										textarea.val( the_value );		//	= defaault behaviour of tinyMCE
									}
								}
								/**
								 * Fix: Block editor does not save the metaboxes on autosave (WP 5.0-beta-3)
								 */
								if( node.hasClass( 'is-autosaving' ) )
								{
									self.alb_perform_autosave( self );
								}
							}
						}
					});
		},
		
		alb_perform_autosave: function( self )
		{
			/**
			 * Blockeditor makes an autosave approx. all 10 seconds - we reduce this to minimum_no_autosave seconds for our data
			 * 
			 */
			if( 0 != this.last_autosave )
			{
				if( this.last_autosave + 1000 * this.minimum_no_autosave  > Date.now() )
				{
					return;
				}
			}
			this.last_autosave = Date.now();
			
			var post = wp.data.select( 'core/editor' ).getCurrentPost();
			
			var senddata = {
						action:		'avia_gutenberg_autosave_metaboxes',
						post_id:	post.id
					};
					
			var fields  = $('form.metabox-location-normal, form.metabox-location-side').serializeArray();
			
			$.each( fields, function( i, field ) {
								senddata[field.name] = field.value;
						});
					
			$.ajax({
					type: "POST",
					url: ajaxurl,
					dataType: 'json',
					cache: false,
					data:	senddata,
							success	: function(response, textStatus, jqXHR) {
										
										if( 'undefined' != typeof response.avia_gutenberg_nonce )
										{
											self.body_container.find('#avia_builder input[name="avia_gutenberg_nonce"]').val( response.avia_gutenberg_nonce );
										}

										if( ! response.success && 'undefined' != typeof response.expired_nonce )
										{
											self.alb_perform_autosave( self );
										}
									},
							error: function(errorObj) {
	//								console.log( 'alb_perform_autosave error: ', errorObj );
								},
							complete: function(test) {
								}

				});
		}
	};
	
	$( document ).ready( function () 
	{
		/**
		 * Only load this class on a Gutenberg Page
		 */
		if( $( 'body' ).hasClass( 'block-editor-page' ) )
    	{
			$.avia_builder_gutenberg = new $.AviaBuilderGutenberg();
		}
	});
	
}) (jQuery);	 
