/* jshint node:true */

var dtsGenerator = require('dts-generator');

module.exports = function (grunt) {
	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-contrib-watch');
	grunt.loadNpmTasks('grunt-peg');
	grunt.loadNpmTasks('grunt-rename');
	grunt.loadNpmTasks('grunt-ts');
	grunt.loadNpmTasks('intern-geezer');

	grunt.initConfig({
		// TODO: Always build, or never build, tests
		all: [ 'src/**/*.ts', 'typings/tsd.d.ts' ],
		ignoreDefinitions: [ '<%= all %>', '!**/*.d.ts', 'typings/tsd.d.ts' ],
		tests: [ 'tests/**/*.ts', 'typings/tsd.d.ts' ],

		clean: {
			framework: {
				src: [
					'**/{*.js,*.js.map}', '!node_modules/**/*', '!third-party/**/*'
				],
				filter: function (filepath) {
					var jsName = filepath.match(/(.*\.js)(?:\.map)?$/)[1];

					// Only clean .js and .js.map files if BOTH the JavaScript and the map file exist.
					// Since the only thing generating map files is grunt-ts, this targets only the
					// JavaScript files generated by that process (including JavaScript files
					// generated for TypeScript files that have been moved or deleted).
					return grunt.file.exists(jsName) && grunt.file.exists(jsName + '.map');
				}
			},
			parser: {
				src: [
					'templating/html/peg/html.js*'
				]
			}
		},

		peg: {
			parser: {
				src: 'src/templating/html/peg/html.pegjs',
				dest: 'dist/templating/html/peg/html.js',
				options: {
					allowedStartRules: [ 'Template', 'BoundText' ],
					wrapper: function (src, parser) {
						return 'define([\'require\', \'module\'], function (require, module) {\n' +
							'return ' + parser + ';\n' +
						'});';
					}
				}
			}
		},

		ts: {
			options: {
				// TODO: Remove `failOnTypeErrors` with TS1.5; see TS#1133
				failOnTypeErrors: false,
				target: 'es5',
				module: 'amd',
				sourceMap: true,
				noImplicitAny: true,
				fast: 'never'
			},
			framework: {
				src: [ '<%= ignoreDefinitions %>' ],
				outDir: 'dist',
				options: {
					mapRoot: '../dist/_debug'
				}
			},
			tests: {
				src: [ '<%= tests %>' ]
			}
		},

		copy: {
			framework: {
				expand: true,
				cwd: 'src/',
				src: [ '**/*.html' ],
				dest: 'dist/'
			},
			sourceForDebugging: {
				expand: true,
				cwd: 'src/',
				src: [ '**/*.ts' ],
				dest: 'dist/_debug/'
			},
			typings: {
				expand: true,
				cwd: 'typings/',
				src: [ '**/*.d.ts', '!tsd.d.ts' ],
				dest: 'dist/_typings/'
			},
			staticFiles: {
				expand: true,
				cwd: '.',
				src: [ 'README.md', 'LICENSE', 'package.json', 'bower.json' ],
				dest: 'dist/'
			}
		},

		rename: {
			sourceMaps: {
				expand: true,
				cwd: 'dist/',
				src: [ '**/*.js.map' ],
				dest: 'dist/_debug/'
			}
		},

		rewriteSourceMapSources: {
			framework: {
				options: {
					find: /^(?:\.\.\/)*src\//,
					replace: ''
				},
				src: [ 'dist/**/*.js.map' ]
			}
		},

		watch: {
			ts: {
				files: [ '<%= all %>' ],
				tasks: [ 'ts:framework', 'dts' ]
			},
			parser: {
				files: [ '<%= peg.parser.src %>' ],
				tasks: [ 'peg:parser' ]
			}
		},

		intern: {
			runner: {
				options: {
					runType: 'runner',
					config: 'tests/mayhem.intern'
				}
			},
			client: {
				options: {
					config: 'tests/mayhem.intern'
				}
			}
		}
	});

	grunt.registerTask('dts', function () {
		var done = this.async();

		dtsGenerator.generate({
			name: 'mayhem',
			baseDir: 'src',
			externs: [
				'../dgrid/dgrid.d.ts',
				'../dojo/dojo.d.ts',
				'../dojo/dijit.d.ts',
				'../dstore/dstore.d.ts',
				'../esprima/esprima.d.ts',
				'../intl-messageformat/intl-messageformat.d.ts',
				'../xstyle/xstyle.d.ts'
			],
			out: 'dist/_typings/mayhem/mayhem.d.ts'
		}, grunt.verbose.writeln.bind(grunt.verbose)).then(done, done);
	});

	grunt.registerMultiTask('rewriteSourceMapSources', function () {
		var find = this.options().find;
		var replace = this.options().replace;

		grunt.log.writeln('Replacing ' + find + ' with ' + replace + ' in ' + this.filesSrc.length + ' files');

		this.filesSrc.forEach(function (file) {
			var map = JSON.parse(grunt.file.read(file));
			map.sources = map.sources.map(function (source) {
				return source.replace(find, replace);
			});
			grunt.file.write(file, JSON.stringify(map));
		});
	});

	grunt.registerTask('test', [ 'ts:tests', 'intern:client' ]);
	grunt.registerTask('build', [
		'peg:parser',
		'ts:framework',
		'copy:typings',
		'dts',
		'copy:framework',
		'copy:sourceForDebugging',
		'copy:staticFiles',
		'rewriteSourceMapSources',
		'rename:sourceMaps'
	]);
	grunt.registerTask('ci', [ 'build', 'test' ]);
	grunt.registerTask('default', [ 'build', 'watch' ]);
};

@@ -2798,24 +2798,21 @@
 : /%5E
-(?:%5C.%5C.%5C/)*src%5C/
+.*%5C/(%5B%5E%5C/%5D+)$
 /,%0A%09
@@ -2825,16 +2825,18 @@
 place: '
+$1
 '%0A%09%09%09%09%7D,

Fix incorrect paths to source files in source maps