text: 'use strict';
  //var crypto = require('crypto');
  var path = require('path');
  var gutil = require('gulp-util');
  var through = require('through2');
  var objectAssign = require('object-assign');
  var file = require('vinyl-file');
  var revHash = require('rev-hash');
  var revPath = require('rev-path');
  
  function relPath(base, filePath) {
  	if (filePath.indexOf(base) !== 0) {
  		return filePath.replace(/\\/g, '/');
  	}
  
  	var newPath = filePath.substr(base.length).replace(/\\/g, '/');
  
  	if (newPath[0] === '/') {
  		return newPath.substr(1);
  	}
  
  	return newPath;
  }
  
  function getManifestFile(opts, cb) {
  	file.read(opts.path, opts, function (err, manifest) {
  		if (err) {
  			// not found
  			if (err.code === 'ENOENT') {
  				cb(null, new gutil.File(opts));
  			} else {
  				cb(err);
  			}
  
  			return;
  		}
  
  		cb(null, manifest);
  	});
  }
  
  function transformFilename(file) {
  	// save the old path for later
  	file.revOrigPath = file.path;
  	file.revOrigBase = file.base;
  	file.revHash = revHash(file.contents);
  	file.path = revPath(file.path, file.revHash);
  }
  
  var plugin = function () {
  	var sourcemaps = [];
  	var pathMap = {};
  
  	return through.obj(function (file, enc, cb) {
  		if (file.isNull()) {
  			cb(null, file);
  			return;
  		}
  
  		if (file.isStream()) {
  			cb(new gutil.PluginError('gulp-rev', 'Streaming not supported'));
  			return;
  		}
  
  		// This is a sourcemap, hold until the end
  		if (path.extname(file.path) === '.map') {
  			sourcemaps.push(file);
  			cb();
  			return;
  		}
  
  		var oldPath = file.path;
  		transformFilename(file);
  		pathMap[oldPath] = file.revHash;
  		cb(null, file);
  
  	}, function(cb) {
  		sourcemaps.forEach(function (file) {
  			var reverseFilename;
  
  			// attempt to parse the sourcemap's JSON to get the reverse filename
  			try {
  				reverseFilename = JSON.parse(file.contents.toString()).file;
  			} catch (err) {}
  
  			if (!reverseFilename) {
  				reverseFilename = path.relative(path.dirname(file.path), path.basename(file.path, '.map'));
  			}
  
  			if (pathMap[reverseFilename]) {
  				// save the old path for later
  				file.revOrigPath = file.path;
  				file.revOrigBase = file.base;
  
  				var hash = pathMap[reverseFilename];
  				file.path = revPath(file.path.replace(/\.map$/, ''), hash) + '.map';
  			} else {
  				transformFilename(file);
  			}
  
  			this.push(file);
  		}, this);
  
  		cb();
  	});
  };
  
  plugin.manifest = function (pth, opts) {
  	if (typeof pth === 'string') {
  		pth = {path: pth};
  	}
  
  	opts = objectAssign({
  		path: 'rev-manifest.json',
  		merge: false
  	}, opts, pth);
  
  	var firstFile = null;
  	var manifest  = {};
  
  	return through.obj(function (file, enc, cb) {
  		// ignore all non-rev'd files
  		if (!file.path || !file.revOrigPath) {
  			cb();
  			return;
  		}
  
  		firstFile = firstFile || file;
  		manifest[relPath(firstFile.revOrigBase, file.revOrigPath)] = relPath(firstFile.revOrigBase, file.path);
  
  		cb();
  	}, function (cb) {
  		// no need to write a manifest file if there's nothing to manifest
  		if (Object.keys(manifest).length === 0) {
  			cb();
  			return;
  		}
  
  		getManifestFile(opts, function (err, manifestFile) {
  			if (err) {
  				cb(err);
  				return;
  			}
  
  			if (opts.merge && !manifestFile.isNull()) {
  				var oldManifest = {};
  
  				try {
  					oldManifest = JSON.parse(manifestFile.contents.toString());
  				} catch (err) {}
  
  				manifest = objectAssign(oldManifest, manifest);
  			}
  
  			manifestFile.contents = new Buffer(JSON.stringify(manifest, null, '  '));
  			this.push(manifestFile);
  			cb();
  		}.bind(this));
  	});
  };
  
  module.exports = plugin;
  