// -*- indent-tabs-mode: t; -*-

'use strict';
var async        = require('async');
var asyncReplace = require('async-replace');
var gutil        = require('gulp-util');
var through      = require('through2');
var cheerio      = require('cheerio');
var replace      = require('gulp-replace');
var fs           = require('fs');
var path         = require('path');
var url          = require('url');

function isLocal(link) {
	return link && ! url.parse(link).hostname;
}

module.exports = function(options) {

	var cssTags = options && options.cssTags ? options.cssTags : {begin: '<style>', end: '</style>'};
	var jsTags = options && options.jsTags ? options.jsTags : {begin: '<script>', end: '</script>'};
	var base = options && options.base;

	// create a stream through which each file will pass
	return through.obj(function(file, enc, callback) {

		if (file.isNull()) {
			this.push(file); // do nothing if no contents
			return callback();
		}

		if (file.isStream()) {
			this.emit('error', new gutil.PluginError('gulp-smoosher', 'Streaming not supported'));
			return callback();
		}

		if (file.isBuffer()) {

			var rePattern = /<!--(| )smoosh(| )-->([\s\S]*?)<!--(| )endsmoosh(| )-->/g;

			var input = String(file.contents);

			var readFileBase = base !== undefined ? base : file.base;

			asyncReplace(input, rePattern, function(match) {

				// Last argument to asyncReplace is always the callback.
				var callback = Array.prototype.slice.call(arguments).pop();

				var $ = cheerio.load(match);

				// Reduce replaceable elements to an array so we can iterate over them.
				var elements = [$('link'), $('script')].map(function toArray(elements) {
					return Array.prototype.slice.call(elements);
				}).reduce(function flatten(a, b) {
					return a.concat(b);
				});

				// Asynchronously replace the contents of each element in this
				// comment block.
				async.each(elements, function iterator(element, callback) {

					var $element = $(element);
					var url, tags;
					if ($element.is('link')) {
						url = $element.attr('href');
						tags = cssTags;
					} else if ($element.is('script')) {
						url = $element.attr('src');
						tags = jsTags;
					}
					if (isLocal(url)) {
						fs.readFile(path.join(readFileBase, url), function onRead(error, data) {
							if (error) {
								return callback(error);
							}
							$(element).replaceWith(tags.begin + data + tags.end);
							callback(null);
						});
					} else {
						callback(null);
					}

				}, function done(error) {

					if (error) {
						return callback(error);
					}
					// "Return" the replacement for asyncReplace.
					callback(null, $.html());
				});

			}, function done(error, output) {

				if (error) {
					return callback(error);
				}

				output = output.replace(/([ ]*)<!--(| )smoosh(| )-->([ ]*)(\n?)|([ ]*)<!--(| )endsmoosh(| )-->([ ]*)(\n?)/g, '');

				file.contents = new Buffer(output);

				callback(null, file);
			});
		}

	});
};

@@ -392,16 +392,671 @@
 url');%0A%0A
+// Reusable regular expression snippets.%0Avar anythingLazy = '(%5B%5C%5Cs%5C%5CS%5D*?)';%0Avar spaces = '( *)';%0Avar optionalNewline = '(%5Cn?)';%0Avar startSmoosh = %5B'%3C!--', anythingLazy, 'smoosh', anythingLazy, '--%3E'%5D.join('');%0Avar endSmoosh = %5B'%3C!--', anythingLazy, 'endsmoosh', anythingLazy, '--%3E'%5D.join('');%0A%0A// Used to replace anything within startSmoosh and endSmoosh.%0Avar replaceRegExp = new RegExp(%5BstartSmoosh, anythingLazy, endSmoosh%5D.join(''), 'g');%0A%0A// Used to remove startSmooshs and endSmooshs.%0Avar removeRegExp = new RegExp(%5B%0A%09%5Bspaces, startSmoosh, spaces, optionalNewline%5D.join(''),%0A%09%5Bspaces, endSmoosh, spaces, optionalNewline%5D.join('')%0A%5D.join('%7C'), 'g');%0A%0A
 function
@@ -1770,88 +1770,8 @@
  %7B%0A%0A
-%09%09%09var rePattern = /%3C!--(%7C )smoosh(%7C )--%3E(%5B%5Cs%5CS%5D*?)%3C!--(%7C )endsmoosh(%7C )--%3E/g;%0A%0A
 %09%09%09v
@@ -1896,15 +1896,19 @@
 , re
-Pattern
+placeRegExp
 , fu
@@ -3361,91 +3361,20 @@
 ace(
-/(%5B %5D*)%3C!--(%7C )smoosh(%7C )--%3E(%5B %5D*)(%5Cn?)%7C(%5B %5D*)%3C!--(%7C )endsmoosh(%7C )--%3E(%5B %5D*)(%5Cn?)/g
+removeRegExp
 , ''

Refactor regular expressions.