#!/usr/bin/env node
/*
 * jQuery Release Management
 */

var fs = require("fs"),
	child = require("child_process"),
	debug = false;

var scpURL = "jqadmin@code.origin.jquery.com:/var/www/html/code.jquery.com/",
	cdnURL = "http://code.origin.jquery.com/",

	version = /^[\d.]+(?:(?:a|b|rc)\d+|pre)?$/,
	versionFile = "version.txt",
	
	file = "dist/jquery.js",
	minFile = "dist/jquery.min.js",
	
	files = {
		"jquery-VER.js": file,
		"jquery-VER.min.js": minFile
	},
	
	finalFiles = {
		"jquery.js": file,
		"jquery-latest.js": file,
		"jquery.min.js": minFile,
		"jquery-latest.min.js": minFile
	};

exec( "git pull && git status", function( error, stdout, stderr ) {
	if ( /Changes to be committed/i.test( stdout ) ) {
		exit( "Please commit changed files before attemping to push a release." );

	} else if ( /Changes not staged for commit/i.test( stdout ) ) {
		exit( "Please stash files before attempting to push a release." );

	} else {
		setVersion();
	}
});

function setVersion() {
	var oldVersion = fs.readFileSync( versionFile, "utf8" );
	
	prompt( "New Version (was " + oldVersion + "): ", function( data ) {
		if ( data && version.test( data ) ) {
			fs.writeFileSync( versionFile, data );
			
			exec( "git commit -a -m 'Tagging the " + data + " release.' && git push && " +
				"git tag " + data + " && git push origin " + data, function() {
					make( data );
			});
			
		} else {
			console.error( "Malformed version number, please try again." );
			setVersion();
		}
	});
}

function make( newVersion ) {
	exec( "make clean && make", function( error, stdout, stderr ) {
		// TODO: Verify JSLint
		
		Object.keys( files ).forEach(function( oldName ) {
			var value = files[ oldName ], name = oldName.replace( /VER/g, newVersion );

			copy( value, name );

			delete files[ oldName ];
			files[ name ] = value;
		});

		exec( "scp " + Object.keys( files ).join( " " ) + " " + scpURL, function() {
			setNextVersion( newVersion );
		});
	});
}

function setNextVersion( newVersion ) {
	var isFinal = false;
	
	if ( /(?:a|b|rc)\d+$/.test( newVersion ) ) {
		newVersion = newVersion.replace( /(?:a|b|rc)\d+$/, "pre" );
		
	} else if ( /^\d+\.\d+\.?(\d*)$/.test( newVersion ) ) {
		newVersion = newVersion.replace( /^(\d+\.\d+\.?)(\d*)$/, function( all, pre, num ) {
			return pre + (pre.charAt( pre.length - 1 ) !== "." ? "." : "") + (num ? parseFloat( num ) + 1 : 1) + "pre";
		});
		
		isFinal = true;
	}
	
	prompt( "Next Version [" + newVersion + "]: ", function( data ) {
		if ( !data ) {
			data = newVersion;
		}
		
		if ( version.test( data ) ) {
			fs.writeFileSync( versionFile, data );
			
			exec( "git commit -a -m 'Updating the source version to " + data + "' && git push", function() {
				if ( isFinal ) {
					makeFinal( newVersion );
				}
			});
			
		} else {
			console.error( "Malformed version number, please try again." );
			setNextVersion( newVersion );
		}
	});
}

function makeFinal( newVersion ) {
	var all = Object.keys( finalFiles );
	
	// Copy all the files
	all.forEach(function( name ) {
		copy( finalFiles[ name ], name );
	});
	
	// Upload files to CDN
	exec( "scp " + all.join( " " ) + " " + scpURL, function() {
		exec( "curl '" + cdnURL + "{" + all.join( "," ) + "}?reload'", function() {
			console.log( "Done." );
		});
	});
}

function copy( oldFile, newFile ) {
	if ( debug ) {
		console.log( "Copying " + oldFile + " to " + newFile );

	} else {
		fs.writeFileSync( newFile, fs.readFileSync( oldFile, "utf8" ) );
	}
}

function prompt( msg, callback ) {
	process.stdout.write( msg );
	
	process.stdin.resume();
	process.stdin.setEncoding( "utf8" );
	
	process.stdin.once( "data", function( chunk ) {
		process.stdin.pause();
		callback( chunk.replace( /\n*$/g, "" ) );
	});
}

function exec( cmd, fn ) {
	if ( debug ) {
		console.log( cmd );
		fn();

	} else {
		child.exec( cmd, fn );
	}
}

function exit( msg ) {
	if ( msg ) {
		console.error( "\nError: " + msg );
	}

	process.exit( 1 );
}