var _demo = "\n" +
"\nwindow.demo = function(message, callback) {" +
"\n  if (typeof callback !== 'function')" +
"\n    throw new Error('bad callback: ' + callback);" +
"\n  info(message + ' (waiting 1s)');" +
"\n  setTimeout(function() {" +
"\n    info(message + ' (done!)');" +
"\n    callback(null, message.length);" +
"\n  }, 1000);" +
"\n}" +
"\n";

var _samples = {
	introSample: "" +
	"// Demonstrates how 'streamline.js' transforms synchronous-looking code" +
	"\n// into asynchronous code with callbacks." +
	"\n//" +
	"\n// Try one of the samples above, or write your own code below." +
	"\n// Syntax is simple: just use '_' anywhere a callback is expected" +
	"\n//" +
	"\n// The samples compute factorial(4) by different methods." +
	"\n//" +
	"\n// Look at the transformed code and run it with the 'execute' button." +
	"\n//" +
	"\n// The transformation generates some one-liner auxiliary functions." +
	"\n// Select the 'show complete code' option to see the whole code." +
	"\n//" +
	"\n// The 'beautify' button can help you tidy your code." +
	_demo +
	"\ndemo('Straight to the answer: fact(4) = 24', _);" +
	"\n" +
	"\n// A few pointers to understand the generated code:" +
	"\n//" +
	"\n// * the '_' parameter is the callback. This is where execution will" +
	"\n//   continue on a return or throw statement." +
	"\n// * the '__then' variable is a 'then' callback. This is where execution will" +
	"\n//   resume at the end of the construct if it didn't encounter a return " +
	"\n//   or throw." +
	"\n// * the '__cb' function is just a little callback wrapper that deals with " +
	"\n//   error handling and other small matters in a generic way." +
	"\n// * the '__trap' function handles errors if the callback is missing." +
	"\n",

	sequenceSample: "" +
	"// Multiply one step at a time:" +
	"\n" +
	"\nvar fact = demo('1', _);" +
	"\nfact *= demo('12', _);" +
	"\nfact *= demo('123', _);" +
	"\nfact *= demo('1234', _);" +
	"\ndemo('fact(4) = ' + fact, _);" +
	"\n",

	expressionsSample: "" +
	"// Multiply all at once:" +
	"\n" +
	"\nvar fact = demo('1', _) * demo('12', _) * demo('123', _) * demo('1234', _);" +
	"\ndemo('fact(4) = ' + fact, _)" +
	"\n",

	functionsSample: "" +
	"// Go through intermediate functions: " +
	"\n" +
	"\nfunction f(n1, n2, _) {" +
	"\n  return demo(n1, _) * demo(n2, _);" +
	"\n}" +
	"\n" +
	"\nfunction g(_) {" +
	"\n  return f('1', '12', _) * f('123', '1234', _);" +
	"\n}" +
	"\n" +
	"\ndemo('fact(4) = ' + g(_), _);" +
	"\n",

	ifElseSample: "" +
	"// Natural recursive version with if/else test." +
	"\n" +
	"\nfunction fact(n, _) {" +
	"\n  if (n == 1) { demo('return: 1', _); return 1; }" +
	"\n  else { demo('recurse: ' + n, _); return n * fact(n - 1, _); }" +
	"\n}" +
	"\n" +
	"\ndemo('fact(4) = ' + fact(4, _), _);" +
	"\n",

	loopSample: "" +
	"// Natural iterative version" +
	"\n" +
	"\nfunction fact(n, _) {" +
	"\n  var result = 1;" +
	"\n  for (var str = '-'; str.length <= n; str += '-') {" +
	"\n    result *= demo(str, _);" +
	"\n  }" +
	"\n  return result;" +
	"\n}" +
	"\n" +
	"\ndemo('fact(4) = ' + fact(4, _), _);" +
	"\n",

	tryCatchSample: "" +
	"// Recursive variant with throw/catch." +
	"\n" +
	"\nfunction fact(n, _) {" +
	"\n  try {" +
	"\n    demo('try: n = ' + n, _);" +
	"\n    if (n == 0) throw new Error('zero');" +
	"\n    return n * fact(n - 1, _);" +
	"\n  }" +
	"\n  catch (ex) { demo('caught ' + ex.message, _); return 1; }" +
	"\n  finally { demo('finally: n = ' + n, _); }" +
	"\n}" +
	"\n" +
	"\ndemo('fact(4) = ' + fact(4, _), _);" +
	"\n",

	lazySample: "" +
	"// Variant with lazy eval operators." +
	"\n// Note that fact(3, _) is evaluated but fact(5, _) is not" +
	"\n" +
	"\nfunction fact(n, _) {" +
	"\n  demo('n=' + n, _);" +
	"\n  return n == 1 ? demo('!', _) : n * fact(n - 1, _);" +
	"\n}" +
	"\n" +
	"\nvar fact4 = (fact(3, _) - 6) || fact(4, _) || fact(5, _);" +
	"\n" +
	"\ndemo('fact(4) = ' + fact4, _);" +
	"\n",

	futuresSample: "" +
	"// Variant with futures." +
	"\n// Much faster because all futures wait together" +
	"\n" +
	"\n// Intermediate function to return future when called" +
	"\n// without _ (demo does not return future)" +
	"\nfunction demo2(str, _) { return demo(str, _); }" +
	"\n" +
	"\nvar v1 = demo2('1');" +
	"\nvar v2 = demo2('12');" +
	"\nvar v3 = demo2('123');" +
	"\nvar v4 = demo2('1234');" +
	"\n" +
	"\ndemo2('fact(4) = ' +v1(_) * v2(_) * v3(_) * v4(_));" +
	"\n",
}

var _complete = false;

function error(message) {
	$('#result').removeClass('info').addClass('error').text(message);
}

function info(message) {
	$('#result').removeClass('error').addClass('success').text(message);
}

Streamline.globals.context = {
	errorHandler: function(err){
		error(err.message || err.toString());
	}
}

eval(_demo); // define demo if user does not execute intro

function _transform() {
	var codeIn = $('#codeIn').val();
	try {
		var codeOut = Streamline.transform(codeIn, {
			noHelpers: !_complete,
			lines: _complete ? "preserve" : "ignore"
		});
		$('#codeOut').val(codeOut);
		info("ready")
	} catch (ex) {
		console.error(ex);
		error(ex.message)
	}
}

function _execute() {
	var codeIn = $('#codeIn').val();
	try {
		var codeOut = Streamline.transform(codeIn, {
			lines: "preserve"
		});
		eval(codeOut);
	} catch (ex) {
		error(ex.message);
	}
}

function _beautify(str) {
	try {
		var str = Narcissus.decompiler.pp(Narcissus.parser.parse(str));
		str = str.replace(/}\s*;/g, "}")
		$('#codeIn').val(str);
		return true;
	} catch (ex) {
		error(ex.message);
		return false;
	}
}

$( function() {
	$('#codeIn').keyup(_transform);
	$('.sample').click( function() {
		$('#codeIn').val(_samples[this.id]);
		_transform();
	});
	$('#beautify').click( function() {
		_beautify($('#codeIn').val());
	})
	$('#complete').change( function() {
		_complete = !_complete;
		_transform();
	})
	$('#execute').click( function() {
		_execute();
	})
	$('#codeIn').val(_samples["introSample"]);
	_transform();
})
