/* exported ToolbarConfigurator */
/* global ToolbarConfigurator */

'use strict';

window.ToolbarConfigurator = {};

( function() {
	/**
	 * @class ToolbarConfigurator.FullToolbarEditor
	 * @constructor
	 */
	function FullToolbarEditor() {
		this.instanceid = 'fte' + CKEDITOR.tools.getNextId();
		this.textarea = new CKEDITOR.dom.element( 'textarea' );
		this.textarea.setAttributes( {
			id: this.instanceid,
			name: this.instanceid,
			contentEditable: true
		} );

		this.buttons = null;
		this.editorInstance = null;
	}

	// Expose the class.
	ToolbarConfigurator.FullToolbarEditor = FullToolbarEditor;

	/**
	 * @param {Function} callback
	 * @param {Object} cfg
	 */
	FullToolbarEditor.prototype.init = function( callback ) {
		var that = this;

		document.body.appendChild( this.textarea.$ );

		CKEDITOR.replace( this.instanceid );

		this.editorInstance = CKEDITOR.instances[ this.instanceid ];

		this.editorInstance.once( 'configLoaded', function( e ) {
			var cfg = e.editor.config;

			// We want all the buttons.
			delete cfg.removeButtons;
			delete cfg.toolbarGroups;
			delete cfg.toolbar;
			ToolbarConfigurator.AbstractToolbarModifier.extendPluginsConfig( cfg );

			e.editor.once( 'loaded', function() {
				that.buttons = FullToolbarEditor.toolbarToButtons( that.editorInstance.toolbar );

				that.buttonsByGroup = FullToolbarEditor.groupButtons( that.buttons );

				that.buttonNamesByGroup = that.groupButtonNamesByGroup( that.buttons );

				e.editor.container.hide();

				if ( typeof callback === 'function' )
					callback( that.buttons );
			} );
		} );
	};

	/**
	 * Group array of button names by their group parents.
	 *
	 * @param {Array} buttons
	 * @returns {Object}
	 */
	FullToolbarEditor.prototype.groupButtonNamesByGroup = function( buttons ) {
		var that = this,
			groups = FullToolbarEditor.groupButtons( buttons );

		for ( var groupName in groups ) {
			var currGroup = groups[ groupName ];

			groups[ groupName ] = FullToolbarEditor.map( currGroup, function( button ) {
				return that.getCamelCasedButtonName( button.name );
			} );
		}

		return groups;
	};

	/**
	 * Returns group literal.
	 *
	 * @param {String} name
	 * @returns {Object}
	 */
	FullToolbarEditor.prototype.getGroupByName = function( name ) {
		var groups = this.editorInstance.config.toolbarGroups || this.getFullToolbarGroupsConfig();

		var max = groups.length;
		for ( var i = 0; i < max; i += 1 ) {
			if ( groups[ i ].name === name )
				return groups[ i ];
		}

		return null;
	};

	/**
	 * @param {String} name
	 * @returns {String | null}
	 */
	FullToolbarEditor.prototype.getCamelCasedButtonName = function( name ) {
		var items = this.editorInstance.ui.items;

		for ( var key in items ) {
			if ( items[ key ].name == name )
				return key;
		}

		return null;
	};

	/**
	 * Returns full toolbarGroups config value which is used when
	 * there is no toolbarGroups field in config.
	 *
	 * @param {Boolean} [pickSeparators=false]
	 * @returns {Array}
	 */
	FullToolbarEditor.prototype.getFullToolbarGroupsConfig = function( pickSeparators ) {
		pickSeparators = ( pickSeparators === true ? true : false );

		var result = [],
			toolbarGroups = this.editorInstance.toolbar;

		var max = toolbarGroups.length;
		for ( var i = 0; i < max; i += 1 ) {
			var currentGroup = toolbarGroups[ i ],
				copiedGroup = {};

			if ( typeof currentGroup.name != 'string' ) {
				// this is not a group
				if ( pickSeparators ) {
					result.push( '/' );
				}
				continue;
			}

			copiedGroup.name = currentGroup.name;
			if ( currentGroup.groups )
				copiedGroup.groups = Array.prototype.slice.call( currentGroup.groups );

			result.push( copiedGroup );
		}

		return result;
	};

	/**
	 * Filters array items based on checker provided in second argument.
	 * Returns new array.
	 *
	 * @param {Array} arr
	 * @param {Function} checker
	 * @returns {Array}
	 */
	FullToolbarEditor.filter = function( arr, checker ) {
		var max = ( arr && arr.length ? arr.length : 0 ),
			result = [];

		for ( var i = 0; i < max; i += 1 ) {
			if ( checker( arr[ i ] ) )
				result.push( arr[ i ] );
		}

		return result;
	};

	/**
	 * Simplified http://underscorejs.org/#map functionality
	 *
	 * @param {Array | Object} enumerable
	 * @param {Function} modifier
	 * @returns {Array | Object}
	 */
	FullToolbarEditor.map = function( enumerable, modifier ) {
		var result;

		if ( CKEDITOR.tools.isArray( enumerable ) ) {
			result = [];

			var max = enumerable.length;
			for ( var i = 0; i < max; i += 1 )
				result.push( modifier( enumerable[ i ] ) );
		} else {
			result = {};

			for ( var key in enumerable )
				result[ key ] = modifier( enumerable[ key ] );
		}

		return result;
	};

	/**
	 * Group buttons by their parent names.
	 *
	 * @static
	 * @param {Array} buttons
	 * @returns {Object} The object (`name => group`) representing CKEDITOR.ui.button or CKEDITOR.ui.richCombo
	 */
	FullToolbarEditor.groupButtons = function( buttons ) {
		var groups = {};

		var max = buttons.length;
		for ( var i = 0; i < max; i += 1 ) {
			var currBtn = buttons[ i ],
				currBtnGroupName = currBtn.toolbar.split( ',' )[ 0 ];

			groups[ currBtnGroupName ] = groups[ currBtnGroupName ] || [];

			groups[ currBtnGroupName ].push( currBtn );
		}

		return groups;
	};

	/**
	 * Pick all buttons from toolbar.
	 *
	 * @static
	 * @param {Array} groups
	 * @returns {Array}
	 */
	FullToolbarEditor.toolbarToButtons = function( groups ) {
		var buttons = [];

		var max = groups.length;
		for ( var i = 0; i < max; i += 1 ) {
			var currentGroup = groups[ i ];

			if ( typeof currentGroup == 'object' )
				buttons = buttons.concat( FullToolbarEditor.groupToButtons( groups[ i ] ) );
		}

		return buttons;
	};

	/**
	 * Creates HTML button representation for view.
	 *
	 * @static
	 * @param {CKEDITOR.ui.button | CKEDITOR.ui.richCombo} button
	 * @returns {CKEDITOR.dom.element}
	 */
	FullToolbarEditor.createToolbarButton = function( button ) {
		var $button = new CKEDITOR.dom.element( 'a' ),
			icon = FullToolbarEditor.createIcon( button.name, button.icon, button.command );

		$button.setStyle( 'float', 'none' );

		$button.addClass( 'cke_' + ( CKEDITOR.lang.dir == 'rtl' ? 'rtl' : 'ltr' ) );

		if ( button instanceof CKEDITOR.ui.button ) {
			$button.addClass( 'cke_button' );
			$button.addClass( 'cke_toolgroup' );

			$button.append( icon );
		} else if ( CKEDITOR.ui.richCombo && button instanceof CKEDITOR.ui.richCombo ) {
			var comboLabel = new CKEDITOR.dom.element( 'span' ),
				comboOpen = new CKEDITOR.dom.element( 'span' ),
				comboArrow = new CKEDITOR.dom.element( 'span' );

			$button.addClass( 'cke_combo_button' );

			comboLabel.addClass( 'cke_combo_text' );
			comboLabel.addClass( 'cke_combo_inlinelabel' );
			comboLabel.setText( button.label );

			comboOpen.addClass( 'cke_combo_open' );
			comboArrow.addClass( 'cke_combo_arrow' );
			comboOpen.append( comboArrow );

			$button.append( comboLabel );
			$button.append( comboOpen );
		}

		return $button;
	};

	/**
	 * Create and return icon element.
	 *
	 * @param {String} name
	 * @param {String} icon
	 * @param {String} command
	 * @static
	 * @returns {CKEDITOR.dom.element}
	 */
	FullToolbarEditor.createIcon = function( name, icon, command ) {
		var iconStyle = CKEDITOR.skin.getIconStyle( name, ( CKEDITOR.lang.dir == 'rtl' ) );

		// We don't know exactly how to get icon style. Especially for extra plugins,
		// Which definition may vary.
		iconStyle = iconStyle || CKEDITOR.skin.getIconStyle( icon, ( CKEDITOR.lang.dir == 'rtl' ) );
		iconStyle = iconStyle || CKEDITOR.skin.getIconStyle( command, ( CKEDITOR.lang.dir == 'rtl' ) );

		var iconElement = new CKEDITOR.dom.element( 'span' );

		iconElement.addClass( 'cke_button_icon' );
		iconElement.addClass( 'cke_button__' + name + '_icon' );
		iconElement.setAttribute( 'style', iconStyle );
		iconElement.setStyle( 'float', 'none' );

		return iconElement;
	};

	/**
	 * Create and return button element
	 *
	 * @param {String} text
	 * @param {String} cssClasses
	 * @returns {CKEDITOR.dom.element}
	 */
	FullToolbarEditor.createButton = function( text, cssClasses ) {
		var $button = new CKEDITOR.dom.element( 'button' );

		$button.addClass( 'button-a' );

		$button.setAttribute( 'type', 'button' );

		if ( typeof cssClasses == 'string' ) {
			cssClasses = cssClasses.split( ' ' );

			var i = cssClasses.length;
			while ( i-- ) {
				$button.addClass( cssClasses[ i ] );
			}
		}

		$button.setHtml( text );

		return $button;
	};

	/**
	 * @static
	 * @param {Object} group
	 * @returns {Array} representing HTML buttons for view
	 */
	FullToolbarEditor.groupToButtons = function( group ) {
		var buttons = [],
			items = group.items;

		var max = items ? items.length : 0;
		for ( var i = 0; i < max; i += 1 ) {
			var item = items[ i ];

			if ( item instanceof CKEDITOR.ui.button || CKEDITOR.ui.richCombo && item instanceof CKEDITOR.ui.richCombo ) {
				item.$ = FullToolbarEditor.createToolbarButton( item );
				buttons.push( item );
			}
		}

		return buttons;
	};

} )();
