asynctest('browser/core/ActionsTest', [
	'ephox.mcagar.api.TinyLoader',
	'ephox.mcagar.api.TinyApis',
	'tinymce/inlite/core/Actions',
	'ephox.agar.api.Pipeline',
	'ephox.agar.api.Step',
	'ephox.agar.api.GeneralSteps'
], function (TinyLoader, TinyApis, Actions, Pipeline, Step, GeneralSteps) {
	var success = arguments[arguments.length - 2];
	var failure = arguments[arguments.length - 1];

	var wrap = function (f, args) {
		return function () {
			var currentArgs = Array.prototype.slice.call(arguments);
			return Step.sync(function () {
				f.apply(null, [].concat(args).concat(currentArgs));
			});
		};
	};

	var sInsertTableTests = function (editor, tinyApis) {
		var sInsertTableTest = function (cols, rows, expectedHtml, message) {
			var sInsertTable = wrap(Actions.insertTable, editor);

			return GeneralSteps.sequence([
				tinyApis.sSetContent(''),
				sInsertTable(cols, rows),
				tinyApis.sAssertContent(expectedHtml, message)
			]);
		};

		return GeneralSteps.sequence([
			sInsertTableTest(2, 3, [
					'<table style="width: 100%;">',
						'<tbody>',
							'<tr>',
								'<td>&nbsp;</td>',
								'<td>&nbsp;</td>',
							'</tr>',
						'<tr>',
							'<td>&nbsp;</td>',
							'<td>&nbsp;</td>',
						'</tr>',
							'<tr>',
								'<td>&nbsp;</td>',
								'<td>&nbsp;</td>',
							'</tr>',
						'</tbody>',
					'</table>'
				].join('\n'),
				'Should be a 2x3 table'
			),

			sInsertTableTest(3, 2, [
					'<table style="width: 100%;">',
						'<tbody>',
							'<tr>',
								'<td>&nbsp;</td>',
								'<td>&nbsp;</td>',
								'<td>&nbsp;</td>',
							'</tr>',
							'<tr>',
								'<td>&nbsp;</td>',
								'<td>&nbsp;</td>',
								'<td>&nbsp;</td>',
							'</tr>',
						'</tbody>',
					'</table>'
				].join('\n'),
				'Should be a 3x2 table'
			)
		]);
	};

	var sFormatBlockTests = function (editor, tinyApis) {
		var sFormatBlockTest = function (name) {
			var sFormatBlock = wrap(Actions.formatBlock, editor);

			return GeneralSteps.sequence([
				tinyApis.sSetContent('<p>a</p>'),
				tinyApis.sSetCursor([0], 0),
				sFormatBlock(name),
				tinyApis.sAssertContent('<' + name + '>a</' + name + '>', 'Should be a ' + name + ' block')
			]);
		};

		return GeneralSteps.sequence([
			sFormatBlockTest('h1'),
			sFormatBlockTest('h2'),
			sFormatBlockTest('pre')
		]);
	};

	var sCreateLinkTests = function (editor, tinyApis) {
		var sCreateLinkTest = function (inputHtml, url, sPath, sOffset, fPath, fOffset, expectedHtml) {
			var sCreateLink = wrap(Actions.createLink, editor);

			return GeneralSteps.sequence([
				tinyApis.sSetContent(inputHtml),
				tinyApis.sSetSelection(sPath, sOffset, fPath, fOffset),
				sCreateLink(url),
				tinyApis.sAssertContent(expectedHtml, 'Should have a link')
			]);
		};

		return GeneralSteps.sequence([
			sCreateLinkTest('<p>a</p>', '#1', [0, 0], 0, [0, 0], 1, '<p><a href="#1">a</a></p>'),
			sCreateLinkTest('<p><a href="#1">a</a></p>', '#2', [0, 0], 0, [0, 0], 1, '<p><a href="#2">a</a></p>'),
			sCreateLinkTest('<p><a href="#1"><em>a</em></a></p>', '#2',	[0, 0, 0], 0, [0, 0, 0], 1,	'<p><a href="#2"><em>a</em></a></p>')
		]);
	};

	var sUnlinkTests = function (editor, tinyApis) {
		var sUnlinkTest = function (inputHtml, sPath, sOffset, fPath, fOffset, expectedHtml) {
			var sUnlink = wrap(Actions.unlink, editor);

			return GeneralSteps.sequence([
				tinyApis.sSetContent(inputHtml),
				tinyApis.sSetSelection(sPath, sOffset, fPath, fOffset),
				sUnlink(),
				tinyApis.sAssertContent(expectedHtml, 'Should not have a link')
			]);
		};

		return GeneralSteps.sequence([
			sUnlinkTest('<p>a</p>', [0, 0], 0, [0, 0], 1, '<p>a</p>'),
			sUnlinkTest('<p><a href="#">a</a></p>', [0, 0, 0], 0, [0, 0, 0], 1, '<p>a</p>'),
			sUnlinkTest('<p><a href="#"><em>a</em></a></p>', [0, 0, 0], 0, [0, 0, 0], 1, '<p><em>a</em></p>'),
			sUnlinkTest('<p><a href="#">a</a>b</p>', [0, 0, 0], 0, [0, 1], 1, '<p>ab</p>')
		]);
	};

	var base64ToBlob = function (base64, type) {
		var buff = atob(base64);
		var bytes = new Uint8Array(buff.length);

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

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

	var sInsertBlobTests = function (editor, tinyApis) {
		var sInsertBlobTest = function (inputHtml, path, offset, blob, base64, expectedHtml) {
			var sInsertBlob = wrap(Actions.insertBlob, editor);

			return GeneralSteps.sequence([
				tinyApis.sSetContent(inputHtml),
				tinyApis.sSetCursor(path, offset),
				sInsertBlob(blob, base64),
				tinyApis.sAssertContent(expectedHtml, 'Should have a image')
			]);
		};

		var base64 = 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
		var blob = base64ToBlob(base64, 'image/gif');

		return GeneralSteps.sequence([
			sInsertBlobTest('<p>a</p>', [0, 0], 0, base64, blob, '<p><img src="data:image/gif;base64,' + base64 + '" />a</p>')
		]);
	};

	TinyLoader.setup(function (editor, onSuccess, onFailure) {
		var tinyApis = TinyApis(editor);

		Pipeline.async({}, [
			sInsertTableTests(editor, tinyApis),
			sFormatBlockTests(editor, tinyApis),
			sInsertBlobTests(editor, tinyApis),
			sCreateLinkTests(editor, tinyApis),
			sUnlinkTests(editor, tinyApis)
		], onSuccess, onFailure);
	}, {
		inline: true
	}, success, failure);
});
