/* exported blobHelpers */

( function() {
	'use strict';

	// jscs:disable maximumLineLength
	var SAMPLE_PNG = 'data:image/png;base64,[encoded data, 5596 characters]',
	// jscs:enable maximumLineLength
		isSupportedEnvironment = typeof Uint8Array === 'function' && typeof Blob === 'function' &&
			typeof URL === 'function' && typeof ArrayBuffer === 'function';

	function ignoreUnsupportedEnvironment( testSuite, check ) {
		testSuite._should = testSuite._should || {};
		testSuite._should.ignore = testSuite._should.ignore || {};

		for ( var key in testSuite ) {
			if ( ( typeof check !== 'undefined' && !check ) || !this.isSupportedEnvironment ) {
				testSuite._should.ignore[ key ] = true;
			}
		}
	}

	function dataUriToBlob( dataURI ) {
		var base64String = atob( dataURI.split( ',' )[1] ),
			fileType = dataURI.match( /^data:([^;]*);base64,/ )[ 1 ],
			arrayBuffer = new Uint8Array( base64String.length );

		for ( var i = 0; i < base64String.length; i++ ) {
			arrayBuffer[ i ] = base64String.charCodeAt( i );
		}

		return new Blob( [ arrayBuffer ], { type: fileType } );
	}

	function simulatePasteBlob( editor, assertion, userOptions ) {
		var defaultOptions = {
				imageDataUrl: SAMPLE_PNG,
				imageType: null,
				template: '<p{%CLASS%}>Hello<img style="height:200px; width:200px" src="{%URL%}" />world.</p>'
			},
			// Our tools break ArrayBuffers, so we need to handle this option separately.
			image = userOptions && userOptions.image || SAMPLE_PNG,
			options = CKEDITOR.tools.object.merge( defaultOptions, userOptions || {} ),
			imageDataUrl = options.imageDataUrl,
			url = getObjectUrl( image, options.imageType ),
			template = options.template,
			input = template.replace( /{%URL%}/g, url ).replace( /{%CLASS%}/g, ' class="MsoNormal"' ),
			expected = template.replace( /{%URL%}/g, imageDataUrl ).replace( /{%CLASS%}/g, '' );

		editor.once( 'pasteFromWord', function( evt ) {
			// `saveSnapshot` is last event after content is paste from word.
			evt.editor.once( 'saveSnapshot', function() {
				resume( function() {
					// Additional wait is required to update undo manager state.
					setTimeout( function() {
						resume( function() {
							assertion( input, expected );
						} );
					}, 100 );

					wait();
				} );
			}, null, null, 999 );
		} );

		editor.fire( 'paste', {
			type: 'auto',
			// This data will be recognized as pasted from Word.
			dataValue: input,
			method: 'paste'
		} );

		wait();
	}

	function getObjectUrl( image, type ) {
		if ( typeof image === 'string' ) {
			return URL.createObjectURL( dataUriToBlob( image ) );
		}

		var uInt8Array = new Uint8Array( image ),
			blob = new Blob( [ uInt8Array ], { type: type } );

		return URL.createObjectURL( blob );
	}

	window.blobHelpers = {
		/*
		 * Modifies testSuite by adding entries in `_should.ignore` object for each method/property, if
		 * the current environment is not supported.
		 *
		 * @param {Object} testSuite
		 * @param {Boolean} [check] Custom check to be considered in addition to the default one.
		 */
		ignoreUnsupportedEnvironment: ignoreUnsupportedEnvironment,

		/*
		 * @property {Boolean} isSupportedEnvironment Whether Blob URLs are supported in current environment.
		 */
		isSupportedEnvironment: isSupportedEnvironment,

		/*
		 * Converts Data URI into proper Blob.
		 *
		 * @param {String} dataUri Data URI to be converted.
		 * @returns {Blob} Blob representing resource described by passed data URI.
		 */
		dataUriToBlob: dataUriToBlob,

		/*
		 * Simulate pasting image as Blob URL.
		 *
		 * @param {CKEDITOR.editor} editor Editor, in which paste occurs.
		 * @param {Function} assertion Test assertion
		 * @param {String} assertion.input HTML, which was pasted.
		 * @param {String} assertion.expected Expected HTML output.
		 */
		simulatePasteBlob: simulatePasteBlob
	};
}() );
