/**
 * @license Copyright (c) 2014-2018, CKSource - Frederico Knabben. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/license
 */

( function() {
	'use strict';

	CKEDITOR.plugins.a11ychecker.quickFixes.get( { langCode: 'de',
		name: 'ElementReplace',
		callback: function( ElementReplace ) {
			/**
			 * Replaces provided element with element that a different tag name, preserving its children.
			 *
			 * @member CKEDITOR.plugins.a11ychecker.quickFix
			 * @class ParagraphToHeader
			 * @constructor
			 * @param {CKEDITOR.plugins.a11ychecker.Issue} issue
			 */
			function ParagraphToHeader( issue ) {
				ElementReplace.call( this, issue );
			}

			ParagraphToHeader.prototype = new ElementReplace();
			ParagraphToHeader.prototype.constructor = ParagraphToHeader;

			ParagraphToHeader.prototype.getTargetName = function( formAttributes ) {
				return formAttributes.level;
			};

			ParagraphToHeader.prototype.display = function( form, editor ) {

				var levelDict = this._getFormHeaderLeves( editor );

				form.setInputs( {
					level: {
						type: 'select',
						label: this.lang.levelLabel,
						value: 'h' + this._getPreferredLevel( editor ),
						options: levelDict
					}
				} );
			};

			ParagraphToHeader.prototype.fix = function( formAttributes, callback ) {
				var that = this;
				ElementReplace.prototype.fix.call( this, formAttributes, function() {
					that._removeBoldTag();
					callback( that );
				} );
			};

			/**
			 * Determines preferred heading level for the header that should be cerated.
			 *
			 * @private
			 * @param {CKEDITOR.editor} editor
			 * @returns {Number} Number ranging from `1` to `6`.
			 */
			ParagraphToHeader.prototype._getPreferredLevel = function( editor ) {
				var ret = 1,
					editable = editor.editable(),
					headerTagRegExp = /^h[1-6]$/i,
					range = new CKEDITOR.dom.range( editable.getDocument() ),
					walker,
					prevElement;

				range.setStartAt( editable, CKEDITOR.POSITION_AFTER_START );
				range.setEndAt( this.issue.element, CKEDITOR.POSITION_BEFORE_START );
				walker = new CKEDITOR.dom.walker( range );

				while ( ( prevElement = walker.previous() ) ) {
					if ( prevElement.getName && prevElement.getName().match( headerTagRegExp ) ) {
						ret = Number( prevElement.getName()[ 1 ] ) + 1;
						break;
					}
				}

				// WE can't return a higher value than 7.
				return Math.min( ret, 6 );
			};

			/**
			 * This method check if issue element contains `<strong>` element only as a first and the only child.
			 * If so we'll remove it, but move its children to the `issue.element`.
			 */
			ParagraphToHeader.prototype._removeBoldTag = function() {
				var isElementEvaluator = function( el ) {
						return el.type === CKEDITOR.NODE_ELEMENT;
					},
					elem = this.issue.element,
					innerElement = elem.getFirst( isElementEvaluator ),
					// If first child element is at the same time last element child, then it means it has only this element.
					hasSingleElement = innerElement && innerElement.equals( elem.getLast( isElementEvaluator ) ),
					suspiciousTagNames = [ 'strong', 'b' ];

				if ( hasSingleElement && CKEDITOR.tools.indexOf( suspiciousTagNames, innerElement.getName() ) !== -1 ) {
					innerElement.moveChildren( elem );
					innerElement.remove();
				}
			};

			/**
			 * Returns minimal and maximal possible header levels for given editor.
			 *
			 * Result will be based on ACF and `config.format_tags`.
			 *
			 * @param {CKEDITOR.editor}
			 * @return {Object} Allowed header level boundaries.
			 * @return {Number} return.min Minimal allowed level.
			 * @return {Number} return.email Maximal allowed level.
			 */
			ParagraphToHeader.prototype._getPossibleLevels = function( editor ) {
				var tags = ( editor.config.format_tags || '' ).split( ';' ),
					ret = {
						min: 1,
						max: 6
					},
					i;

				// Filtering tags.
				for ( i = tags.length - 1; i >= 0; i-- ) {
					// If given tag is not header tag or if it's not allowed by the ACF.
					if ( !tags[ i ].match( /^h[1-6]$/i ) || !editor.filter.check( tags[ i ] ) ) {
						tags.splice( i, 1 );
					} else {
						tags[ i ] = Number( tags[ i ][ 1 ] );
					}
				}

				if ( tags.length ) {
					// Note if IE8 has to be supported we need to inline sorting here.
					tags.sort();

					ret.min = tags[ 0 ];
					ret.max = tags[ tags.length - 1 ];
				}

				return ret;
			};

			/**
			 * Returns options dictionary that should be put in form header level select.
			 *
			 * @param {CKEDITOR.editor} editor
			 */
			ParagraphToHeader.prototype._getFormHeaderLeves = function( editor ) {
				var dict = {},
					boundaries = this._getPossibleLevels( editor ),
					preferredLevel = this._getPreferredLevel( editor );

				for ( var i = boundaries.min; i <= boundaries.max; i++ ) {
					dict[ 'h' + i ] = 'H' + i;
				}

				if ( dict[ 'h' + preferredLevel ] ) {
					dict[ 'h' + preferredLevel ] += ( ' ' + this.lang.suggested );
				}

				return dict;
			};


			ParagraphToHeader.prototype.lang = {"levelLabel":"Überschriftenebene","suggested":"(Vorschlag)"};
			CKEDITOR.plugins.a11ychecker.quickFixes.add( 'de/ParagraphToHeader', ParagraphToHeader );
		}
	} );
}() );
